blob: d2a0c64bdc0c6f26923a21db159616ed274db840 [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},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200422 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200423 {"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},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200450 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100451# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200452 {"balloon_split", 1, 1, FEARG_1, 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},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200457 {"bufadd", 1, 1, FEARG_1, f_bufadd},
458 {"bufexists", 1, 1, FEARG_1, f_bufexists},
459 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200460 {"buffer_name", 1, 1, 0, f_bufname}, // obsolete
461 {"buffer_number", 1, 1, 0, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200462 {"buflisted", 1, 1, FEARG_1, f_buflisted},
463 {"bufload", 1, 1, FEARG_1, f_bufload},
464 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
465 {"bufname", 1, 1, FEARG_1, f_bufname},
466 {"bufnr", 1, 2, FEARG_1, f_bufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200467 {"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 Moolenaar7a4ea1d2019-08-04 21:35:12 +0200502 {"complete", 2, 2, 0, f_complete},
503 {"complete_add", 1, 1, 0, f_complete_add},
504 {"complete_check", 0, 0, 0, f_complete_check},
505 {"complete_info", 0, 1, 0, f_complete_info},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200506 {"confirm", 1, 4, 0, f_confirm},
507 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200509 {"cos", 1, 1, FEARG_1, f_cos},
510 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200511#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200512 {"count", 2, 4, FEARG_1, f_count},
513 {"cscope_connection",0,3, 0, f_cscope_connection},
514 {"cursor", 1, 3, 0, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100515#ifdef MSWIN
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200516 {"debugbreak", 1, 1, 0, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200517#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200518 {"deepcopy", 1, 2, 0, f_deepcopy},
519 {"delete", 1, 2, 0, f_delete},
520 {"deletebufline", 2, 3, 0, f_deletebufline},
521 {"did_filetype", 0, 0, 0, f_did_filetype},
522 {"diff_filler", 1, 1, 0, f_diff_filler},
523 {"diff_hlID", 2, 2, 0, f_diff_hlID},
524 {"empty", 1, 1, FEARG_1, f_empty},
525 {"environ", 0, 0, 0, f_environ},
526 {"escape", 2, 2, 0, f_escape},
527 {"eval", 1, 1, FEARG_1, f_eval},
528 {"eventhandler", 0, 0, 0, f_eventhandler},
529 {"executable", 1, 1, 0, f_executable},
530 {"execute", 1, 2, 0, f_execute},
531 {"exepath", 1, 1, 0, f_exepath},
532 {"exists", 1, 1, 0, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200534 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200535#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200536 {"expand", 1, 3, 0, f_expand},
537 {"expandcmd", 1, 1, 0, f_expandcmd},
538 {"extend", 2, 3, FEARG_1, f_extend},
539 {"feedkeys", 1, 2, 0, f_feedkeys},
540 {"file_readable", 1, 1, 0, f_filereadable}, // obsolete
541 {"filereadable", 1, 1, 0, f_filereadable},
542 {"filewritable", 1, 1, 0, f_filewritable},
543 {"filter", 2, 2, FEARG_1, f_filter},
544 {"finddir", 1, 3, 0, f_finddir},
545 {"findfile", 1, 3, 0, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200546#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200547 {"float2nr", 1, 1, FEARG_1, f_float2nr},
548 {"floor", 1, 1, FEARG_1, f_floor},
549 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200551 {"fnameescape", 1, 1, 0, f_fnameescape},
552 {"fnamemodify", 2, 2, 0, f_fnamemodify},
553 {"foldclosed", 1, 1, 0, f_foldclosed},
554 {"foldclosedend", 1, 1, 0, f_foldclosedend},
555 {"foldlevel", 1, 1, 0, f_foldlevel},
556 {"foldtext", 0, 0, 0, f_foldtext},
557 {"foldtextresult", 1, 1, 0, f_foldtextresult},
558 {"foreground", 0, 0, 0, f_foreground},
559 {"funcref", 1, 3, 0, f_funcref},
560 {"function", 1, 3, 0, f_function},
561 {"garbagecollect", 0, 1, 0, f_garbagecollect},
562 {"get", 2, 3, FEARG_1, f_get},
563 {"getbufinfo", 0, 1, 0, f_getbufinfo},
564 {"getbufline", 2, 3, 0, f_getbufline},
565 {"getbufvar", 2, 3, 0, f_getbufvar},
566 {"getchangelist", 1, 1, 0, f_getchangelist},
567 {"getchar", 0, 1, 0, f_getchar},
568 {"getcharmod", 0, 0, 0, f_getcharmod},
569 {"getcharsearch", 0, 0, 0, f_getcharsearch},
570 {"getcmdline", 0, 0, 0, f_getcmdline},
571 {"getcmdpos", 0, 0, 0, f_getcmdpos},
572 {"getcmdtype", 0, 0, 0, f_getcmdtype},
573 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200574 {"getcompletion", 2, 3, 0, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200575 {"getcurpos", 0, 0, 0, f_getcurpos},
576 {"getcwd", 0, 2, 0, f_getcwd},
577 {"getenv", 1, 1, 0, f_getenv},
578 {"getfontname", 0, 1, 0, f_getfontname},
579 {"getfperm", 1, 1, 0, f_getfperm},
580 {"getfsize", 1, 1, 0, f_getfsize},
581 {"getftime", 1, 1, 0, f_getftime},
582 {"getftype", 1, 1, 0, f_getftype},
583 {"getjumplist", 0, 2, 0, f_getjumplist},
584 {"getline", 1, 2, 0, f_getline},
585 {"getloclist", 1, 2, 0, f_getloclist},
586 {"getmatches", 0, 1, 0, f_getmatches},
587 {"getpid", 0, 0, 0, f_getpid},
588 {"getpos", 1, 1, 0, f_getpos},
589 {"getqflist", 0, 1, 0, f_getqflist},
590 {"getreg", 0, 3, 0, f_getreg},
591 {"getregtype", 0, 1, 0, f_getregtype},
592 {"gettabinfo", 0, 1, 0, f_gettabinfo},
593 {"gettabvar", 2, 3, 0, f_gettabvar},
594 {"gettabwinvar", 3, 4, 0, f_gettabwinvar},
595 {"gettagstack", 0, 1, 0, f_gettagstack},
596 {"getwininfo", 0, 1, 0, f_getwininfo},
597 {"getwinpos", 0, 1, 0, f_getwinpos},
598 {"getwinposx", 0, 0, 0, f_getwinposx},
599 {"getwinposy", 0, 0, 0, f_getwinposy},
600 {"getwinvar", 2, 3, 0, f_getwinvar},
601 {"glob", 1, 4, 0, f_glob},
602 {"glob2regpat", 1, 1, 0, f_glob2regpat},
603 {"globpath", 2, 5, 0, f_globpath},
604 {"has", 1, 1, 0, f_has},
605 {"has_key", 2, 2, FEARG_1, f_has_key},
606 {"haslocaldir", 0, 2, 0, f_haslocaldir},
607 {"hasmapto", 1, 3, 0, f_hasmapto},
608 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
609 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
610 {"histadd", 2, 2, 0, f_histadd},
611 {"histdel", 1, 2, 0, f_histdel},
612 {"histget", 1, 2, 0, f_histget},
613 {"histnr", 1, 1, 0, f_histnr},
614 {"hlID", 1, 1, 0, f_hlID},
615 {"hlexists", 1, 1, 0, f_hlexists},
616 {"hostname", 0, 0, 0, f_hostname},
617 {"iconv", 3, 3, 0, f_iconv},
618 {"indent", 1, 1, 0, f_indent},
619 {"index", 2, 4, FEARG_1, f_index},
620 {"input", 1, 3, 0, f_input},
621 {"inputdialog", 1, 3, 0, f_inputdialog},
622 {"inputlist", 1, 1, 0, f_inputlist},
623 {"inputrestore", 0, 0, 0, f_inputrestore},
624 {"inputsave", 0, 0, 0, f_inputsave},
625 {"inputsecret", 1, 2, 0, f_inputsecret},
626 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200627 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200628 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200629#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200630 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200631#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200632 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200634 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200636 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200638 {"job_getchannel", 1, 1, 0, f_job_getchannel},
639 {"job_info", 0, 1, 0, f_job_info},
640 {"job_setoptions", 2, 2, 0, f_job_setoptions},
641 {"job_start", 1, 2, 0, f_job_start},
642 {"job_status", 1, 1, 0, f_job_status},
643 {"job_stop", 1, 2, 0, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200645 {"join", 1, 2, FEARG_1, f_join},
646 {"js_decode", 1, 1, 0, f_js_decode},
647 {"js_encode", 1, 1, 0, f_js_encode},
648 {"json_decode", 1, 1, 0, f_json_decode},
649 {"json_encode", 1, 1, 0, f_json_encode},
650 {"keys", 1, 1, FEARG_1, f_keys},
651 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
652 {"len", 1, 1, FEARG_1, f_len},
653 {"libcall", 3, 3, 0, f_libcall},
654 {"libcallnr", 3, 3, 0, f_libcallnr},
655 {"line", 1, 1, 0, f_line},
656 {"line2byte", 1, 1, 0, f_line2byte},
657 {"lispindent", 1, 1, 0, f_lispindent},
658 {"list2str", 1, 2, 0, f_list2str},
659 {"listener_add", 1, 2, 0, f_listener_add},
660 {"listener_flush", 0, 1, 0, f_listener_flush},
661 {"listener_remove", 1, 1, 0, f_listener_remove},
662 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200663#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200664 {"log", 1, 1, FEARG_1, f_log},
665 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666#endif
667#ifdef FEAT_LUA
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200668 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200669#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200670 {"map", 2, 2, FEARG_1, f_map},
671 {"maparg", 1, 4, 0, f_maparg},
672 {"mapcheck", 1, 3, 0, f_mapcheck},
673 {"match", 2, 4, 0, f_match},
674 {"matchadd", 2, 5, 0, f_matchadd},
675 {"matchaddpos", 2, 5, 0, f_matchaddpos},
676 {"matcharg", 1, 1, 0, f_matcharg},
677 {"matchdelete", 1, 2, 0, f_matchdelete},
678 {"matchend", 2, 4, 0, f_matchend},
679 {"matchlist", 2, 4, 0, f_matchlist},
680 {"matchstr", 2, 4, 0, f_matchstr},
681 {"matchstrpos", 2, 4, 0, f_matchstrpos},
682 {"max", 1, 1, FEARG_1, f_max},
683 {"min", 1, 1, FEARG_1, f_min},
684 {"mkdir", 1, 3, 0, f_mkdir},
685 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200686#ifdef FEAT_MZSCHEME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200687 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200689 {"nextnonblank", 1, 1, 0, f_nextnonblank},
690 {"nr2char", 1, 2, 0, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200691 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200692 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200694 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200696#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200697 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
698 {"popup_beval", 2, 2, 0, f_popup_beval},
699 {"popup_clear", 0, 0, 0, f_popup_clear},
700 {"popup_close", 1, 2, 0, f_popup_close},
701 {"popup_create", 2, 2, 0, f_popup_create},
702 {"popup_dialog", 2, 2, 0, f_popup_dialog},
703 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
704 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
705 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
706 {"popup_getpos", 1, 1, 0, f_popup_getpos},
707 {"popup_getpreview", 0, 0, 0, f_popup_getpreview},
708 {"popup_hide", 1, 1, 0, f_popup_hide},
709 {"popup_locate", 2, 2, 0, f_popup_locate},
710 {"popup_menu", 2, 2, 0, f_popup_menu},
711 {"popup_move", 2, 2, 0, f_popup_move},
712 {"popup_notification", 2, 2, 0, f_popup_notification},
713 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
714 {"popup_settext", 2, 2, 0, f_popup_settext},
715 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200716#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200717#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200718 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200719#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200720 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200721 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200722#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200723 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
724 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
725 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200726#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100727#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200728 {"prop_add", 3, 3, 0, f_prop_add},
729 {"prop_clear", 1, 3, 0, f_prop_clear},
730 {"prop_list", 1, 2, 0, f_prop_list},
731 {"prop_remove", 1, 3, 0, f_prop_remove},
732 {"prop_type_add", 2, 2, 0, f_prop_type_add},
733 {"prop_type_change", 2, 2, 0, f_prop_type_change},
734 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
735 {"prop_type_get", 1, 2, 0, f_prop_type_get},
736 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100737#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200738 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200739 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200740#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200741 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200742#endif
743#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200744 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200745#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100746#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100748#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200749 {"range", 1, 3, 0, f_range},
750 {"readdir", 1, 2, 0, f_readdir},
751 {"readfile", 1, 3, 0, f_readfile},
752 {"reg_executing", 0, 0, 0, f_reg_executing},
753 {"reg_recording", 0, 0, 0, f_reg_recording},
754 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200755#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200756 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200758 {"reltimestr", 1, 1, 0, f_reltimestr},
759 {"remote_expr", 2, 4, 0, f_remote_expr},
760 {"remote_foreground", 1, 1, 0, f_remote_foreground},
761 {"remote_peek", 1, 2, 0, f_remote_peek},
762 {"remote_read", 1, 2, 0, f_remote_read},
763 {"remote_send", 2, 3, 0, f_remote_send},
764 {"remote_startserver", 1, 1, 0, f_remote_startserver},
765 {"remove", 2, 3, FEARG_1, f_remove},
766 {"rename", 2, 2, 0, f_rename},
767 {"repeat", 2, 2, FEARG_1, f_repeat},
768 {"resolve", 1, 1, 0, f_resolve},
769 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200770#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200771 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100773#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200774 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100775#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200776 {"screenattr", 2, 2, 0, f_screenattr},
777 {"screenchar", 2, 2, 0, f_screenchar},
778 {"screenchars", 2, 2, 0, f_screenchars},
779 {"screencol", 0, 0, 0, f_screencol},
780 {"screenpos", 3, 3, 0, f_screenpos},
781 {"screenrow", 0, 0, 0, f_screenrow},
782 {"screenstring", 2, 2, 0, f_screenstring},
783 {"search", 1, 4, 0, f_search},
784 {"searchdecl", 1, 3, 0, f_searchdecl},
785 {"searchpair", 3, 7, 0, f_searchpair},
786 {"searchpairpos", 3, 7, 0, f_searchpairpos},
787 {"searchpos", 1, 4, 0, f_searchpos},
788 {"server2client", 2, 2, 0, f_server2client},
789 {"serverlist", 0, 0, 0, f_serverlist},
790 {"setbufline", 3, 3, 0, f_setbufline},
791 {"setbufvar", 3, 3, 0, f_setbufvar},
792 {"setcharsearch", 1, 1, 0, f_setcharsearch},
793 {"setcmdpos", 1, 1, 0, f_setcmdpos},
794 {"setenv", 2, 2, 0, f_setenv},
795 {"setfperm", 2, 2, 0, f_setfperm},
796 {"setline", 2, 2, 0, f_setline},
797 {"setloclist", 2, 4, 0, f_setloclist},
798 {"setmatches", 1, 2, 0, f_setmatches},
799 {"setpos", 2, 2, 0, f_setpos},
800 {"setqflist", 1, 3, 0, f_setqflist},
801 {"setreg", 2, 3, 0, f_setreg},
802 {"settabvar", 3, 3, 0, f_settabvar},
803 {"settabwinvar", 4, 4, 0, f_settabwinvar},
804 {"settagstack", 2, 3, 0, f_settagstack},
805 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200806#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200807 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200809 {"shellescape", 1, 2, 0, f_shellescape},
810 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100811#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200812 {"sign_define", 1, 2, 0, f_sign_define},
813 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
814 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
815 {"sign_jump", 3, 3, 0, f_sign_jump},
816 {"sign_place", 4, 5, 0, f_sign_place},
817 {"sign_placelist", 1, 1, 0, f_sign_placelist},
818 {"sign_undefine", 0, 1, 0, f_sign_undefine},
819 {"sign_unplace", 1, 2, 0, f_sign_unplace},
820 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100821#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200822 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200824 {"sin", 1, 1, FEARG_1, f_sin},
825 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200826#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200827 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200828#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200829 {"sound_clear", 0, 0, 0, f_sound_clear},
830 {"sound_playevent", 1, 2, 0, f_sound_playevent},
831 {"sound_playfile", 1, 2, 0, f_sound_playfile},
832 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200833#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200834 {"soundfold", 1, 1, 0, f_soundfold},
835 {"spellbadword", 0, 1, 0, f_spellbadword},
836 {"spellsuggest", 1, 3, 0, f_spellsuggest},
837 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200838#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200839 {"sqrt", 1, 1, FEARG_1, f_sqrt},
840 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200841#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200842 {"str2list", 1, 2, FEARG_1, f_str2list},
843 {"str2nr", 1, 2, 0, f_str2nr},
844 {"strcharpart", 2, 3, 0, f_strcharpart},
845 {"strchars", 1, 2, 0, f_strchars},
846 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200848 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200850 {"strgetchar", 2, 2, 0, f_strgetchar},
851 {"stridx", 2, 3, 0, f_stridx},
852 {"string", 1, 1, FEARG_1, f_string},
853 {"strlen", 1, 1, FEARG_1, f_strlen},
854 {"strpart", 2, 3, 0, f_strpart},
855 {"strridx", 2, 3, 0, f_strridx},
856 {"strtrans", 1, 1, FEARG_1, f_strtrans},
857 {"strwidth", 1, 1, FEARG_1, f_strwidth},
858 {"submatch", 1, 2, 0, f_submatch},
859 {"substitute", 4, 4, FEARG_1, f_substitute},
860 {"swapinfo", 1, 1, 0, f_swapinfo},
861 {"swapname", 1, 1, 0, f_swapname},
862 {"synID", 3, 3, 0, f_synID},
863 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
864 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
865 {"synconcealed", 2, 2, 0, f_synconcealed},
866 {"synstack", 2, 2, 0, f_synstack},
867 {"system", 1, 2, FEARG_1, f_system},
868 {"systemlist", 1, 2, FEARG_1, f_systemlist},
869 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
870 {"tabpagenr", 0, 1, 0, f_tabpagenr},
871 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
872 {"tagfiles", 0, 0, 0, f_tagfiles},
873 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200875 {"tan", 1, 1, FEARG_1, f_tan},
876 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200877#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200878 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200879#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200880 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
881 {"term_dumpload", 1, 2, 0, f_term_dumpload},
882 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
883 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200884# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200885 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200886# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200887 {"term_getattr", 2, 2, 0, f_term_getattr},
888 {"term_getcursor", 1, 1, 0, f_term_getcursor},
889 {"term_getjob", 1, 1, 0, f_term_getjob},
890 {"term_getline", 2, 2, 0, f_term_getline},
891 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
892 {"term_getsize", 1, 1, 0, f_term_getsize},
893 {"term_getstatus", 1, 1, 0, f_term_getstatus},
894 {"term_gettitle", 1, 1, 0, f_term_gettitle},
895 {"term_gettty", 1, 2, 0, f_term_gettty},
896 {"term_list", 0, 0, 0, f_term_list},
897 {"term_scrape", 2, 2, 0, f_term_scrape},
898 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200899# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200900 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200901# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200902 {"term_setkill", 2, 2, 0, f_term_setkill},
903 {"term_setrestore", 2, 2, 0, f_term_setrestore},
904 {"term_setsize", 3, 3, 0, f_term_setsize},
905 {"term_start", 1, 2, 0, f_term_start},
906 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200907#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200908 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
909 {"test_autochdir", 0, 0, 0, f_test_autochdir},
910 {"test_feedinput", 1, 1, 0, f_test_feedinput},
911 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
912 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
913 {"test_getvalue", 1, 1, 0, f_test_getvalue},
914 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
915 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200916#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200917 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200919 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200921 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200923 {"test_null_list", 0, 0, 0, f_test_null_list},
924 {"test_null_partial", 0, 0, 0, f_test_null_partial},
925 {"test_null_string", 0, 0, 0, f_test_null_string},
926 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
927 {"test_override", 2, 2, 0, f_test_override},
928 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200929#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200930 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200931#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200932#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200933 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200934#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200935 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200936#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200937 {"timer_info", 0, 1, 0, f_timer_info},
938 {"timer_pause", 2, 2, 0, f_timer_pause},
939 {"timer_start", 2, 3, 0, f_timer_start},
940 {"timer_stop", 1, 1, 0, f_timer_stop},
941 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200942#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200943 {"tolower", 1, 1, 0, f_tolower},
944 {"toupper", 1, 1, 0, f_toupper},
945 {"tr", 3, 3, 0, f_tr},
946 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200947#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200948 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200950 {"type", 1, 1, FEARG_1, f_type},
951 {"undofile", 1, 1, 0, f_undofile},
952 {"undotree", 0, 0, 0, f_undotree},
953 {"uniq", 1, 3, FEARG_1, f_uniq},
954 {"values", 1, 1, FEARG_1, f_values},
955 {"virtcol", 1, 1, 0, f_virtcol},
956 {"visualmode", 0, 1, 0, f_visualmode},
957 {"wildmenumode", 0, 0, 0, f_wildmenumode},
958 {"win_execute", 2, 3, 0, f_win_execute},
959 {"win_findbuf", 1, 1, 0, f_win_findbuf},
960 {"win_getid", 0, 2, 0, f_win_getid},
961 {"win_gotoid", 1, 1, 0, f_win_gotoid},
962 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
963 {"win_id2win", 1, 1, 0, f_win_id2win},
964 {"win_screenpos", 1, 1, 0, f_win_screenpos},
965 {"winbufnr", 1, 1, 0, f_winbufnr},
966 {"wincol", 0, 0, 0, f_wincol},
967 {"winheight", 1, 1, 0, f_winheight},
968 {"winlayout", 0, 1, 0, f_winlayout},
969 {"winline", 0, 0, 0, f_winline},
970 {"winnr", 0, 1, 0, f_winnr},
971 {"winrestcmd", 0, 0, 0, f_winrestcmd},
972 {"winrestview", 1, 1, 0, f_winrestview},
973 {"winsaveview", 0, 0, 0, f_winsaveview},
974 {"winwidth", 1, 1, 0, f_winwidth},
975 {"wordcount", 0, 0, 0, f_wordcount},
976 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200977 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200978};
979
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200980/*
981 * Function given to ExpandGeneric() to obtain the list of internal
982 * or user defined function names.
983 */
984 char_u *
985get_function_name(expand_T *xp, int idx)
986{
987 static int intidx = -1;
988 char_u *name;
989
990 if (idx == 0)
991 intidx = -1;
992 if (intidx < 0)
993 {
994 name = get_user_func_name(xp, idx);
995 if (name != NULL)
996 return name;
997 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200998 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200999 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001000 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001001 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001002 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001003 STRCAT(IObuff, ")");
1004 return IObuff;
1005 }
1006
1007 return NULL;
1008}
1009
1010/*
1011 * Function given to ExpandGeneric() to obtain the list of internal or
1012 * user defined variable or function names.
1013 */
1014 char_u *
1015get_expr_name(expand_T *xp, int idx)
1016{
1017 static int intidx = -1;
1018 char_u *name;
1019
1020 if (idx == 0)
1021 intidx = -1;
1022 if (intidx < 0)
1023 {
1024 name = get_function_name(xp, idx);
1025 if (name != NULL)
1026 return name;
1027 }
1028 return get_user_var_name(xp, ++intidx);
1029}
1030
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001031/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001032 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001033 * Return index, or -1 if not found
1034 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001035 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001036find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001037{
1038 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001039 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001040 int cmp;
1041 int x;
1042
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001043 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001044
1045 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001046 while (first <= last)
1047 {
1048 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001049 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001050 if (cmp < 0)
1051 last = x - 1;
1052 else if (cmp > 0)
1053 first = x + 1;
1054 else
1055 return x;
1056 }
1057 return -1;
1058}
1059
1060 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001061has_internal_func(char_u *name)
1062{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001063 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001064}
1065
1066 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001067call_internal_func(
1068 char_u *name,
1069 int argcount,
1070 typval_T *argvars,
1071 typval_T *rettv)
1072{
1073 int i;
1074
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001075 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001076 if (i < 0)
1077 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001078 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001079 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001080 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001081 return ERROR_TOOMANY;
1082 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001083 global_functions[i].f_func(argvars, rettv);
1084 return ERROR_NONE;
1085}
1086
1087/*
1088 * Invoke a method for base->method().
1089 */
1090 int
1091call_internal_method(
1092 char_u *name,
1093 int argcount,
1094 typval_T *argvars,
1095 typval_T *rettv,
1096 typval_T *basetv)
1097{
1098 int i;
1099 int fi;
1100 typval_T argv[MAX_FUNC_ARGS + 1];
1101
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001102 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001103 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001104 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001105 if (global_functions[fi].f_argtype == 0)
1106 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001107 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001108 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001109 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001110 return ERROR_TOOMANY;
1111
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001112 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001113 {
1114 // base value goes last
1115 for (i = 0; i < argcount; ++i)
1116 argv[i] = argvars[i];
1117 argv[argcount] = *basetv;
1118 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001119 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001120 {
1121 // base value goes second
1122 argv[0] = argvars[0];
1123 argv[1] = *basetv;
1124 for (i = 1; i < argcount; ++i)
1125 argv[i + 1] = argvars[i];
1126 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001127 else if (global_functions[fi].f_argtype == FEARG_3)
1128 {
1129 // base value goes third
1130 argv[0] = argvars[0];
1131 argv[1] = argvars[1];
1132 argv[2] = *basetv;
1133 for (i = 2; i < argcount; ++i)
1134 argv[i + 1] = argvars[i];
1135 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001136 else
1137 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001138 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001139 argv[0] = *basetv;
1140 for (i = 0; i < argcount; ++i)
1141 argv[i + 1] = argvars[i];
1142 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001143 argv[argcount + 1].v_type = VAR_UNKNOWN;
1144
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001145 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001146 return ERROR_NONE;
1147}
1148
1149/*
1150 * Return TRUE for a non-zero Number and a non-empty String.
1151 */
1152 static int
1153non_zero_arg(typval_T *argvars)
1154{
1155 return ((argvars[0].v_type == VAR_NUMBER
1156 && argvars[0].vval.v_number != 0)
1157 || (argvars[0].v_type == VAR_SPECIAL
1158 && argvars[0].vval.v_number == VVAL_TRUE)
1159 || (argvars[0].v_type == VAR_STRING
1160 && argvars[0].vval.v_string != NULL
1161 && *argvars[0].vval.v_string != NUL));
1162}
1163
1164/*
1165 * Get the lnum from the first argument.
1166 * Also accepts ".", "$", etc., but that only works for the current buffer.
1167 * Returns -1 on error.
1168 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001169 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001170tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001171{
1172 typval_T rettv;
1173 linenr_T lnum;
1174
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001175 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001176 if (lnum == 0) /* no valid number, try using line() */
1177 {
1178 rettv.v_type = VAR_NUMBER;
1179 f_line(argvars, &rettv);
1180 lnum = (linenr_T)rettv.vval.v_number;
1181 clear_tv(&rettv);
1182 }
1183 return lnum;
1184}
1185
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001186/*
1187 * Get the lnum from the first argument.
1188 * Also accepts "$", then "buf" is used.
1189 * Returns 0 on error.
1190 */
1191 static linenr_T
1192tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1193{
1194 if (argvars[0].v_type == VAR_STRING
1195 && argvars[0].vval.v_string != NULL
1196 && argvars[0].vval.v_string[0] == '$'
1197 && buf != NULL)
1198 return buf->b_ml.ml_line_count;
1199 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1200}
1201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001202#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001203/*
1204 * Get the float value of "argvars[0]" into "f".
1205 * Returns FAIL when the argument is not a Number or Float.
1206 */
1207 static int
1208get_float_arg(typval_T *argvars, float_T *f)
1209{
1210 if (argvars[0].v_type == VAR_FLOAT)
1211 {
1212 *f = argvars[0].vval.v_float;
1213 return OK;
1214 }
1215 if (argvars[0].v_type == VAR_NUMBER)
1216 {
1217 *f = (float_T)argvars[0].vval.v_number;
1218 return OK;
1219 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001220 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001221 return FAIL;
1222}
1223
1224/*
1225 * "abs(expr)" function
1226 */
1227 static void
1228f_abs(typval_T *argvars, typval_T *rettv)
1229{
1230 if (argvars[0].v_type == VAR_FLOAT)
1231 {
1232 rettv->v_type = VAR_FLOAT;
1233 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1234 }
1235 else
1236 {
1237 varnumber_T n;
1238 int error = FALSE;
1239
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001240 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001241 if (error)
1242 rettv->vval.v_number = -1;
1243 else if (n > 0)
1244 rettv->vval.v_number = n;
1245 else
1246 rettv->vval.v_number = -n;
1247 }
1248}
1249
1250/*
1251 * "acos()" function
1252 */
1253 static void
1254f_acos(typval_T *argvars, typval_T *rettv)
1255{
1256 float_T f = 0.0;
1257
1258 rettv->v_type = VAR_FLOAT;
1259 if (get_float_arg(argvars, &f) == OK)
1260 rettv->vval.v_float = acos(f);
1261 else
1262 rettv->vval.v_float = 0.0;
1263}
1264#endif
1265
1266/*
1267 * "add(list, item)" function
1268 */
1269 static void
1270f_add(typval_T *argvars, typval_T *rettv)
1271{
1272 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001273 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001274
1275 rettv->vval.v_number = 1; /* Default: Failed */
1276 if (argvars[0].v_type == VAR_LIST)
1277 {
1278 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001279 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001280 (char_u *)N_("add() argument"), TRUE)
1281 && list_append_tv(l, &argvars[1]) == OK)
1282 copy_tv(&argvars[0], rettv);
1283 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001284 else if (argvars[0].v_type == VAR_BLOB)
1285 {
1286 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001287 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001288 (char_u *)N_("add() argument"), TRUE))
1289 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001290 int error = FALSE;
1291 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1292
1293 if (!error)
1294 {
1295 ga_append(&b->bv_ga, (int)n);
1296 copy_tv(&argvars[0], rettv);
1297 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001298 }
1299 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001300 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001301 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001302}
1303
1304/*
1305 * "and(expr, expr)" function
1306 */
1307 static void
1308f_and(typval_T *argvars, typval_T *rettv)
1309{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001310 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1311 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001312}
1313
1314/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001315 * If there is a window for "curbuf", make it the current window.
1316 */
1317 static void
1318find_win_for_curbuf(void)
1319{
1320 wininfo_T *wip;
1321
1322 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1323 {
1324 if (wip->wi_win != NULL)
1325 {
1326 curwin = wip->wi_win;
1327 break;
1328 }
1329 }
1330}
1331
1332/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001333 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001334 */
1335 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001336set_buffer_lines(
1337 buf_T *buf,
1338 linenr_T lnum_arg,
1339 int append,
1340 typval_T *lines,
1341 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001342{
Bram Moolenaarca851592018-06-06 21:04:07 +02001343 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1344 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001345 list_T *l = NULL;
1346 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001348 linenr_T append_lnum;
1349 buf_T *curbuf_save = NULL;
1350 win_T *curwin_save = NULL;
1351 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001352
Bram Moolenaarca851592018-06-06 21:04:07 +02001353 /* When using the current buffer ml_mfp will be set if needed. Useful when
1354 * setline() is used on startup. For other buffers the buffer must be
1355 * loaded. */
1356 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001357 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001358 rettv->vval.v_number = 1; /* FAIL */
1359 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 }
1361
Bram Moolenaarca851592018-06-06 21:04:07 +02001362 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001363 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001364 curbuf_save = curbuf;
1365 curwin_save = curwin;
1366 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001367 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001368 }
1369
1370 if (append)
1371 // appendbufline() uses the line number below which we insert
1372 append_lnum = lnum - 1;
1373 else
1374 // setbufline() uses the line number above which we insert, we only
1375 // append if it's below the last line
1376 append_lnum = curbuf->b_ml.ml_line_count;
1377
1378 if (lines->v_type == VAR_LIST)
1379 {
1380 l = lines->vval.v_list;
1381 li = l->lv_first;
1382 }
1383 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001384 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001385
1386 /* default result is zero == OK */
1387 for (;;)
1388 {
1389 if (l != NULL)
1390 {
1391 /* list argument, get next string */
1392 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001393 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001394 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001395 li = li->li_next;
1396 }
1397
Bram Moolenaarca851592018-06-06 21:04:07 +02001398 rettv->vval.v_number = 1; /* FAIL */
1399 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1400 break;
1401
1402 /* When coming here from Insert mode, sync undo, so that this can be
1403 * undone separately from what was previously inserted. */
1404 if (u_sync_once == 2)
1405 {
1406 u_sync_once = 1; /* notify that u_sync() was called */
1407 u_sync(TRUE);
1408 }
1409
1410 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1411 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001412 // Existing line, replace it.
1413 // Removes any existing text properties.
1414 if (u_savesub(lnum) == OK && ml_replace_len(
1415 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001416 {
1417 changed_bytes(lnum, 0);
1418 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1419 check_cursor_col();
1420 rettv->vval.v_number = 0; /* OK */
1421 }
1422 }
1423 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1424 {
1425 /* append the line */
1426 ++added;
1427 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1428 rettv->vval.v_number = 0; /* OK */
1429 }
1430
1431 if (l == NULL) /* only one string argument */
1432 break;
1433 ++lnum;
1434 }
1435
1436 if (added > 0)
1437 {
1438 win_T *wp;
1439 tabpage_T *tp;
1440
1441 appended_lines_mark(append_lnum, added);
1442 FOR_ALL_TAB_WINDOWS(tp, wp)
1443 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1444 wp->w_cursor.lnum += added;
1445 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001446 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001447 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001448
1449 if (!is_curbuf)
1450 {
1451 curbuf = curbuf_save;
1452 curwin = curwin_save;
1453 }
1454}
1455
1456/*
1457 * "append(lnum, string/list)" function
1458 */
1459 static void
1460f_append(typval_T *argvars, typval_T *rettv)
1461{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001462 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001463
1464 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1465}
1466
1467/*
1468 * "appendbufline(buf, lnum, string/list)" function
1469 */
1470 static void
1471f_appendbufline(typval_T *argvars, typval_T *rettv)
1472{
1473 linenr_T lnum;
1474 buf_T *buf;
1475
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001476 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001477 if (buf == NULL)
1478 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001479 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001480 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001481 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001482 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1483 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001484}
1485
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486#ifdef FEAT_FLOAT
1487/*
1488 * "asin()" function
1489 */
1490 static void
1491f_asin(typval_T *argvars, typval_T *rettv)
1492{
1493 float_T f = 0.0;
1494
1495 rettv->v_type = VAR_FLOAT;
1496 if (get_float_arg(argvars, &f) == OK)
1497 rettv->vval.v_float = asin(f);
1498 else
1499 rettv->vval.v_float = 0.0;
1500}
1501
1502/*
1503 * "atan()" function
1504 */
1505 static void
1506f_atan(typval_T *argvars, typval_T *rettv)
1507{
1508 float_T f = 0.0;
1509
1510 rettv->v_type = VAR_FLOAT;
1511 if (get_float_arg(argvars, &f) == OK)
1512 rettv->vval.v_float = atan(f);
1513 else
1514 rettv->vval.v_float = 0.0;
1515}
1516
1517/*
1518 * "atan2()" function
1519 */
1520 static void
1521f_atan2(typval_T *argvars, typval_T *rettv)
1522{
1523 float_T fx = 0.0, fy = 0.0;
1524
1525 rettv->v_type = VAR_FLOAT;
1526 if (get_float_arg(argvars, &fx) == OK
1527 && get_float_arg(&argvars[1], &fy) == OK)
1528 rettv->vval.v_float = atan2(fx, fy);
1529 else
1530 rettv->vval.v_float = 0.0;
1531}
1532#endif
1533
1534/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001535 * "balloon_show()" function
1536 */
1537#ifdef FEAT_BEVAL
1538 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001539f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1540{
1541 rettv->v_type = VAR_STRING;
1542 if (balloonEval != NULL)
1543 {
1544 if (balloonEval->msg == NULL)
1545 rettv->vval.v_string = NULL;
1546 else
1547 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1548 }
1549}
1550
1551 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001552f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1553{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001554 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001555 {
1556 if (argvars[0].v_type == VAR_LIST
1557# ifdef FEAT_GUI
1558 && !gui.in_use
1559# endif
1560 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001561 {
1562 list_T *l = argvars[0].vval.v_list;
1563
1564 // empty list removes the balloon
1565 post_balloon(balloonEval, NULL,
1566 l == NULL || l->lv_len == 0 ? NULL : l);
1567 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001568 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001569 {
1570 char_u *mesg = tv_get_string_chk(&argvars[0]);
1571
1572 if (mesg != NULL)
1573 // empty string removes the balloon
1574 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1575 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001576 }
1577}
1578
Bram Moolenaar669a8282017-11-19 20:13:05 +01001579# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001580 static void
1581f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1582{
1583 if (rettv_list_alloc(rettv) == OK)
1584 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001585 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001586
1587 if (msg != NULL)
1588 {
1589 pumitem_T *array;
1590 int size = split_message(msg, &array);
1591 int i;
1592
1593 /* Skip the first and last item, they are always empty. */
1594 for (i = 1; i < size - 1; ++i)
1595 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001596 while (size > 0)
1597 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001598 vim_free(array);
1599 }
1600 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001601}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001602# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001603#endif
1604
1605/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001606 * "browse(save, title, initdir, default)" function
1607 */
1608 static void
1609f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1610{
1611#ifdef FEAT_BROWSE
1612 int save;
1613 char_u *title;
1614 char_u *initdir;
1615 char_u *defname;
1616 char_u buf[NUMBUFLEN];
1617 char_u buf2[NUMBUFLEN];
1618 int error = FALSE;
1619
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001620 save = (int)tv_get_number_chk(&argvars[0], &error);
1621 title = tv_get_string_chk(&argvars[1]);
1622 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1623 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624
1625 if (error || title == NULL || initdir == NULL || defname == NULL)
1626 rettv->vval.v_string = NULL;
1627 else
1628 rettv->vval.v_string =
1629 do_browse(save ? BROWSE_SAVE : 0,
1630 title, defname, NULL, initdir, NULL, curbuf);
1631#else
1632 rettv->vval.v_string = NULL;
1633#endif
1634 rettv->v_type = VAR_STRING;
1635}
1636
1637/*
1638 * "browsedir(title, initdir)" function
1639 */
1640 static void
1641f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1642{
1643#ifdef FEAT_BROWSE
1644 char_u *title;
1645 char_u *initdir;
1646 char_u buf[NUMBUFLEN];
1647
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001648 title = tv_get_string_chk(&argvars[0]);
1649 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001650
1651 if (title == NULL || initdir == NULL)
1652 rettv->vval.v_string = NULL;
1653 else
1654 rettv->vval.v_string = do_browse(BROWSE_DIR,
1655 title, NULL, NULL, initdir, NULL, curbuf);
1656#else
1657 rettv->vval.v_string = NULL;
1658#endif
1659 rettv->v_type = VAR_STRING;
1660}
1661
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001662/*
1663 * Find a buffer by number or exact name.
1664 */
1665 static buf_T *
1666find_buffer(typval_T *avar)
1667{
1668 buf_T *buf = NULL;
1669
1670 if (avar->v_type == VAR_NUMBER)
1671 buf = buflist_findnr((int)avar->vval.v_number);
1672 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1673 {
1674 buf = buflist_findname_exp(avar->vval.v_string);
1675 if (buf == NULL)
1676 {
1677 /* No full path name match, try a match with a URL or a "nofile"
1678 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001679 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001680 if (buf->b_fname != NULL
1681 && (path_with_url(buf->b_fname)
1682#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001683 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001684#endif
1685 )
1686 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1687 break;
1688 }
1689 }
1690 return buf;
1691}
1692
1693/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001694 * "bufadd(expr)" function
1695 */
1696 static void
1697f_bufadd(typval_T *argvars, typval_T *rettv)
1698{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001699 char_u *name = tv_get_string(&argvars[0]);
1700
1701 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001702}
1703
1704/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001705 * "bufexists(expr)" function
1706 */
1707 static void
1708f_bufexists(typval_T *argvars, typval_T *rettv)
1709{
1710 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1711}
1712
1713/*
1714 * "buflisted(expr)" function
1715 */
1716 static void
1717f_buflisted(typval_T *argvars, typval_T *rettv)
1718{
1719 buf_T *buf;
1720
1721 buf = find_buffer(&argvars[0]);
1722 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1723}
1724
1725/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001726 * "bufload(expr)" function
1727 */
1728 static void
1729f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1730{
1731 buf_T *buf = get_buf_arg(&argvars[0]);
1732
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001733 if (buf != NULL)
1734 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001735}
1736
1737/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001738 * "bufloaded(expr)" function
1739 */
1740 static void
1741f_bufloaded(typval_T *argvars, typval_T *rettv)
1742{
1743 buf_T *buf;
1744
1745 buf = find_buffer(&argvars[0]);
1746 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1747}
1748
1749 buf_T *
1750buflist_find_by_name(char_u *name, int curtab_only)
1751{
1752 int save_magic;
1753 char_u *save_cpo;
1754 buf_T *buf;
1755
1756 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1757 save_magic = p_magic;
1758 p_magic = TRUE;
1759 save_cpo = p_cpo;
1760 p_cpo = (char_u *)"";
1761
1762 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1763 TRUE, FALSE, curtab_only));
1764
1765 p_magic = save_magic;
1766 p_cpo = save_cpo;
1767 return buf;
1768}
1769
1770/*
1771 * Get buffer by number or pattern.
1772 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001773 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001774tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001775{
1776 char_u *name = tv->vval.v_string;
1777 buf_T *buf;
1778
1779 if (tv->v_type == VAR_NUMBER)
1780 return buflist_findnr((int)tv->vval.v_number);
1781 if (tv->v_type != VAR_STRING)
1782 return NULL;
1783 if (name == NULL || *name == NUL)
1784 return curbuf;
1785 if (name[0] == '$' && name[1] == NUL)
1786 return lastbuf;
1787
1788 buf = buflist_find_by_name(name, curtab_only);
1789
1790 /* If not found, try expanding the name, like done for bufexists(). */
1791 if (buf == NULL)
1792 buf = find_buffer(tv);
1793
1794 return buf;
1795}
1796
1797/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001798 * Get the buffer from "arg" and give an error and return NULL if it is not
1799 * valid.
1800 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001801 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001802get_buf_arg(typval_T *arg)
1803{
1804 buf_T *buf;
1805
1806 ++emsg_off;
1807 buf = tv_get_buf(arg, FALSE);
1808 --emsg_off;
1809 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001810 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001811 return buf;
1812}
1813
1814/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001815 * "bufname(expr)" function
1816 */
1817 static void
1818f_bufname(typval_T *argvars, typval_T *rettv)
1819{
1820 buf_T *buf;
1821
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001822 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001823 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001824 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 rettv->v_type = VAR_STRING;
1826 if (buf != NULL && buf->b_fname != NULL)
1827 rettv->vval.v_string = vim_strsave(buf->b_fname);
1828 else
1829 rettv->vval.v_string = NULL;
1830 --emsg_off;
1831}
1832
1833/*
1834 * "bufnr(expr)" function
1835 */
1836 static void
1837f_bufnr(typval_T *argvars, typval_T *rettv)
1838{
1839 buf_T *buf;
1840 int error = FALSE;
1841 char_u *name;
1842
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001843 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001845 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846 --emsg_off;
1847
1848 /* If the buffer isn't found and the second argument is not zero create a
1849 * new buffer. */
1850 if (buf == NULL
1851 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001852 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001853 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001854 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001855 && !error)
1856 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1857
1858 if (buf != NULL)
1859 rettv->vval.v_number = buf->b_fnum;
1860 else
1861 rettv->vval.v_number = -1;
1862}
1863
1864 static void
1865buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1866{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001867 win_T *wp;
1868 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001869 buf_T *buf;
1870
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001871 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001872 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001873 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001874 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001875 {
1876 ++winnr;
1877 if (wp->w_buffer == buf)
1878 break;
1879 }
1880 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001881 --emsg_off;
1882}
1883
1884/*
1885 * "bufwinid(nr)" function
1886 */
1887 static void
1888f_bufwinid(typval_T *argvars, typval_T *rettv)
1889{
1890 buf_win_common(argvars, rettv, FALSE);
1891}
1892
1893/*
1894 * "bufwinnr(nr)" function
1895 */
1896 static void
1897f_bufwinnr(typval_T *argvars, typval_T *rettv)
1898{
1899 buf_win_common(argvars, rettv, TRUE);
1900}
1901
1902/*
1903 * "byte2line(byte)" function
1904 */
1905 static void
1906f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1907{
1908#ifndef FEAT_BYTEOFF
1909 rettv->vval.v_number = -1;
1910#else
1911 long boff = 0;
1912
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001913 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001914 if (boff < 0)
1915 rettv->vval.v_number = -1;
1916 else
1917 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1918 (linenr_T)0, &boff);
1919#endif
1920}
1921
1922 static void
1923byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1924{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001925 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001926 char_u *str;
1927 varnumber_T idx;
1928
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001929 str = tv_get_string_chk(&argvars[0]);
1930 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001931 rettv->vval.v_number = -1;
1932 if (str == NULL || idx < 0)
1933 return;
1934
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935 t = str;
1936 for ( ; idx > 0; idx--)
1937 {
1938 if (*t == NUL) /* EOL reached */
1939 return;
1940 if (enc_utf8 && comp)
1941 t += utf_ptr2len(t);
1942 else
1943 t += (*mb_ptr2len)(t);
1944 }
1945 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001946}
1947
1948/*
1949 * "byteidx()" function
1950 */
1951 static void
1952f_byteidx(typval_T *argvars, typval_T *rettv)
1953{
1954 byteidx(argvars, rettv, FALSE);
1955}
1956
1957/*
1958 * "byteidxcomp()" function
1959 */
1960 static void
1961f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1962{
1963 byteidx(argvars, rettv, TRUE);
1964}
1965
1966/*
1967 * "call(func, arglist [, dict])" function
1968 */
1969 static void
1970f_call(typval_T *argvars, typval_T *rettv)
1971{
1972 char_u *func;
1973 partial_T *partial = NULL;
1974 dict_T *selfdict = NULL;
1975
1976 if (argvars[1].v_type != VAR_LIST)
1977 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001978 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979 return;
1980 }
1981 if (argvars[1].vval.v_list == NULL)
1982 return;
1983
1984 if (argvars[0].v_type == VAR_FUNC)
1985 func = argvars[0].vval.v_string;
1986 else if (argvars[0].v_type == VAR_PARTIAL)
1987 {
1988 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001989 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001990 }
1991 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001992 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001993 if (*func == NUL)
1994 return; /* type error or empty name */
1995
1996 if (argvars[2].v_type != VAR_UNKNOWN)
1997 {
1998 if (argvars[2].v_type != VAR_DICT)
1999 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002000 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002001 return;
2002 }
2003 selfdict = argvars[2].vval.v_dict;
2004 }
2005
2006 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2007}
2008
2009#ifdef FEAT_FLOAT
2010/*
2011 * "ceil({float})" function
2012 */
2013 static void
2014f_ceil(typval_T *argvars, typval_T *rettv)
2015{
2016 float_T f = 0.0;
2017
2018 rettv->v_type = VAR_FLOAT;
2019 if (get_float_arg(argvars, &f) == OK)
2020 rettv->vval.v_float = ceil(f);
2021 else
2022 rettv->vval.v_float = 0.0;
2023}
2024#endif
2025
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002026/*
2027 * "changenr()" function
2028 */
2029 static void
2030f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2031{
2032 rettv->vval.v_number = curbuf->b_u_seq_cur;
2033}
2034
2035/*
2036 * "char2nr(string)" function
2037 */
2038 static void
2039f_char2nr(typval_T *argvars, typval_T *rettv)
2040{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002041 if (has_mbyte)
2042 {
2043 int utf8 = 0;
2044
2045 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002046 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002047
2048 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002049 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002050 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002051 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052 }
2053 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002054 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002055}
2056
2057/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002058 * "chdir(dir)" function
2059 */
2060 static void
2061f_chdir(typval_T *argvars, typval_T *rettv)
2062{
2063 char_u *cwd;
2064 cdscope_T scope = CDSCOPE_GLOBAL;
2065
2066 rettv->v_type = VAR_STRING;
2067 rettv->vval.v_string = NULL;
2068
2069 if (argvars[0].v_type != VAR_STRING)
2070 return;
2071
2072 // Return the current directory
2073 cwd = alloc(MAXPATHL);
2074 if (cwd != NULL)
2075 {
2076 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2077 {
2078#ifdef BACKSLASH_IN_FILENAME
2079 slash_adjust(cwd);
2080#endif
2081 rettv->vval.v_string = vim_strsave(cwd);
2082 }
2083 vim_free(cwd);
2084 }
2085
2086 if (curwin->w_localdir != NULL)
2087 scope = CDSCOPE_WINDOW;
2088 else if (curtab->tp_localdir != NULL)
2089 scope = CDSCOPE_TABPAGE;
2090
2091 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2092 // Directory change failed
2093 VIM_CLEAR(rettv->vval.v_string);
2094}
2095
2096/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 * "cindent(lnum)" function
2098 */
2099 static void
2100f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2101{
2102#ifdef FEAT_CINDENT
2103 pos_T pos;
2104 linenr_T lnum;
2105
2106 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002107 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002108 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2109 {
2110 curwin->w_cursor.lnum = lnum;
2111 rettv->vval.v_number = get_c_indent();
2112 curwin->w_cursor = pos;
2113 }
2114 else
2115#endif
2116 rettv->vval.v_number = -1;
2117}
2118
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002119 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002120get_optional_window(typval_T *argvars, int idx)
2121{
2122 win_T *win = curwin;
2123
2124 if (argvars[idx].v_type != VAR_UNKNOWN)
2125 {
2126 win = find_win_by_nr_or_id(&argvars[idx]);
2127 if (win == NULL)
2128 {
2129 emsg(_(e_invalwindow));
2130 return NULL;
2131 }
2132 }
2133 return win;
2134}
2135
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002136/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002137 * "col(string)" function
2138 */
2139 static void
2140f_col(typval_T *argvars, typval_T *rettv)
2141{
2142 colnr_T col = 0;
2143 pos_T *fp;
2144 int fnum = curbuf->b_fnum;
2145
2146 fp = var2fpos(&argvars[0], FALSE, &fnum);
2147 if (fp != NULL && fnum == curbuf->b_fnum)
2148 {
2149 if (fp->col == MAXCOL)
2150 {
2151 /* '> can be MAXCOL, get the length of the line then */
2152 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2153 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2154 else
2155 col = MAXCOL;
2156 }
2157 else
2158 {
2159 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002160 /* col(".") when the cursor is on the NUL at the end of the line
2161 * because of "coladd" can be seen as an extra column. */
2162 if (virtual_active() && fp == &curwin->w_cursor)
2163 {
2164 char_u *p = ml_get_cursor();
2165
2166 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2167 curwin->w_virtcol - curwin->w_cursor.coladd))
2168 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 int l;
2170
2171 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2172 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173 }
2174 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 }
2176 }
2177 rettv->vval.v_number = col;
2178}
2179
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180/*
2181 * "confirm(message, buttons[, default [, type]])" function
2182 */
2183 static void
2184f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2185{
2186#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2187 char_u *message;
2188 char_u *buttons = NULL;
2189 char_u buf[NUMBUFLEN];
2190 char_u buf2[NUMBUFLEN];
2191 int def = 1;
2192 int type = VIM_GENERIC;
2193 char_u *typestr;
2194 int error = FALSE;
2195
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002196 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002197 if (message == NULL)
2198 error = TRUE;
2199 if (argvars[1].v_type != VAR_UNKNOWN)
2200 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002201 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002202 if (buttons == NULL)
2203 error = TRUE;
2204 if (argvars[2].v_type != VAR_UNKNOWN)
2205 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002206 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207 if (argvars[3].v_type != VAR_UNKNOWN)
2208 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002209 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210 if (typestr == NULL)
2211 error = TRUE;
2212 else
2213 {
2214 switch (TOUPPER_ASC(*typestr))
2215 {
2216 case 'E': type = VIM_ERROR; break;
2217 case 'Q': type = VIM_QUESTION; break;
2218 case 'I': type = VIM_INFO; break;
2219 case 'W': type = VIM_WARNING; break;
2220 case 'G': type = VIM_GENERIC; break;
2221 }
2222 }
2223 }
2224 }
2225 }
2226
2227 if (buttons == NULL || *buttons == NUL)
2228 buttons = (char_u *)_("&Ok");
2229
2230 if (!error)
2231 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2232 def, NULL, FALSE);
2233#endif
2234}
2235
2236/*
2237 * "copy()" function
2238 */
2239 static void
2240f_copy(typval_T *argvars, typval_T *rettv)
2241{
2242 item_copy(&argvars[0], rettv, FALSE, 0);
2243}
2244
2245#ifdef FEAT_FLOAT
2246/*
2247 * "cos()" function
2248 */
2249 static void
2250f_cos(typval_T *argvars, typval_T *rettv)
2251{
2252 float_T f = 0.0;
2253
2254 rettv->v_type = VAR_FLOAT;
2255 if (get_float_arg(argvars, &f) == OK)
2256 rettv->vval.v_float = cos(f);
2257 else
2258 rettv->vval.v_float = 0.0;
2259}
2260
2261/*
2262 * "cosh()" function
2263 */
2264 static void
2265f_cosh(typval_T *argvars, typval_T *rettv)
2266{
2267 float_T f = 0.0;
2268
2269 rettv->v_type = VAR_FLOAT;
2270 if (get_float_arg(argvars, &f) == OK)
2271 rettv->vval.v_float = cosh(f);
2272 else
2273 rettv->vval.v_float = 0.0;
2274}
2275#endif
2276
2277/*
2278 * "count()" function
2279 */
2280 static void
2281f_count(typval_T *argvars, typval_T *rettv)
2282{
2283 long n = 0;
2284 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002285 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002286
Bram Moolenaar9966b212017-07-28 16:46:57 +02002287 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002288 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002289
2290 if (argvars[0].v_type == VAR_STRING)
2291 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002292 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002293 char_u *p = argvars[0].vval.v_string;
2294 char_u *next;
2295
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002296 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002297 {
2298 if (ic)
2299 {
2300 size_t len = STRLEN(expr);
2301
2302 while (*p != NUL)
2303 {
2304 if (MB_STRNICMP(p, expr, len) == 0)
2305 {
2306 ++n;
2307 p += len;
2308 }
2309 else
2310 MB_PTR_ADV(p);
2311 }
2312 }
2313 else
2314 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2315 != NULL)
2316 {
2317 ++n;
2318 p = next + STRLEN(expr);
2319 }
2320 }
2321
2322 }
2323 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002324 {
2325 listitem_T *li;
2326 list_T *l;
2327 long idx;
2328
2329 if ((l = argvars[0].vval.v_list) != NULL)
2330 {
2331 li = l->lv_first;
2332 if (argvars[2].v_type != VAR_UNKNOWN)
2333 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002334 if (argvars[3].v_type != VAR_UNKNOWN)
2335 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002336 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002337 if (!error)
2338 {
2339 li = list_find(l, idx);
2340 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002341 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002342 }
2343 }
2344 if (error)
2345 li = NULL;
2346 }
2347
2348 for ( ; li != NULL; li = li->li_next)
2349 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2350 ++n;
2351 }
2352 }
2353 else if (argvars[0].v_type == VAR_DICT)
2354 {
2355 int todo;
2356 dict_T *d;
2357 hashitem_T *hi;
2358
2359 if ((d = argvars[0].vval.v_dict) != NULL)
2360 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002361 if (argvars[2].v_type != VAR_UNKNOWN)
2362 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002363 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002364 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365 }
2366
2367 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2368 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2369 {
2370 if (!HASHITEM_EMPTY(hi))
2371 {
2372 --todo;
2373 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2374 ++n;
2375 }
2376 }
2377 }
2378 }
2379 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002380 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002381 rettv->vval.v_number = n;
2382}
2383
2384/*
2385 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2386 *
2387 * Checks the existence of a cscope connection.
2388 */
2389 static void
2390f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2391{
2392#ifdef FEAT_CSCOPE
2393 int num = 0;
2394 char_u *dbpath = NULL;
2395 char_u *prepend = NULL;
2396 char_u buf[NUMBUFLEN];
2397
2398 if (argvars[0].v_type != VAR_UNKNOWN
2399 && argvars[1].v_type != VAR_UNKNOWN)
2400 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002401 num = (int)tv_get_number(&argvars[0]);
2402 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002403 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002404 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002405 }
2406
2407 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2408#endif
2409}
2410
2411/*
2412 * "cursor(lnum, col)" function, or
2413 * "cursor(list)"
2414 *
2415 * Moves the cursor to the specified line and column.
2416 * Returns 0 when the position could be set, -1 otherwise.
2417 */
2418 static void
2419f_cursor(typval_T *argvars, typval_T *rettv)
2420{
2421 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002422 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002423 int set_curswant = TRUE;
2424
2425 rettv->vval.v_number = -1;
2426 if (argvars[1].v_type == VAR_UNKNOWN)
2427 {
2428 pos_T pos;
2429 colnr_T curswant = -1;
2430
2431 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2432 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002433 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 return;
2435 }
2436 line = pos.lnum;
2437 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002438 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002439 if (curswant >= 0)
2440 {
2441 curwin->w_curswant = curswant - 1;
2442 set_curswant = FALSE;
2443 }
2444 }
2445 else
2446 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002447 line = tv_get_lnum(argvars);
2448 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002449 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002450 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002452 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002453 return; /* type error; errmsg already given */
2454 if (line > 0)
2455 curwin->w_cursor.lnum = line;
2456 if (col > 0)
2457 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459
2460 /* Make sure the cursor is in a valid position. */
2461 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002462 /* Correct cursor for multi-byte character. */
2463 if (has_mbyte)
2464 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465
2466 curwin->w_set_curswant = set_curswant;
2467 rettv->vval.v_number = 0;
2468}
2469
Bram Moolenaar4f974752019-02-17 17:44:42 +01002470#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002471/*
2472 * "debugbreak()" function
2473 */
2474 static void
2475f_debugbreak(typval_T *argvars, typval_T *rettv)
2476{
2477 int pid;
2478
2479 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002480 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002481 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002482 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002483 else
2484 {
2485 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2486
2487 if (hProcess != NULL)
2488 {
2489 DebugBreakProcess(hProcess);
2490 CloseHandle(hProcess);
2491 rettv->vval.v_number = OK;
2492 }
2493 }
2494}
2495#endif
2496
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002497/*
2498 * "deepcopy()" function
2499 */
2500 static void
2501f_deepcopy(typval_T *argvars, typval_T *rettv)
2502{
2503 int noref = 0;
2504 int copyID;
2505
2506 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002507 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002508 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002509 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002510 else
2511 {
2512 copyID = get_copyID();
2513 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2514 }
2515}
2516
2517/*
2518 * "delete()" function
2519 */
2520 static void
2521f_delete(typval_T *argvars, typval_T *rettv)
2522{
2523 char_u nbuf[NUMBUFLEN];
2524 char_u *name;
2525 char_u *flags;
2526
2527 rettv->vval.v_number = -1;
2528 if (check_restricted() || check_secure())
2529 return;
2530
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002531 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002532 if (name == NULL || *name == NUL)
2533 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002534 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002535 return;
2536 }
2537
2538 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002539 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002540 else
2541 flags = (char_u *)"";
2542
2543 if (*flags == NUL)
2544 /* delete a file */
2545 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2546 else if (STRCMP(flags, "d") == 0)
2547 /* delete an empty directory */
2548 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2549 else if (STRCMP(flags, "rf") == 0)
2550 /* delete a directory recursively */
2551 rettv->vval.v_number = delete_recursive(name);
2552 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002553 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554}
2555
2556/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002557 * "deletebufline()" function
2558 */
2559 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002560f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002561{
2562 buf_T *buf;
2563 linenr_T first, last;
2564 linenr_T lnum;
2565 long count;
2566 int is_curbuf;
2567 buf_T *curbuf_save = NULL;
2568 win_T *curwin_save = NULL;
2569 tabpage_T *tp;
2570 win_T *wp;
2571
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002572 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002573 if (buf == NULL)
2574 {
2575 rettv->vval.v_number = 1; /* FAIL */
2576 return;
2577 }
2578 is_curbuf = buf == curbuf;
2579
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002580 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002581 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002582 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002583 else
2584 last = first;
2585
2586 if (buf->b_ml.ml_mfp == NULL || first < 1
2587 || first > buf->b_ml.ml_line_count || last < first)
2588 {
2589 rettv->vval.v_number = 1; /* FAIL */
2590 return;
2591 }
2592
2593 if (!is_curbuf)
2594 {
2595 curbuf_save = curbuf;
2596 curwin_save = curwin;
2597 curbuf = buf;
2598 find_win_for_curbuf();
2599 }
2600 if (last > curbuf->b_ml.ml_line_count)
2601 last = curbuf->b_ml.ml_line_count;
2602 count = last - first + 1;
2603
2604 // When coming here from Insert mode, sync undo, so that this can be
2605 // undone separately from what was previously inserted.
2606 if (u_sync_once == 2)
2607 {
2608 u_sync_once = 1; // notify that u_sync() was called
2609 u_sync(TRUE);
2610 }
2611
2612 if (u_save(first - 1, last + 1) == FAIL)
2613 {
2614 rettv->vval.v_number = 1; /* FAIL */
2615 return;
2616 }
2617
2618 for (lnum = first; lnum <= last; ++lnum)
2619 ml_delete(first, TRUE);
2620
2621 FOR_ALL_TAB_WINDOWS(tp, wp)
2622 if (wp->w_buffer == buf)
2623 {
2624 if (wp->w_cursor.lnum > last)
2625 wp->w_cursor.lnum -= count;
2626 else if (wp->w_cursor.lnum> first)
2627 wp->w_cursor.lnum = first;
2628 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2629 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2630 }
2631 check_cursor_col();
2632 deleted_lines_mark(first, count);
2633
2634 if (!is_curbuf)
2635 {
2636 curbuf = curbuf_save;
2637 curwin = curwin_save;
2638 }
2639}
2640
2641/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002642 * "did_filetype()" function
2643 */
2644 static void
2645f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2646{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002647 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002648}
2649
2650/*
2651 * "diff_filler()" function
2652 */
2653 static void
2654f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2655{
2656#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002657 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002658#endif
2659}
2660
2661/*
2662 * "diff_hlID()" function
2663 */
2664 static void
2665f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2666{
2667#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002668 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002669 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002670 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002671 static int fnum = 0;
2672 static int change_start = 0;
2673 static int change_end = 0;
2674 static hlf_T hlID = (hlf_T)0;
2675 int filler_lines;
2676 int col;
2677
2678 if (lnum < 0) /* ignore type error in {lnum} arg */
2679 lnum = 0;
2680 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002681 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 || fnum != curbuf->b_fnum)
2683 {
2684 /* New line, buffer, change: need to get the values. */
2685 filler_lines = diff_check(curwin, lnum);
2686 if (filler_lines < 0)
2687 {
2688 if (filler_lines == -1)
2689 {
2690 change_start = MAXCOL;
2691 change_end = -1;
2692 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2693 hlID = HLF_ADD; /* added line */
2694 else
2695 hlID = HLF_CHD; /* changed line */
2696 }
2697 else
2698 hlID = HLF_ADD; /* added line */
2699 }
2700 else
2701 hlID = (hlf_T)0;
2702 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002703 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 fnum = curbuf->b_fnum;
2705 }
2706
2707 if (hlID == HLF_CHD || hlID == HLF_TXD)
2708 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002709 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002710 if (col >= change_start && col <= change_end)
2711 hlID = HLF_TXD; /* changed text */
2712 else
2713 hlID = HLF_CHD; /* changed line */
2714 }
2715 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2716#endif
2717}
2718
2719/*
2720 * "empty({expr})" function
2721 */
2722 static void
2723f_empty(typval_T *argvars, typval_T *rettv)
2724{
2725 int n = FALSE;
2726
2727 switch (argvars[0].v_type)
2728 {
2729 case VAR_STRING:
2730 case VAR_FUNC:
2731 n = argvars[0].vval.v_string == NULL
2732 || *argvars[0].vval.v_string == NUL;
2733 break;
2734 case VAR_PARTIAL:
2735 n = FALSE;
2736 break;
2737 case VAR_NUMBER:
2738 n = argvars[0].vval.v_number == 0;
2739 break;
2740 case VAR_FLOAT:
2741#ifdef FEAT_FLOAT
2742 n = argvars[0].vval.v_float == 0.0;
2743 break;
2744#endif
2745 case VAR_LIST:
2746 n = argvars[0].vval.v_list == NULL
2747 || argvars[0].vval.v_list->lv_first == NULL;
2748 break;
2749 case VAR_DICT:
2750 n = argvars[0].vval.v_dict == NULL
2751 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2752 break;
2753 case VAR_SPECIAL:
2754 n = argvars[0].vval.v_number != VVAL_TRUE;
2755 break;
2756
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002757 case VAR_BLOB:
2758 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002759 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2760 break;
2761
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 case VAR_JOB:
2763#ifdef FEAT_JOB_CHANNEL
2764 n = argvars[0].vval.v_job == NULL
2765 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2766 break;
2767#endif
2768 case VAR_CHANNEL:
2769#ifdef FEAT_JOB_CHANNEL
2770 n = argvars[0].vval.v_channel == NULL
2771 || !channel_is_open(argvars[0].vval.v_channel);
2772 break;
2773#endif
2774 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002775 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002776 n = TRUE;
2777 break;
2778 }
2779
2780 rettv->vval.v_number = n;
2781}
2782
2783/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002784 * "environ()" function
2785 */
2786 static void
2787f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2788{
2789#if !defined(AMIGA)
2790 int i = 0;
2791 char_u *entry, *value;
2792# ifdef MSWIN
2793 extern wchar_t **_wenviron;
2794# else
2795 extern char **environ;
2796# endif
2797
2798 if (rettv_dict_alloc(rettv) != OK)
2799 return;
2800
2801# ifdef MSWIN
2802 if (*_wenviron == NULL)
2803 return;
2804# else
2805 if (*environ == NULL)
2806 return;
2807# endif
2808
2809 for (i = 0; ; ++i)
2810 {
2811# ifdef MSWIN
2812 short_u *p;
2813
2814 if ((p = (short_u *)_wenviron[i]) == NULL)
2815 return;
2816 entry = utf16_to_enc(p, NULL);
2817# else
2818 if ((entry = (char_u *)environ[i]) == NULL)
2819 return;
2820 entry = vim_strsave(entry);
2821# endif
2822 if (entry == NULL) // out of memory
2823 return;
2824 if ((value = vim_strchr(entry, '=')) == NULL)
2825 {
2826 vim_free(entry);
2827 continue;
2828 }
2829 *value++ = NUL;
2830 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2831 vim_free(entry);
2832 }
2833#endif
2834}
2835
2836/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002837 * "escape({string}, {chars})" function
2838 */
2839 static void
2840f_escape(typval_T *argvars, typval_T *rettv)
2841{
2842 char_u buf[NUMBUFLEN];
2843
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002844 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2845 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002846 rettv->v_type = VAR_STRING;
2847}
2848
2849/*
2850 * "eval()" function
2851 */
2852 static void
2853f_eval(typval_T *argvars, typval_T *rettv)
2854{
2855 char_u *s, *p;
2856
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002857 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002858 if (s != NULL)
2859 s = skipwhite(s);
2860
2861 p = s;
2862 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2863 {
2864 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002865 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002866 need_clr_eos = FALSE;
2867 rettv->v_type = VAR_NUMBER;
2868 rettv->vval.v_number = 0;
2869 }
2870 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002871 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002872}
2873
2874/*
2875 * "eventhandler()" function
2876 */
2877 static void
2878f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2879{
2880 rettv->vval.v_number = vgetc_busy;
2881}
2882
2883/*
2884 * "executable()" function
2885 */
2886 static void
2887f_executable(typval_T *argvars, typval_T *rettv)
2888{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002889 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002890
2891 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02002892 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002893}
2894
2895static garray_T redir_execute_ga;
2896
2897/*
2898 * Append "value[value_len]" to the execute() output.
2899 */
2900 void
2901execute_redir_str(char_u *value, int value_len)
2902{
2903 int len;
2904
2905 if (value_len == -1)
2906 len = (int)STRLEN(value); /* Append the entire string */
2907 else
2908 len = value_len; /* Append only "value_len" characters */
2909 if (ga_grow(&redir_execute_ga, len) == OK)
2910 {
2911 mch_memmove((char *)redir_execute_ga.ga_data
2912 + redir_execute_ga.ga_len, value, len);
2913 redir_execute_ga.ga_len += len;
2914 }
2915}
2916
2917/*
2918 * Get next line from a list.
2919 * Called by do_cmdline() to get the next line.
2920 * Returns allocated string, or NULL for end of function.
2921 */
2922
2923 static char_u *
2924get_list_line(
2925 int c UNUSED,
2926 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002927 int indent UNUSED,
2928 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002929{
2930 listitem_T **p = (listitem_T **)cookie;
2931 listitem_T *item = *p;
2932 char_u buf[NUMBUFLEN];
2933 char_u *s;
2934
2935 if (item == NULL)
2936 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002937 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002938 *p = item->li_next;
2939 return s == NULL ? NULL : vim_strsave(s);
2940}
2941
2942/*
2943 * "execute()" function
2944 */
2945 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002946execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002947{
2948 char_u *cmd = NULL;
2949 list_T *list = NULL;
2950 int save_msg_silent = msg_silent;
2951 int save_emsg_silent = emsg_silent;
2952 int save_emsg_noredir = emsg_noredir;
2953 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002954 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002955 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002956 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002957 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002958
2959 rettv->vval.v_string = NULL;
2960 rettv->v_type = VAR_STRING;
2961
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002962 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002963 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002964 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002965 if (list == NULL || list->lv_first == NULL)
2966 /* empty list, no commands, empty output */
2967 return;
2968 ++list->lv_refcount;
2969 }
2970 else
2971 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002972 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002973 if (cmd == NULL)
2974 return;
2975 }
2976
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002977 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002978 {
2979 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002980 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002981
2982 if (s == NULL)
2983 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002984 if (*s == NUL)
2985 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002986 if (STRNCMP(s, "silent", 6) == 0)
2987 ++msg_silent;
2988 if (STRCMP(s, "silent!") == 0)
2989 {
2990 emsg_silent = TRUE;
2991 emsg_noredir = TRUE;
2992 }
2993 }
2994 else
2995 ++msg_silent;
2996
2997 if (redir_execute)
2998 save_ga = redir_execute_ga;
2999 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3000 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003001 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003002 if (!echo_output)
3003 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003004
3005 if (cmd != NULL)
3006 do_cmdline_cmd(cmd);
3007 else
3008 {
3009 listitem_T *item = list->lv_first;
3010
3011 do_cmdline(NULL, get_list_line, (void *)&item,
3012 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3013 --list->lv_refcount;
3014 }
3015
Bram Moolenaard297f352017-01-29 20:31:21 +01003016 /* Need to append a NUL to the result. */
3017 if (ga_grow(&redir_execute_ga, 1) == OK)
3018 {
3019 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3020 rettv->vval.v_string = redir_execute_ga.ga_data;
3021 }
3022 else
3023 {
3024 ga_clear(&redir_execute_ga);
3025 rettv->vval.v_string = NULL;
3026 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003027 msg_silent = save_msg_silent;
3028 emsg_silent = save_emsg_silent;
3029 emsg_noredir = save_emsg_noredir;
3030
3031 redir_execute = save_redir_execute;
3032 if (redir_execute)
3033 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003034 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003035
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003036 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003037 if (echo_output)
3038 // When not working silently: put it in column zero. A following
3039 // "echon" will overwrite the message, unavoidably.
3040 msg_col = 0;
3041 else
3042 // When working silently: Put it back where it was, since nothing
3043 // should have been written.
3044 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003045}
3046
3047/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003048 * "execute()" function
3049 */
3050 static void
3051f_execute(typval_T *argvars, typval_T *rettv)
3052{
3053 execute_common(argvars, rettv, 0);
3054}
3055
3056/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003057 * "exepath()" function
3058 */
3059 static void
3060f_exepath(typval_T *argvars, typval_T *rettv)
3061{
3062 char_u *p = NULL;
3063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003064 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065 rettv->v_type = VAR_STRING;
3066 rettv->vval.v_string = p;
3067}
3068
3069/*
3070 * "exists()" function
3071 */
3072 static void
3073f_exists(typval_T *argvars, typval_T *rettv)
3074{
3075 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003078 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079 if (*p == '$') /* environment variable */
3080 {
3081 /* first try "normal" environment variables (fast) */
3082 if (mch_getenv(p + 1) != NULL)
3083 n = TRUE;
3084 else
3085 {
3086 /* try expanding things like $VIM and ${HOME} */
3087 p = expand_env_save(p);
3088 if (p != NULL && *p != '$')
3089 n = TRUE;
3090 vim_free(p);
3091 }
3092 }
3093 else if (*p == '&' || *p == '+') /* option */
3094 {
3095 n = (get_option_tv(&p, NULL, TRUE) == OK);
3096 if (*skipwhite(p) != NUL)
3097 n = FALSE; /* trailing garbage */
3098 }
3099 else if (*p == '*') /* internal or user defined function */
3100 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003101 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102 }
3103 else if (*p == ':')
3104 {
3105 n = cmd_exists(p + 1);
3106 }
3107 else if (*p == '#')
3108 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003109 if (p[1] == '#')
3110 n = autocmd_supported(p + 2);
3111 else
3112 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003113 }
3114 else /* internal variable */
3115 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003116 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003117 }
3118
3119 rettv->vval.v_number = n;
3120}
3121
3122#ifdef FEAT_FLOAT
3123/*
3124 * "exp()" function
3125 */
3126 static void
3127f_exp(typval_T *argvars, typval_T *rettv)
3128{
3129 float_T f = 0.0;
3130
3131 rettv->v_type = VAR_FLOAT;
3132 if (get_float_arg(argvars, &f) == OK)
3133 rettv->vval.v_float = exp(f);
3134 else
3135 rettv->vval.v_float = 0.0;
3136}
3137#endif
3138
3139/*
3140 * "expand()" function
3141 */
3142 static void
3143f_expand(typval_T *argvars, typval_T *rettv)
3144{
3145 char_u *s;
3146 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003147 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003148 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3149 expand_T xpc;
3150 int error = FALSE;
3151 char_u *result;
3152
3153 rettv->v_type = VAR_STRING;
3154 if (argvars[1].v_type != VAR_UNKNOWN
3155 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003156 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003157 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003158 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003159
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003160 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003161 if (*s == '%' || *s == '#' || *s == '<')
3162 {
3163 ++emsg_off;
3164 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3165 --emsg_off;
3166 if (rettv->v_type == VAR_LIST)
3167 {
3168 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3169 list_append_string(rettv->vval.v_list, result, -1);
3170 else
3171 vim_free(result);
3172 }
3173 else
3174 rettv->vval.v_string = result;
3175 }
3176 else
3177 {
3178 /* When the optional second argument is non-zero, don't remove matches
3179 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3180 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003181 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003182 options |= WILD_KEEP_ALL;
3183 if (!error)
3184 {
3185 ExpandInit(&xpc);
3186 xpc.xp_context = EXPAND_FILES;
3187 if (p_wic)
3188 options += WILD_ICASE;
3189 if (rettv->v_type == VAR_STRING)
3190 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3191 options, WILD_ALL);
3192 else if (rettv_list_alloc(rettv) != FAIL)
3193 {
3194 int i;
3195
3196 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3197 for (i = 0; i < xpc.xp_numfiles; i++)
3198 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3199 ExpandCleanup(&xpc);
3200 }
3201 }
3202 else
3203 rettv->vval.v_string = NULL;
3204 }
3205}
3206
3207/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003208 * "expandcmd()" function
3209 * Expand all the special characters in a command string.
3210 */
3211 static void
3212f_expandcmd(typval_T *argvars, typval_T *rettv)
3213{
3214 exarg_T eap;
3215 char_u *cmdstr;
3216 char *errormsg = NULL;
3217
3218 rettv->v_type = VAR_STRING;
3219 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3220
3221 memset(&eap, 0, sizeof(eap));
3222 eap.cmd = cmdstr;
3223 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003224 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003225 eap.usefilter = FALSE;
3226 eap.nextcmd = NULL;
3227 eap.cmdidx = CMD_USER;
3228
3229 expand_filename(&eap, &cmdstr, &errormsg);
3230 if (errormsg != NULL && *errormsg != NUL)
3231 emsg(errormsg);
3232
3233 rettv->vval.v_string = cmdstr;
3234}
3235
3236/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003237 * "extend(list, list [, idx])" function
3238 * "extend(dict, dict [, action])" function
3239 */
3240 static void
3241f_extend(typval_T *argvars, typval_T *rettv)
3242{
3243 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3244
3245 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3246 {
3247 list_T *l1, *l2;
3248 listitem_T *item;
3249 long before;
3250 int error = FALSE;
3251
3252 l1 = argvars[0].vval.v_list;
3253 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003254 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003255 && l2 != NULL)
3256 {
3257 if (argvars[2].v_type != VAR_UNKNOWN)
3258 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003259 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003260 if (error)
3261 return; /* type error; errmsg already given */
3262
3263 if (before == l1->lv_len)
3264 item = NULL;
3265 else
3266 {
3267 item = list_find(l1, before);
3268 if (item == NULL)
3269 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003270 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003271 return;
3272 }
3273 }
3274 }
3275 else
3276 item = NULL;
3277 list_extend(l1, l2, item);
3278
3279 copy_tv(&argvars[0], rettv);
3280 }
3281 }
3282 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3283 {
3284 dict_T *d1, *d2;
3285 char_u *action;
3286 int i;
3287
3288 d1 = argvars[0].vval.v_dict;
3289 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003290 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003291 && d2 != NULL)
3292 {
3293 /* Check the third argument. */
3294 if (argvars[2].v_type != VAR_UNKNOWN)
3295 {
3296 static char *(av[]) = {"keep", "force", "error"};
3297
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003298 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299 if (action == NULL)
3300 return; /* type error; errmsg already given */
3301 for (i = 0; i < 3; ++i)
3302 if (STRCMP(action, av[i]) == 0)
3303 break;
3304 if (i == 3)
3305 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003306 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003307 return;
3308 }
3309 }
3310 else
3311 action = (char_u *)"force";
3312
3313 dict_extend(d1, d2, action);
3314
3315 copy_tv(&argvars[0], rettv);
3316 }
3317 }
3318 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003319 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003320}
3321
3322/*
3323 * "feedkeys()" function
3324 */
3325 static void
3326f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3327{
3328 int remap = TRUE;
3329 int insert = FALSE;
3330 char_u *keys, *flags;
3331 char_u nbuf[NUMBUFLEN];
3332 int typed = FALSE;
3333 int execute = FALSE;
3334 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003335 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003336 char_u *keys_esc;
3337
3338 /* This is not allowed in the sandbox. If the commands would still be
3339 * executed in the sandbox it would be OK, but it probably happens later,
3340 * when "sandbox" is no longer set. */
3341 if (check_secure())
3342 return;
3343
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003344 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003345
3346 if (argvars[1].v_type != VAR_UNKNOWN)
3347 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003348 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003349 for ( ; *flags != NUL; ++flags)
3350 {
3351 switch (*flags)
3352 {
3353 case 'n': remap = FALSE; break;
3354 case 'm': remap = TRUE; break;
3355 case 't': typed = TRUE; break;
3356 case 'i': insert = TRUE; break;
3357 case 'x': execute = TRUE; break;
3358 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003359 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360 }
3361 }
3362 }
3363
3364 if (*keys != NUL || execute)
3365 {
3366 /* Need to escape K_SPECIAL and CSI before putting the string in the
3367 * typeahead buffer. */
3368 keys_esc = vim_strsave_escape_csi(keys);
3369 if (keys_esc != NULL)
3370 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003371 if (lowlevel)
3372 {
3373#ifdef USE_INPUT_BUF
3374 add_to_input_buf(keys, (int)STRLEN(keys));
3375#else
3376 emsg(_("E980: lowlevel input not supported"));
3377#endif
3378 }
3379 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003380 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003381 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003382 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003383 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003384#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003385 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003386#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003387 )
3388 typebuf_was_filled = TRUE;
3389 }
3390 vim_free(keys_esc);
3391
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 if (execute)
3393 {
3394 int save_msg_scroll = msg_scroll;
3395
3396 /* Avoid a 1 second delay when the keys start Insert mode. */
3397 msg_scroll = FALSE;
3398
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003399 if (!dangerous)
3400 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003401 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003402 if (!dangerous)
3403 --ex_normal_busy;
3404
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003405 msg_scroll |= save_msg_scroll;
3406 }
3407 }
3408 }
3409}
3410
3411/*
3412 * "filereadable()" function
3413 */
3414 static void
3415f_filereadable(typval_T *argvars, typval_T *rettv)
3416{
3417 int fd;
3418 char_u *p;
3419 int n;
3420
3421#ifndef O_NONBLOCK
3422# define O_NONBLOCK 0
3423#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003424 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3426 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3427 {
3428 n = TRUE;
3429 close(fd);
3430 }
3431 else
3432 n = FALSE;
3433
3434 rettv->vval.v_number = n;
3435}
3436
3437/*
3438 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3439 * rights to write into.
3440 */
3441 static void
3442f_filewritable(typval_T *argvars, typval_T *rettv)
3443{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003444 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003445}
3446
3447 static void
3448findfilendir(
3449 typval_T *argvars UNUSED,
3450 typval_T *rettv,
3451 int find_what UNUSED)
3452{
3453#ifdef FEAT_SEARCHPATH
3454 char_u *fname;
3455 char_u *fresult = NULL;
3456 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3457 char_u *p;
3458 char_u pathbuf[NUMBUFLEN];
3459 int count = 1;
3460 int first = TRUE;
3461 int error = FALSE;
3462#endif
3463
3464 rettv->vval.v_string = NULL;
3465 rettv->v_type = VAR_STRING;
3466
3467#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003468 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003469
3470 if (argvars[1].v_type != VAR_UNKNOWN)
3471 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003472 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003473 if (p == NULL)
3474 error = TRUE;
3475 else
3476 {
3477 if (*p != NUL)
3478 path = p;
3479
3480 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003481 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003482 }
3483 }
3484
3485 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3486 error = TRUE;
3487
3488 if (*fname != NUL && !error)
3489 {
3490 do
3491 {
3492 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3493 vim_free(fresult);
3494 fresult = find_file_in_path_option(first ? fname : NULL,
3495 first ? (int)STRLEN(fname) : 0,
3496 0, first, path,
3497 find_what,
3498 curbuf->b_ffname,
3499 find_what == FINDFILE_DIR
3500 ? (char_u *)"" : curbuf->b_p_sua);
3501 first = FALSE;
3502
3503 if (fresult != NULL && rettv->v_type == VAR_LIST)
3504 list_append_string(rettv->vval.v_list, fresult, -1);
3505
3506 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3507 }
3508
3509 if (rettv->v_type == VAR_STRING)
3510 rettv->vval.v_string = fresult;
3511#endif
3512}
3513
3514/*
3515 * "filter()" function
3516 */
3517 static void
3518f_filter(typval_T *argvars, typval_T *rettv)
3519{
3520 filter_map(argvars, rettv, FALSE);
3521}
3522
3523/*
3524 * "finddir({fname}[, {path}[, {count}]])" function
3525 */
3526 static void
3527f_finddir(typval_T *argvars, typval_T *rettv)
3528{
3529 findfilendir(argvars, rettv, FINDFILE_DIR);
3530}
3531
3532/*
3533 * "findfile({fname}[, {path}[, {count}]])" function
3534 */
3535 static void
3536f_findfile(typval_T *argvars, typval_T *rettv)
3537{
3538 findfilendir(argvars, rettv, FINDFILE_FILE);
3539}
3540
3541#ifdef FEAT_FLOAT
3542/*
3543 * "float2nr({float})" function
3544 */
3545 static void
3546f_float2nr(typval_T *argvars, typval_T *rettv)
3547{
3548 float_T f = 0.0;
3549
3550 if (get_float_arg(argvars, &f) == OK)
3551 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003552 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003553 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003554 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003555 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003556 else
3557 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003558 }
3559}
3560
3561/*
3562 * "floor({float})" function
3563 */
3564 static void
3565f_floor(typval_T *argvars, typval_T *rettv)
3566{
3567 float_T f = 0.0;
3568
3569 rettv->v_type = VAR_FLOAT;
3570 if (get_float_arg(argvars, &f) == OK)
3571 rettv->vval.v_float = floor(f);
3572 else
3573 rettv->vval.v_float = 0.0;
3574}
3575
3576/*
3577 * "fmod()" function
3578 */
3579 static void
3580f_fmod(typval_T *argvars, typval_T *rettv)
3581{
3582 float_T fx = 0.0, fy = 0.0;
3583
3584 rettv->v_type = VAR_FLOAT;
3585 if (get_float_arg(argvars, &fx) == OK
3586 && get_float_arg(&argvars[1], &fy) == OK)
3587 rettv->vval.v_float = fmod(fx, fy);
3588 else
3589 rettv->vval.v_float = 0.0;
3590}
3591#endif
3592
3593/*
3594 * "fnameescape({string})" function
3595 */
3596 static void
3597f_fnameescape(typval_T *argvars, typval_T *rettv)
3598{
3599 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003600 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003601 rettv->v_type = VAR_STRING;
3602}
3603
3604/*
3605 * "fnamemodify({fname}, {mods})" function
3606 */
3607 static void
3608f_fnamemodify(typval_T *argvars, typval_T *rettv)
3609{
3610 char_u *fname;
3611 char_u *mods;
3612 int usedlen = 0;
3613 int len;
3614 char_u *fbuf = NULL;
3615 char_u buf[NUMBUFLEN];
3616
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003617 fname = tv_get_string_chk(&argvars[0]);
3618 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003619 if (fname == NULL || mods == NULL)
3620 fname = NULL;
3621 else
3622 {
3623 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003624 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003625 }
3626
3627 rettv->v_type = VAR_STRING;
3628 if (fname == NULL)
3629 rettv->vval.v_string = NULL;
3630 else
3631 rettv->vval.v_string = vim_strnsave(fname, len);
3632 vim_free(fbuf);
3633}
3634
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635/*
3636 * "foldclosed()" function
3637 */
3638 static void
3639foldclosed_both(
3640 typval_T *argvars UNUSED,
3641 typval_T *rettv,
3642 int end UNUSED)
3643{
3644#ifdef FEAT_FOLDING
3645 linenr_T lnum;
3646 linenr_T first, last;
3647
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003648 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3650 {
3651 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3652 {
3653 if (end)
3654 rettv->vval.v_number = (varnumber_T)last;
3655 else
3656 rettv->vval.v_number = (varnumber_T)first;
3657 return;
3658 }
3659 }
3660#endif
3661 rettv->vval.v_number = -1;
3662}
3663
3664/*
3665 * "foldclosed()" function
3666 */
3667 static void
3668f_foldclosed(typval_T *argvars, typval_T *rettv)
3669{
3670 foldclosed_both(argvars, rettv, FALSE);
3671}
3672
3673/*
3674 * "foldclosedend()" function
3675 */
3676 static void
3677f_foldclosedend(typval_T *argvars, typval_T *rettv)
3678{
3679 foldclosed_both(argvars, rettv, TRUE);
3680}
3681
3682/*
3683 * "foldlevel()" function
3684 */
3685 static void
3686f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3687{
3688#ifdef FEAT_FOLDING
3689 linenr_T lnum;
3690
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003691 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003692 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3693 rettv->vval.v_number = foldLevel(lnum);
3694#endif
3695}
3696
3697/*
3698 * "foldtext()" function
3699 */
3700 static void
3701f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3702{
3703#ifdef FEAT_FOLDING
3704 linenr_T foldstart;
3705 linenr_T foldend;
3706 char_u *dashes;
3707 linenr_T lnum;
3708 char_u *s;
3709 char_u *r;
3710 int len;
3711 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003712 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003713#endif
3714
3715 rettv->v_type = VAR_STRING;
3716 rettv->vval.v_string = NULL;
3717#ifdef FEAT_FOLDING
3718 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3719 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3720 dashes = get_vim_var_str(VV_FOLDDASHES);
3721 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3722 && dashes != NULL)
3723 {
3724 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003725 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003726 if (!linewhite(lnum))
3727 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003728
3729 /* Find interesting text in this line. */
3730 s = skipwhite(ml_get(lnum));
3731 /* skip C comment-start */
3732 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3733 {
3734 s = skipwhite(s + 2);
3735 if (*skipwhite(s) == NUL
3736 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3737 {
3738 s = skipwhite(ml_get(lnum + 1));
3739 if (*s == '*')
3740 s = skipwhite(s + 1);
3741 }
3742 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003743 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003744 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003745 r = alloc(STRLEN(txt)
3746 + STRLEN(dashes) // for %s
3747 + 20 // for %3ld
3748 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003749 if (r != NULL)
3750 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003751 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003752 len = (int)STRLEN(r);
3753 STRCAT(r, s);
3754 /* remove 'foldmarker' and 'commentstring' */
3755 foldtext_cleanup(r + len);
3756 rettv->vval.v_string = r;
3757 }
3758 }
3759#endif
3760}
3761
3762/*
3763 * "foldtextresult(lnum)" function
3764 */
3765 static void
3766f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3767{
3768#ifdef FEAT_FOLDING
3769 linenr_T lnum;
3770 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003771 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003772 foldinfo_T foldinfo;
3773 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003774 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775#endif
3776
3777 rettv->v_type = VAR_STRING;
3778 rettv->vval.v_string = NULL;
3779#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003780 if (entered)
3781 return; /* reject recursive use */
3782 entered = TRUE;
3783
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003784 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003785 /* treat illegal types and illegal string values for {lnum} the same */
3786 if (lnum < 0)
3787 lnum = 0;
3788 fold_count = foldedCount(curwin, lnum, &foldinfo);
3789 if (fold_count > 0)
3790 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003791 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3792 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003793 if (text == buf)
3794 text = vim_strsave(text);
3795 rettv->vval.v_string = text;
3796 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003797
3798 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003799#endif
3800}
3801
3802/*
3803 * "foreground()" function
3804 */
3805 static void
3806f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3807{
3808#ifdef FEAT_GUI
3809 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003810 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003811 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003812 return;
3813 }
3814#endif
3815#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003816 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003817#endif
3818}
3819
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003820 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003821common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003822{
3823 char_u *s;
3824 char_u *name;
3825 int use_string = FALSE;
3826 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003827 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003828
3829 if (argvars[0].v_type == VAR_FUNC)
3830 {
3831 /* function(MyFunc, [arg], dict) */
3832 s = argvars[0].vval.v_string;
3833 }
3834 else if (argvars[0].v_type == VAR_PARTIAL
3835 && argvars[0].vval.v_partial != NULL)
3836 {
3837 /* function(dict.MyFunc, [arg]) */
3838 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003839 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003840 }
3841 else
3842 {
3843 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003844 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003845 use_string = TRUE;
3846 }
3847
Bram Moolenaar843b8842016-08-21 14:36:15 +02003848 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003849 {
3850 name = s;
3851 trans_name = trans_function_name(&name, FALSE,
3852 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3853 if (*name != NUL)
3854 s = NULL;
3855 }
3856
Bram Moolenaar843b8842016-08-21 14:36:15 +02003857 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3858 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003859 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003860 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003861 else if (trans_name != NULL && (is_funcref
3862 ? find_func(trans_name) == NULL
3863 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003864 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003865 else
3866 {
3867 int dict_idx = 0;
3868 int arg_idx = 0;
3869 list_T *list = NULL;
3870
3871 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3872 {
3873 char sid_buf[25];
3874 int off = *s == 's' ? 2 : 5;
3875
3876 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3877 * also be called from another script. Using trans_function_name()
3878 * would also work, but some plugins depend on the name being
3879 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003880 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003881 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003882 if (name != NULL)
3883 {
3884 STRCPY(name, sid_buf);
3885 STRCAT(name, s + off);
3886 }
3887 }
3888 else
3889 name = vim_strsave(s);
3890
3891 if (argvars[1].v_type != VAR_UNKNOWN)
3892 {
3893 if (argvars[2].v_type != VAR_UNKNOWN)
3894 {
3895 /* function(name, [args], dict) */
3896 arg_idx = 1;
3897 dict_idx = 2;
3898 }
3899 else if (argvars[1].v_type == VAR_DICT)
3900 /* function(name, dict) */
3901 dict_idx = 1;
3902 else
3903 /* function(name, [args]) */
3904 arg_idx = 1;
3905 if (dict_idx > 0)
3906 {
3907 if (argvars[dict_idx].v_type != VAR_DICT)
3908 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003909 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003910 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003911 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912 }
3913 if (argvars[dict_idx].vval.v_dict == NULL)
3914 dict_idx = 0;
3915 }
3916 if (arg_idx > 0)
3917 {
3918 if (argvars[arg_idx].v_type != VAR_LIST)
3919 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003920 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003922 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923 }
3924 list = argvars[arg_idx].vval.v_list;
3925 if (list == NULL || list->lv_len == 0)
3926 arg_idx = 0;
3927 }
3928 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003929 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003930 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003931 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932
3933 /* result is a VAR_PARTIAL */
3934 if (pt == NULL)
3935 vim_free(name);
3936 else
3937 {
3938 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3939 {
3940 listitem_T *li;
3941 int i = 0;
3942 int arg_len = 0;
3943 int lv_len = 0;
3944
3945 if (arg_pt != NULL)
3946 arg_len = arg_pt->pt_argc;
3947 if (list != NULL)
3948 lv_len = list->lv_len;
3949 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003950 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003951 if (pt->pt_argv == NULL)
3952 {
3953 vim_free(pt);
3954 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003955 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003957 for (i = 0; i < arg_len; i++)
3958 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3959 if (lv_len > 0)
3960 for (li = list->lv_first; li != NULL;
3961 li = li->li_next)
3962 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003963 }
3964
3965 /* For "function(dict.func, [], dict)" and "func" is a partial
3966 * use "dict". That is backwards compatible. */
3967 if (dict_idx > 0)
3968 {
3969 /* The dict is bound explicitly, pt_auto is FALSE. */
3970 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3971 ++pt->pt_dict->dv_refcount;
3972 }
3973 else if (arg_pt != NULL)
3974 {
3975 /* If the dict was bound automatically the result is also
3976 * bound automatically. */
3977 pt->pt_dict = arg_pt->pt_dict;
3978 pt->pt_auto = arg_pt->pt_auto;
3979 if (pt->pt_dict != NULL)
3980 ++pt->pt_dict->dv_refcount;
3981 }
3982
3983 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003984 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3985 {
3986 pt->pt_func = arg_pt->pt_func;
3987 func_ptr_ref(pt->pt_func);
3988 vim_free(name);
3989 }
3990 else if (is_funcref)
3991 {
3992 pt->pt_func = find_func(trans_name);
3993 func_ptr_ref(pt->pt_func);
3994 vim_free(name);
3995 }
3996 else
3997 {
3998 pt->pt_name = name;
3999 func_ref(name);
4000 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004001 }
4002 rettv->v_type = VAR_PARTIAL;
4003 rettv->vval.v_partial = pt;
4004 }
4005 else
4006 {
4007 /* result is a VAR_FUNC */
4008 rettv->v_type = VAR_FUNC;
4009 rettv->vval.v_string = name;
4010 func_ref(name);
4011 }
4012 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004013theend:
4014 vim_free(trans_name);
4015}
4016
4017/*
4018 * "funcref()" function
4019 */
4020 static void
4021f_funcref(typval_T *argvars, typval_T *rettv)
4022{
4023 common_function(argvars, rettv, TRUE);
4024}
4025
4026/*
4027 * "function()" function
4028 */
4029 static void
4030f_function(typval_T *argvars, typval_T *rettv)
4031{
4032 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004033}
4034
4035/*
4036 * "garbagecollect()" function
4037 */
4038 static void
4039f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4040{
4041 /* This is postponed until we are back at the toplevel, because we may be
4042 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4043 want_garbage_collect = TRUE;
4044
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004045 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004046 garbage_collect_at_exit = TRUE;
4047}
4048
4049/*
4050 * "get()" function
4051 */
4052 static void
4053f_get(typval_T *argvars, typval_T *rettv)
4054{
4055 listitem_T *li;
4056 list_T *l;
4057 dictitem_T *di;
4058 dict_T *d;
4059 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004060 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004061
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004062 if (argvars[0].v_type == VAR_BLOB)
4063 {
4064 int error = FALSE;
4065 int idx = tv_get_number_chk(&argvars[1], &error);
4066
4067 if (!error)
4068 {
4069 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004070 if (idx < 0)
4071 idx = blob_len(argvars[0].vval.v_blob) + idx;
4072 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4073 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004074 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004075 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004076 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004077 tv = rettv;
4078 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004079 }
4080 }
4081 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004082 {
4083 if ((l = argvars[0].vval.v_list) != NULL)
4084 {
4085 int error = FALSE;
4086
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004087 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004088 if (!error && li != NULL)
4089 tv = &li->li_tv;
4090 }
4091 }
4092 else if (argvars[0].v_type == VAR_DICT)
4093 {
4094 if ((d = argvars[0].vval.v_dict) != NULL)
4095 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004096 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004097 if (di != NULL)
4098 tv = &di->di_tv;
4099 }
4100 }
4101 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4102 {
4103 partial_T *pt;
4104 partial_T fref_pt;
4105
4106 if (argvars[0].v_type == VAR_PARTIAL)
4107 pt = argvars[0].vval.v_partial;
4108 else
4109 {
4110 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4111 fref_pt.pt_name = argvars[0].vval.v_string;
4112 pt = &fref_pt;
4113 }
4114
4115 if (pt != NULL)
4116 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004117 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004118 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004119
4120 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4121 {
4122 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004123 n = partial_name(pt);
4124 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004125 rettv->vval.v_string = NULL;
4126 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004127 {
4128 rettv->vval.v_string = vim_strsave(n);
4129 if (rettv->v_type == VAR_FUNC)
4130 func_ref(rettv->vval.v_string);
4131 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004132 }
4133 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004134 {
4135 what_is_dict = TRUE;
4136 if (pt->pt_dict != NULL)
4137 rettv_dict_set(rettv, pt->pt_dict);
4138 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004139 else if (STRCMP(what, "args") == 0)
4140 {
4141 rettv->v_type = VAR_LIST;
4142 if (rettv_list_alloc(rettv) == OK)
4143 {
4144 int i;
4145
4146 for (i = 0; i < pt->pt_argc; ++i)
4147 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4148 }
4149 }
4150 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004151 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004152
4153 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4154 // third argument
4155 if (!what_is_dict)
4156 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004157 }
4158 }
4159 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004160 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004161
4162 if (tv == NULL)
4163 {
4164 if (argvars[2].v_type != VAR_UNKNOWN)
4165 copy_tv(&argvars[2], rettv);
4166 }
4167 else
4168 copy_tv(tv, rettv);
4169}
4170
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004171/*
4172 * Returns buffer options, variables and other attributes in a dictionary.
4173 */
4174 static dict_T *
4175get_buffer_info(buf_T *buf)
4176{
4177 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004178 tabpage_T *tp;
4179 win_T *wp;
4180 list_T *windows;
4181
4182 dict = dict_alloc();
4183 if (dict == NULL)
4184 return NULL;
4185
Bram Moolenaare0be1672018-07-08 16:50:37 +02004186 dict_add_number(dict, "bufnr", buf->b_fnum);
4187 dict_add_string(dict, "name", buf->b_ffname);
4188 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4189 : buflist_findlnum(buf));
4190 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4191 dict_add_number(dict, "listed", buf->b_p_bl);
4192 dict_add_number(dict, "changed", bufIsChanged(buf));
4193 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4194 dict_add_number(dict, "hidden",
4195 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004196
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004197 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004198 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004199
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004200 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004201 windows = list_alloc();
4202 if (windows != NULL)
4203 {
4204 FOR_ALL_TAB_WINDOWS(tp, wp)
4205 if (wp->w_buffer == buf)
4206 list_append_number(windows, (varnumber_T)wp->w_id);
4207 dict_add_list(dict, "windows", windows);
4208 }
4209
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004210#ifdef FEAT_TEXT_PROP
4211 // List of popup windows displaying this buffer
4212 windows = list_alloc();
4213 if (windows != NULL)
4214 {
4215 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4216 if (wp->w_buffer == buf)
4217 list_append_number(windows, (varnumber_T)wp->w_id);
4218 FOR_ALL_TABPAGES(tp)
4219 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4220 if (wp->w_buffer == buf)
4221 list_append_number(windows, (varnumber_T)wp->w_id);
4222
4223 dict_add_list(dict, "popups", windows);
4224 }
4225#endif
4226
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004227#ifdef FEAT_SIGNS
4228 if (buf->b_signlist != NULL)
4229 {
4230 /* List of signs placed in this buffer */
4231 list_T *signs = list_alloc();
4232 if (signs != NULL)
4233 {
4234 get_buffer_signs(buf, signs);
4235 dict_add_list(dict, "signs", signs);
4236 }
4237 }
4238#endif
4239
4240 return dict;
4241}
4242
4243/*
4244 * "getbufinfo()" function
4245 */
4246 static void
4247f_getbufinfo(typval_T *argvars, typval_T *rettv)
4248{
4249 buf_T *buf = NULL;
4250 buf_T *argbuf = NULL;
4251 dict_T *d;
4252 int filtered = FALSE;
4253 int sel_buflisted = FALSE;
4254 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004255 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004256
4257 if (rettv_list_alloc(rettv) != OK)
4258 return;
4259
4260 /* List of all the buffers or selected buffers */
4261 if (argvars[0].v_type == VAR_DICT)
4262 {
4263 dict_T *sel_d = argvars[0].vval.v_dict;
4264
4265 if (sel_d != NULL)
4266 {
4267 dictitem_T *di;
4268
4269 filtered = TRUE;
4270
4271 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004272 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004273 sel_buflisted = TRUE;
4274
4275 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004276 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004277 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004278
4279 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004280 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004281 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004282 }
4283 }
4284 else if (argvars[0].v_type != VAR_UNKNOWN)
4285 {
4286 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004287 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004288 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004289 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004290 --emsg_off;
4291 if (argbuf == NULL)
4292 return;
4293 }
4294
4295 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004296 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004297 {
4298 if (argbuf != NULL && argbuf != buf)
4299 continue;
4300 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004301 || (sel_buflisted && !buf->b_p_bl)
4302 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004303 continue;
4304
4305 d = get_buffer_info(buf);
4306 if (d != NULL)
4307 list_append_dict(rettv->vval.v_list, d);
4308 if (argbuf != NULL)
4309 return;
4310 }
4311}
4312
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004313/*
4314 * Get line or list of lines from buffer "buf" into "rettv".
4315 * Return a range (from start to end) of lines in rettv from the specified
4316 * buffer.
4317 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4318 */
4319 static void
4320get_buffer_lines(
4321 buf_T *buf,
4322 linenr_T start,
4323 linenr_T end,
4324 int retlist,
4325 typval_T *rettv)
4326{
4327 char_u *p;
4328
4329 rettv->v_type = VAR_STRING;
4330 rettv->vval.v_string = NULL;
4331 if (retlist && rettv_list_alloc(rettv) == FAIL)
4332 return;
4333
4334 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4335 return;
4336
4337 if (!retlist)
4338 {
4339 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4340 p = ml_get_buf(buf, start, FALSE);
4341 else
4342 p = (char_u *)"";
4343 rettv->vval.v_string = vim_strsave(p);
4344 }
4345 else
4346 {
4347 if (end < start)
4348 return;
4349
4350 if (start < 1)
4351 start = 1;
4352 if (end > buf->b_ml.ml_line_count)
4353 end = buf->b_ml.ml_line_count;
4354 while (start <= end)
4355 if (list_append_string(rettv->vval.v_list,
4356 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4357 break;
4358 }
4359}
4360
4361/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004362 * "getbufline()" function
4363 */
4364 static void
4365f_getbufline(typval_T *argvars, typval_T *rettv)
4366{
4367 linenr_T lnum;
4368 linenr_T end;
4369 buf_T *buf;
4370
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004371 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004372 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004373 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004374 --emsg_off;
4375
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004376 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004377 if (argvars[2].v_type == VAR_UNKNOWN)
4378 end = lnum;
4379 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004380 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004381
4382 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4383}
4384
4385/*
4386 * "getbufvar()" function
4387 */
4388 static void
4389f_getbufvar(typval_T *argvars, typval_T *rettv)
4390{
4391 buf_T *buf;
4392 buf_T *save_curbuf;
4393 char_u *varname;
4394 dictitem_T *v;
4395 int done = FALSE;
4396
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004397 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4398 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004399 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004400 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004401
4402 rettv->v_type = VAR_STRING;
4403 rettv->vval.v_string = NULL;
4404
4405 if (buf != NULL && varname != NULL)
4406 {
4407 /* set curbuf to be our buf, temporarily */
4408 save_curbuf = curbuf;
4409 curbuf = buf;
4410
Bram Moolenaar30567352016-08-27 21:25:44 +02004411 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004412 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004413 if (varname[1] == NUL)
4414 {
4415 /* get all buffer-local options in a dict */
4416 dict_T *opts = get_winbuf_options(TRUE);
4417
4418 if (opts != NULL)
4419 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004420 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004421 done = TRUE;
4422 }
4423 }
4424 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4425 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004426 done = TRUE;
4427 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004428 else
4429 {
4430 /* Look up the variable. */
4431 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4432 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4433 'b', varname, FALSE);
4434 if (v != NULL)
4435 {
4436 copy_tv(&v->di_tv, rettv);
4437 done = TRUE;
4438 }
4439 }
4440
4441 /* restore previous notion of curbuf */
4442 curbuf = save_curbuf;
4443 }
4444
4445 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4446 /* use the default value */
4447 copy_tv(&argvars[2], rettv);
4448
4449 --emsg_off;
4450}
4451
4452/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004453 * "getchangelist()" function
4454 */
4455 static void
4456f_getchangelist(typval_T *argvars, typval_T *rettv)
4457{
4458#ifdef FEAT_JUMPLIST
4459 buf_T *buf;
4460 int i;
4461 list_T *l;
4462 dict_T *d;
4463#endif
4464
4465 if (rettv_list_alloc(rettv) != OK)
4466 return;
4467
4468#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004469 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004470 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004471 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004472 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004473 if (buf == NULL)
4474 return;
4475
4476 l = list_alloc();
4477 if (l == NULL)
4478 return;
4479
4480 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4481 return;
4482 /*
4483 * The current window change list index tracks only the position in the
4484 * current buffer change list. For other buffers, use the change list
4485 * length as the current index.
4486 */
4487 list_append_number(rettv->vval.v_list,
4488 (varnumber_T)((buf == curwin->w_buffer)
4489 ? curwin->w_changelistidx : buf->b_changelistlen));
4490
4491 for (i = 0; i < buf->b_changelistlen; ++i)
4492 {
4493 if (buf->b_changelist[i].lnum == 0)
4494 continue;
4495 if ((d = dict_alloc()) == NULL)
4496 return;
4497 if (list_append_dict(l, d) == FAIL)
4498 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004499 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4500 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004501 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004502 }
4503#endif
4504}
4505/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004506 * "getchar()" function
4507 */
4508 static void
4509f_getchar(typval_T *argvars, typval_T *rettv)
4510{
4511 varnumber_T n;
4512 int error = FALSE;
4513
Bram Moolenaar84d93902018-09-11 20:10:20 +02004514#ifdef MESSAGE_QUEUE
4515 // vpeekc() used to check for messages, but that caused problems, invoking
4516 // a callback where it was not expected. Some plugins use getchar(1) in a
4517 // loop to await a message, therefore make sure we check for messages here.
4518 parse_queued_messages();
4519#endif
4520
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004521 /* Position the cursor. Needed after a message that ends in a space. */
4522 windgoto(msg_row, msg_col);
4523
4524 ++no_mapping;
4525 ++allow_keys;
4526 for (;;)
4527 {
4528 if (argvars[0].v_type == VAR_UNKNOWN)
4529 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004530 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004531 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004532 /* getchar(1): only check if char avail */
4533 n = vpeekc_any();
4534 else if (error || vpeekc_any() == NUL)
4535 /* illegal argument or getchar(0) and no char avail: return zero */
4536 n = 0;
4537 else
4538 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004539 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004540
4541 if (n == K_IGNORE)
4542 continue;
4543 break;
4544 }
4545 --no_mapping;
4546 --allow_keys;
4547
4548 set_vim_var_nr(VV_MOUSE_WIN, 0);
4549 set_vim_var_nr(VV_MOUSE_WINID, 0);
4550 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4551 set_vim_var_nr(VV_MOUSE_COL, 0);
4552
4553 rettv->vval.v_number = n;
4554 if (IS_SPECIAL(n) || mod_mask != 0)
4555 {
4556 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4557 int i = 0;
4558
4559 /* Turn a special key into three bytes, plus modifier. */
4560 if (mod_mask != 0)
4561 {
4562 temp[i++] = K_SPECIAL;
4563 temp[i++] = KS_MODIFIER;
4564 temp[i++] = mod_mask;
4565 }
4566 if (IS_SPECIAL(n))
4567 {
4568 temp[i++] = K_SPECIAL;
4569 temp[i++] = K_SECOND(n);
4570 temp[i++] = K_THIRD(n);
4571 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004572 else if (has_mbyte)
4573 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004574 else
4575 temp[i++] = n;
4576 temp[i++] = NUL;
4577 rettv->v_type = VAR_STRING;
4578 rettv->vval.v_string = vim_strsave(temp);
4579
4580#ifdef FEAT_MOUSE
4581 if (is_mouse_key(n))
4582 {
4583 int row = mouse_row;
4584 int col = mouse_col;
4585 win_T *win;
4586 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004587 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004588 int winnr = 1;
4589
4590 if (row >= 0 && col >= 0)
4591 {
4592 /* Find the window at the mouse coordinates and compute the
4593 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004594 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004595 if (win == NULL)
4596 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004597 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004598# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004599 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004600 winnr = 0;
4601 else
4602# endif
4603 for (wp = firstwin; wp != win && wp != NULL;
4604 wp = wp->w_next)
4605 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004606 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4607 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4608 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4609 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4610 }
4611 }
4612#endif
4613 }
4614}
4615
4616/*
4617 * "getcharmod()" function
4618 */
4619 static void
4620f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4621{
4622 rettv->vval.v_number = mod_mask;
4623}
4624
4625/*
4626 * "getcharsearch()" function
4627 */
4628 static void
4629f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4630{
4631 if (rettv_dict_alloc(rettv) != FAIL)
4632 {
4633 dict_T *dict = rettv->vval.v_dict;
4634
Bram Moolenaare0be1672018-07-08 16:50:37 +02004635 dict_add_string(dict, "char", last_csearch());
4636 dict_add_number(dict, "forward", last_csearch_forward());
4637 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004638 }
4639}
4640
4641/*
4642 * "getcmdline()" function
4643 */
4644 static void
4645f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4646{
4647 rettv->v_type = VAR_STRING;
4648 rettv->vval.v_string = get_cmdline_str();
4649}
4650
4651/*
4652 * "getcmdpos()" function
4653 */
4654 static void
4655f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4656{
4657 rettv->vval.v_number = get_cmdline_pos() + 1;
4658}
4659
4660/*
4661 * "getcmdtype()" function
4662 */
4663 static void
4664f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4665{
4666 rettv->v_type = VAR_STRING;
4667 rettv->vval.v_string = alloc(2);
4668 if (rettv->vval.v_string != NULL)
4669 {
4670 rettv->vval.v_string[0] = get_cmdline_type();
4671 rettv->vval.v_string[1] = NUL;
4672 }
4673}
4674
4675/*
4676 * "getcmdwintype()" function
4677 */
4678 static void
4679f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4680{
4681 rettv->v_type = VAR_STRING;
4682 rettv->vval.v_string = NULL;
4683#ifdef FEAT_CMDWIN
4684 rettv->vval.v_string = alloc(2);
4685 if (rettv->vval.v_string != NULL)
4686 {
4687 rettv->vval.v_string[0] = cmdwin_type;
4688 rettv->vval.v_string[1] = NUL;
4689 }
4690#endif
4691}
4692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693/*
4694 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004695 *
4696 * Return the current working directory of a window in a tab page.
4697 * First optional argument 'winnr' is the window number or -1 and the second
4698 * optional argument 'tabnr' is the tab page number.
4699 *
4700 * If no arguments are supplied, then return the directory of the current
4701 * window.
4702 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4703 * the specified window.
4704 * If 'winnr' is 0 then return the directory of the current window.
4705 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4706 * directory of the specified tab page. Otherwise return the directory of the
4707 * specified window in the specified tab page.
4708 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004709 */
4710 static void
4711f_getcwd(typval_T *argvars, typval_T *rettv)
4712{
4713 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004714 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004715 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004716 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717
4718 rettv->v_type = VAR_STRING;
4719 rettv->vval.v_string = NULL;
4720
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004721 if (argvars[0].v_type == VAR_NUMBER
4722 && argvars[0].vval.v_number == -1
4723 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004724 global = TRUE;
4725 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004726 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004727
4728 if (wp != NULL && wp->w_localdir != NULL)
4729 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004730 else if (tp != NULL && tp->tp_localdir != NULL)
4731 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4732 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004734 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735 rettv->vval.v_string = vim_strsave(globaldir);
4736 else
4737 {
4738 cwd = alloc(MAXPATHL);
4739 if (cwd != NULL)
4740 {
4741 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4742 rettv->vval.v_string = vim_strsave(cwd);
4743 vim_free(cwd);
4744 }
4745 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004747#ifdef BACKSLASH_IN_FILENAME
4748 if (rettv->vval.v_string != NULL)
4749 slash_adjust(rettv->vval.v_string);
4750#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004751}
4752
4753/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004754 * "getenv()" function
4755 */
4756 static void
4757f_getenv(typval_T *argvars, typval_T *rettv)
4758{
4759 int mustfree = FALSE;
4760 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4761
4762 if (p == NULL)
4763 {
4764 rettv->v_type = VAR_SPECIAL;
4765 rettv->vval.v_number = VVAL_NULL;
4766 return;
4767 }
4768 if (!mustfree)
4769 p = vim_strsave(p);
4770 rettv->vval.v_string = p;
4771 rettv->v_type = VAR_STRING;
4772}
4773
4774/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004775 * "getfontname()" function
4776 */
4777 static void
4778f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4779{
4780 rettv->v_type = VAR_STRING;
4781 rettv->vval.v_string = NULL;
4782#ifdef FEAT_GUI
4783 if (gui.in_use)
4784 {
4785 GuiFont font;
4786 char_u *name = NULL;
4787
4788 if (argvars[0].v_type == VAR_UNKNOWN)
4789 {
4790 /* Get the "Normal" font. Either the name saved by
4791 * hl_set_font_name() or from the font ID. */
4792 font = gui.norm_font;
4793 name = hl_get_font_name();
4794 }
4795 else
4796 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004797 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004798 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4799 return;
4800 font = gui_mch_get_font(name, FALSE);
4801 if (font == NOFONT)
4802 return; /* Invalid font name, return empty string. */
4803 }
4804 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4805 if (argvars[0].v_type != VAR_UNKNOWN)
4806 gui_mch_free_font(font);
4807 }
4808#endif
4809}
4810
4811/*
4812 * "getfperm({fname})" function
4813 */
4814 static void
4815f_getfperm(typval_T *argvars, typval_T *rettv)
4816{
4817 char_u *fname;
4818 stat_T st;
4819 char_u *perm = NULL;
4820 char_u flags[] = "rwx";
4821 int i;
4822
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004823 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004824
4825 rettv->v_type = VAR_STRING;
4826 if (mch_stat((char *)fname, &st) >= 0)
4827 {
4828 perm = vim_strsave((char_u *)"---------");
4829 if (perm != NULL)
4830 {
4831 for (i = 0; i < 9; i++)
4832 {
4833 if (st.st_mode & (1 << (8 - i)))
4834 perm[i] = flags[i % 3];
4835 }
4836 }
4837 }
4838 rettv->vval.v_string = perm;
4839}
4840
4841/*
4842 * "getfsize({fname})" function
4843 */
4844 static void
4845f_getfsize(typval_T *argvars, typval_T *rettv)
4846{
4847 char_u *fname;
4848 stat_T st;
4849
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004850 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004851
4852 rettv->v_type = VAR_NUMBER;
4853
4854 if (mch_stat((char *)fname, &st) >= 0)
4855 {
4856 if (mch_isdir(fname))
4857 rettv->vval.v_number = 0;
4858 else
4859 {
4860 rettv->vval.v_number = (varnumber_T)st.st_size;
4861
4862 /* non-perfect check for overflow */
4863 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4864 rettv->vval.v_number = -2;
4865 }
4866 }
4867 else
4868 rettv->vval.v_number = -1;
4869}
4870
4871/*
4872 * "getftime({fname})" function
4873 */
4874 static void
4875f_getftime(typval_T *argvars, typval_T *rettv)
4876{
4877 char_u *fname;
4878 stat_T st;
4879
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004880 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004881
4882 if (mch_stat((char *)fname, &st) >= 0)
4883 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4884 else
4885 rettv->vval.v_number = -1;
4886}
4887
4888/*
4889 * "getftype({fname})" function
4890 */
4891 static void
4892f_getftype(typval_T *argvars, typval_T *rettv)
4893{
4894 char_u *fname;
4895 stat_T st;
4896 char_u *type = NULL;
4897 char *t;
4898
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004899 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004900
4901 rettv->v_type = VAR_STRING;
4902 if (mch_lstat((char *)fname, &st) >= 0)
4903 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004904 if (S_ISREG(st.st_mode))
4905 t = "file";
4906 else if (S_ISDIR(st.st_mode))
4907 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908 else if (S_ISLNK(st.st_mode))
4909 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 else if (S_ISBLK(st.st_mode))
4911 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004912 else if (S_ISCHR(st.st_mode))
4913 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004914 else if (S_ISFIFO(st.st_mode))
4915 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004916 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02004917 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004918 else
4919 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004920 type = vim_strsave((char_u *)t);
4921 }
4922 rettv->vval.v_string = type;
4923}
4924
4925/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004926 * "getjumplist()" function
4927 */
4928 static void
4929f_getjumplist(typval_T *argvars, typval_T *rettv)
4930{
4931#ifdef FEAT_JUMPLIST
4932 win_T *wp;
4933 int i;
4934 list_T *l;
4935 dict_T *d;
4936#endif
4937
4938 if (rettv_list_alloc(rettv) != OK)
4939 return;
4940
4941#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004942 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004943 if (wp == NULL)
4944 return;
4945
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01004946 cleanup_jumplist(wp, TRUE);
4947
Bram Moolenaar4f505882018-02-10 21:06:32 +01004948 l = list_alloc();
4949 if (l == NULL)
4950 return;
4951
4952 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4953 return;
4954 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4955
4956 for (i = 0; i < wp->w_jumplistlen; ++i)
4957 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004958 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4959 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004960 if ((d = dict_alloc()) == NULL)
4961 return;
4962 if (list_append_dict(l, d) == FAIL)
4963 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004964 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4965 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004966 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004967 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004968 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02004969 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004970 }
4971#endif
4972}
4973
4974/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004975 * "getline(lnum, [end])" function
4976 */
4977 static void
4978f_getline(typval_T *argvars, typval_T *rettv)
4979{
4980 linenr_T lnum;
4981 linenr_T end;
4982 int retlist;
4983
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004984 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004985 if (argvars[1].v_type == VAR_UNKNOWN)
4986 {
4987 end = 0;
4988 retlist = FALSE;
4989 }
4990 else
4991 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004992 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004993 retlist = TRUE;
4994 }
4995
4996 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4997}
4998
Bram Moolenaar4ae20952016-08-13 15:29:14 +02004999#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005000 static void
5001get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5002{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005003 if (what_arg->v_type == VAR_UNKNOWN)
5004 {
5005 if (rettv_list_alloc(rettv) == OK)
5006 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005007 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005008 }
5009 else
5010 {
5011 if (rettv_dict_alloc(rettv) == OK)
5012 if (is_qf || (wp != NULL))
5013 {
5014 if (what_arg->v_type == VAR_DICT)
5015 {
5016 dict_T *d = what_arg->vval.v_dict;
5017
5018 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005019 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005020 }
5021 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005022 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005023 }
5024 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005025}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005026#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005027
5028/*
5029 * "getloclist()" function
5030 */
5031 static void
5032f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5033{
5034#ifdef FEAT_QUICKFIX
5035 win_T *wp;
5036
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005037 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005038 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5039#endif
5040}
5041
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005043 * "getpid()" function
5044 */
5045 static void
5046f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5047{
5048 rettv->vval.v_number = mch_get_pid();
5049}
5050
5051 static void
5052getpos_both(
5053 typval_T *argvars,
5054 typval_T *rettv,
5055 int getcurpos)
5056{
5057 pos_T *fp;
5058 list_T *l;
5059 int fnum = -1;
5060
5061 if (rettv_list_alloc(rettv) == OK)
5062 {
5063 l = rettv->vval.v_list;
5064 if (getcurpos)
5065 fp = &curwin->w_cursor;
5066 else
5067 fp = var2fpos(&argvars[0], TRUE, &fnum);
5068 if (fnum != -1)
5069 list_append_number(l, (varnumber_T)fnum);
5070 else
5071 list_append_number(l, (varnumber_T)0);
5072 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5073 : (varnumber_T)0);
5074 list_append_number(l, (fp != NULL)
5075 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5076 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005077 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005078 (varnumber_T)0);
5079 if (getcurpos)
5080 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005081 int save_set_curswant = curwin->w_set_curswant;
5082 colnr_T save_curswant = curwin->w_curswant;
5083 colnr_T save_virtcol = curwin->w_virtcol;
5084
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005085 update_curswant();
5086 list_append_number(l, curwin->w_curswant == MAXCOL ?
5087 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005088
5089 // Do not change "curswant", as it is unexpected that a get
5090 // function has a side effect.
5091 if (save_set_curswant)
5092 {
5093 curwin->w_set_curswant = save_set_curswant;
5094 curwin->w_curswant = save_curswant;
5095 curwin->w_virtcol = save_virtcol;
5096 curwin->w_valid &= ~VALID_VIRTCOL;
5097 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005098 }
5099 }
5100 else
5101 rettv->vval.v_number = FALSE;
5102}
5103
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104/*
5105 * "getcurpos()" function
5106 */
5107 static void
5108f_getcurpos(typval_T *argvars, typval_T *rettv)
5109{
5110 getpos_both(argvars, rettv, TRUE);
5111}
5112
5113/*
5114 * "getpos(string)" function
5115 */
5116 static void
5117f_getpos(typval_T *argvars, typval_T *rettv)
5118{
5119 getpos_both(argvars, rettv, FALSE);
5120}
5121
5122/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005123 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005124 */
5125 static void
5126f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5127{
5128#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005129 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005130#endif
5131}
5132
5133/*
5134 * "getreg()" function
5135 */
5136 static void
5137f_getreg(typval_T *argvars, typval_T *rettv)
5138{
5139 char_u *strregname;
5140 int regname;
5141 int arg2 = FALSE;
5142 int return_list = FALSE;
5143 int error = FALSE;
5144
5145 if (argvars[0].v_type != VAR_UNKNOWN)
5146 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005147 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005148 error = strregname == NULL;
5149 if (argvars[1].v_type != VAR_UNKNOWN)
5150 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005151 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005152 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005153 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005154 }
5155 }
5156 else
5157 strregname = get_vim_var_str(VV_REG);
5158
5159 if (error)
5160 return;
5161
5162 regname = (strregname == NULL ? '"' : *strregname);
5163 if (regname == 0)
5164 regname = '"';
5165
5166 if (return_list)
5167 {
5168 rettv->v_type = VAR_LIST;
5169 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5170 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5171 if (rettv->vval.v_list == NULL)
5172 (void)rettv_list_alloc(rettv);
5173 else
5174 ++rettv->vval.v_list->lv_refcount;
5175 }
5176 else
5177 {
5178 rettv->v_type = VAR_STRING;
5179 rettv->vval.v_string = get_reg_contents(regname,
5180 arg2 ? GREG_EXPR_SRC : 0);
5181 }
5182}
5183
5184/*
5185 * "getregtype()" function
5186 */
5187 static void
5188f_getregtype(typval_T *argvars, typval_T *rettv)
5189{
5190 char_u *strregname;
5191 int regname;
5192 char_u buf[NUMBUFLEN + 2];
5193 long reglen = 0;
5194
5195 if (argvars[0].v_type != VAR_UNKNOWN)
5196 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005197 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005198 if (strregname == NULL) /* type error; errmsg already given */
5199 {
5200 rettv->v_type = VAR_STRING;
5201 rettv->vval.v_string = NULL;
5202 return;
5203 }
5204 }
5205 else
5206 /* Default to v:register */
5207 strregname = get_vim_var_str(VV_REG);
5208
5209 regname = (strregname == NULL ? '"' : *strregname);
5210 if (regname == 0)
5211 regname = '"';
5212
5213 buf[0] = NUL;
5214 buf[1] = NUL;
5215 switch (get_reg_type(regname, &reglen))
5216 {
5217 case MLINE: buf[0] = 'V'; break;
5218 case MCHAR: buf[0] = 'v'; break;
5219 case MBLOCK:
5220 buf[0] = Ctrl_V;
5221 sprintf((char *)buf + 1, "%ld", reglen + 1);
5222 break;
5223 }
5224 rettv->v_type = VAR_STRING;
5225 rettv->vval.v_string = vim_strsave(buf);
5226}
5227
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005228/*
5229 * Returns information (variables, options, etc.) about a tab page
5230 * as a dictionary.
5231 */
5232 static dict_T *
5233get_tabpage_info(tabpage_T *tp, int tp_idx)
5234{
5235 win_T *wp;
5236 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005237 list_T *l;
5238
5239 dict = dict_alloc();
5240 if (dict == NULL)
5241 return NULL;
5242
Bram Moolenaare0be1672018-07-08 16:50:37 +02005243 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005244
5245 l = list_alloc();
5246 if (l != NULL)
5247 {
5248 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005249 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005250 list_append_number(l, (varnumber_T)wp->w_id);
5251 dict_add_list(dict, "windows", l);
5252 }
5253
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005254 /* Make a reference to tabpage variables */
5255 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005256
5257 return dict;
5258}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005259
5260/*
5261 * "gettabinfo()" function
5262 */
5263 static void
5264f_gettabinfo(typval_T *argvars, typval_T *rettv)
5265{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005266 tabpage_T *tp, *tparg = NULL;
5267 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005268 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005269
5270 if (rettv_list_alloc(rettv) != OK)
5271 return;
5272
5273 if (argvars[0].v_type != VAR_UNKNOWN)
5274 {
5275 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005276 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005277 if (tparg == NULL)
5278 return;
5279 }
5280
5281 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005282 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005283 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005284 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005285 if (tparg != NULL && tp != tparg)
5286 continue;
5287 d = get_tabpage_info(tp, tpnr);
5288 if (d != NULL)
5289 list_append_dict(rettv->vval.v_list, d);
5290 if (tparg != NULL)
5291 return;
5292 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005293}
5294
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005295/*
5296 * "gettabvar()" function
5297 */
5298 static void
5299f_gettabvar(typval_T *argvars, typval_T *rettv)
5300{
5301 win_T *oldcurwin;
5302 tabpage_T *tp, *oldtabpage;
5303 dictitem_T *v;
5304 char_u *varname;
5305 int done = FALSE;
5306
5307 rettv->v_type = VAR_STRING;
5308 rettv->vval.v_string = NULL;
5309
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005310 varname = tv_get_string_chk(&argvars[1]);
5311 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005312 if (tp != NULL && varname != NULL)
5313 {
5314 /* Set tp to be our tabpage, temporarily. Also set the window to the
5315 * first window in the tabpage, otherwise the window is not valid. */
5316 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005317 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5318 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005319 {
5320 /* look up the variable */
5321 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5322 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5323 if (v != NULL)
5324 {
5325 copy_tv(&v->di_tv, rettv);
5326 done = TRUE;
5327 }
5328 }
5329
5330 /* restore previous notion of curwin */
5331 restore_win(oldcurwin, oldtabpage, TRUE);
5332 }
5333
5334 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5335 copy_tv(&argvars[2], rettv);
5336}
5337
5338/*
5339 * "gettabwinvar()" function
5340 */
5341 static void
5342f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5343{
5344 getwinvar(argvars, rettv, 1);
5345}
5346
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005347/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005348 * "gettagstack()" function
5349 */
5350 static void
5351f_gettagstack(typval_T *argvars, typval_T *rettv)
5352{
5353 win_T *wp = curwin; // default is current window
5354
5355 if (rettv_dict_alloc(rettv) != OK)
5356 return;
5357
5358 if (argvars[0].v_type != VAR_UNKNOWN)
5359 {
5360 wp = find_win_by_nr_or_id(&argvars[0]);
5361 if (wp == NULL)
5362 return;
5363 }
5364
5365 get_tagstack(wp, rettv->vval.v_dict);
5366}
5367
5368/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005369 * Returns information about a window as a dictionary.
5370 */
5371 static dict_T *
5372get_win_info(win_T *wp, short tpnr, short winnr)
5373{
5374 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005375
5376 dict = dict_alloc();
5377 if (dict == NULL)
5378 return NULL;
5379
Bram Moolenaare0be1672018-07-08 16:50:37 +02005380 dict_add_number(dict, "tabnr", tpnr);
5381 dict_add_number(dict, "winnr", winnr);
5382 dict_add_number(dict, "winid", wp->w_id);
5383 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005384 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005385 dict_add_number(dict, "topline", wp->w_topline);
5386 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005387#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005388 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005389#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005390 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005391 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005392 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005393
Bram Moolenaar69905d12017-08-13 18:14:47 +02005394#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005395 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005396#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005397#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005398 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5399 dict_add_number(dict, "loclist",
5400 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005401#endif
5402
Bram Moolenaar30567352016-08-27 21:25:44 +02005403 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005404 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005405
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005406 return dict;
5407}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005408
5409/*
5410 * "getwininfo()" function
5411 */
5412 static void
5413f_getwininfo(typval_T *argvars, typval_T *rettv)
5414{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005415 tabpage_T *tp;
5416 win_T *wp = NULL, *wparg = NULL;
5417 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005418 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005419
5420 if (rettv_list_alloc(rettv) != OK)
5421 return;
5422
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005423 if (argvars[0].v_type != VAR_UNKNOWN)
5424 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005425 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005426 if (wparg == NULL)
5427 return;
5428 }
5429
5430 /* Collect information about either all the windows across all the tab
5431 * pages or one particular window.
5432 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005433 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005434 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005435 tabnr++;
5436 winnr = 0;
5437 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005438 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005439 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005440 if (wparg != NULL && wp != wparg)
5441 continue;
5442 d = get_win_info(wp, tabnr, winnr);
5443 if (d != NULL)
5444 list_append_dict(rettv->vval.v_list, d);
5445 if (wparg != NULL)
5446 /* found information about a specific window */
5447 return;
5448 }
5449 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005450}
5451
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005453 * "win_execute()" function
5454 */
5455 static void
5456f_win_execute(typval_T *argvars, typval_T *rettv)
5457{
5458 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005459 tabpage_T *tp;
5460 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005461 win_T *save_curwin;
5462 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005463
Bram Moolenaar820680b2019-08-09 14:56:22 +02005464 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005465 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005466 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005467 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005468 check_cursor();
5469 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005470 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005471 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005472 }
5473}
5474
5475/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005476 * "win_findbuf()" function
5477 */
5478 static void
5479f_win_findbuf(typval_T *argvars, typval_T *rettv)
5480{
5481 if (rettv_list_alloc(rettv) != FAIL)
5482 win_findbuf(argvars, rettv->vval.v_list);
5483}
5484
5485/*
5486 * "win_getid()" function
5487 */
5488 static void
5489f_win_getid(typval_T *argvars, typval_T *rettv)
5490{
5491 rettv->vval.v_number = win_getid(argvars);
5492}
5493
5494/*
5495 * "win_gotoid()" function
5496 */
5497 static void
5498f_win_gotoid(typval_T *argvars, typval_T *rettv)
5499{
5500 rettv->vval.v_number = win_gotoid(argvars);
5501}
5502
5503/*
5504 * "win_id2tabwin()" function
5505 */
5506 static void
5507f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5508{
5509 if (rettv_list_alloc(rettv) != FAIL)
5510 win_id2tabwin(argvars, rettv->vval.v_list);
5511}
5512
5513/*
5514 * "win_id2win()" function
5515 */
5516 static void
5517f_win_id2win(typval_T *argvars, typval_T *rettv)
5518{
5519 rettv->vval.v_number = win_id2win(argvars);
5520}
5521
5522/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005523 * "win_screenpos()" function
5524 */
5525 static void
5526f_win_screenpos(typval_T *argvars, typval_T *rettv)
5527{
5528 win_T *wp;
5529
5530 if (rettv_list_alloc(rettv) == FAIL)
5531 return;
5532
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005533 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005534 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5535 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5536}
5537
5538/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005539 * "getwinpos({timeout})" function
5540 */
5541 static void
5542f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5543{
5544 int x = -1;
5545 int y = -1;
5546
5547 if (rettv_list_alloc(rettv) == FAIL)
5548 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005549#if defined(FEAT_GUI) \
5550 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5551 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005552 {
5553 varnumber_T timeout = 100;
5554
5555 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005556 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005557
5558 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005559 }
5560#endif
5561 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5562 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5563}
5564
5565
5566/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005567 * "getwinposx()" function
5568 */
5569 static void
5570f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5571{
5572 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005573#if defined(FEAT_GUI) \
5574 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5575 || defined(MSWIN)
5576
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005577 {
5578 int x, y;
5579
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005580 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005581 rettv->vval.v_number = x;
5582 }
5583#endif
5584}
5585
5586/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005587 * "getwinposy()" function
5588 */
5589 static void
5590f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5591{
5592 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005593#if defined(FEAT_GUI) \
5594 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5595 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596 {
5597 int x, y;
5598
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005599 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005600 rettv->vval.v_number = y;
5601 }
5602#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005603}
5604
5605/*
5606 * "getwinvar()" function
5607 */
5608 static void
5609f_getwinvar(typval_T *argvars, typval_T *rettv)
5610{
5611 getwinvar(argvars, rettv, 0);
5612}
5613
5614/*
5615 * "glob()" function
5616 */
5617 static void
5618f_glob(typval_T *argvars, typval_T *rettv)
5619{
5620 int options = WILD_SILENT|WILD_USE_NL;
5621 expand_T xpc;
5622 int error = FALSE;
5623
5624 /* When the optional second argument is non-zero, don't remove matches
5625 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5626 rettv->v_type = VAR_STRING;
5627 if (argvars[1].v_type != VAR_UNKNOWN)
5628 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005629 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630 options |= WILD_KEEP_ALL;
5631 if (argvars[2].v_type != VAR_UNKNOWN)
5632 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005633 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005634 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005635 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005636 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005637 options |= WILD_ALLLINKS;
5638 }
5639 }
5640 if (!error)
5641 {
5642 ExpandInit(&xpc);
5643 xpc.xp_context = EXPAND_FILES;
5644 if (p_wic)
5645 options += WILD_ICASE;
5646 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005647 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648 NULL, options, WILD_ALL);
5649 else if (rettv_list_alloc(rettv) != FAIL)
5650 {
5651 int i;
5652
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005653 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005654 NULL, options, WILD_ALL_KEEP);
5655 for (i = 0; i < xpc.xp_numfiles; i++)
5656 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5657
5658 ExpandCleanup(&xpc);
5659 }
5660 }
5661 else
5662 rettv->vval.v_string = NULL;
5663}
5664
5665/*
5666 * "globpath()" function
5667 */
5668 static void
5669f_globpath(typval_T *argvars, typval_T *rettv)
5670{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005671 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005672 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005673 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005674 int error = FALSE;
5675 garray_T ga;
5676 int i;
5677
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005678 // When the optional second argument is non-zero, don't remove matches
5679 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005680 rettv->v_type = VAR_STRING;
5681 if (argvars[2].v_type != VAR_UNKNOWN)
5682 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005683 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005684 flags |= WILD_KEEP_ALL;
5685 if (argvars[3].v_type != VAR_UNKNOWN)
5686 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005687 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005688 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005689 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005690 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691 flags |= WILD_ALLLINKS;
5692 }
5693 }
5694 if (file != NULL && !error)
5695 {
5696 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005697 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005698 if (rettv->v_type == VAR_STRING)
5699 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5700 else if (rettv_list_alloc(rettv) != FAIL)
5701 for (i = 0; i < ga.ga_len; ++i)
5702 list_append_string(rettv->vval.v_list,
5703 ((char_u **)(ga.ga_data))[i], -1);
5704 ga_clear_strings(&ga);
5705 }
5706 else
5707 rettv->vval.v_string = NULL;
5708}
5709
5710/*
5711 * "glob2regpat()" function
5712 */
5713 static void
5714f_glob2regpat(typval_T *argvars, typval_T *rettv)
5715{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005716 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005717
5718 rettv->v_type = VAR_STRING;
5719 rettv->vval.v_string = (pat == NULL)
5720 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5721}
5722
5723/* for VIM_VERSION_ defines */
5724#include "version.h"
5725
5726/*
5727 * "has()" function
5728 */
5729 static void
5730f_has(typval_T *argvars, typval_T *rettv)
5731{
5732 int i;
5733 char_u *name;
5734 int n = FALSE;
5735 static char *(has_list[]) =
5736 {
5737#ifdef AMIGA
5738 "amiga",
5739# ifdef FEAT_ARP
5740 "arp",
5741# endif
5742#endif
5743#ifdef __BEOS__
5744 "beos",
5745#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005746#if defined(BSD) && !defined(MACOS_X)
5747 "bsd",
5748#endif
5749#ifdef hpux
5750 "hpux",
5751#endif
5752#ifdef __linux__
5753 "linux",
5754#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005755#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005756 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5757 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005758# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005759 "macunix", /* Mac OS X, with the darwin feature */
5760 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005761# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005762#endif
5763#ifdef __QNX__
5764 "qnx",
5765#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005766#ifdef SUN_SYSTEM
5767 "sun",
5768#else
5769 "moon",
5770#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005771#ifdef UNIX
5772 "unix",
5773#endif
5774#ifdef VMS
5775 "vms",
5776#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005777#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005778 "win32",
5779#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005780#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005781 "win32unix",
5782#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005783#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005784 "win64",
5785#endif
5786#ifdef EBCDIC
5787 "ebcdic",
5788#endif
5789#ifndef CASE_INSENSITIVE_FILENAME
5790 "fname_case",
5791#endif
5792#ifdef HAVE_ACL
5793 "acl",
5794#endif
5795#ifdef FEAT_ARABIC
5796 "arabic",
5797#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005798 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005799#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005800 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005801#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005802#ifdef FEAT_AUTOSERVERNAME
5803 "autoservername",
5804#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005805#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005806 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01005807# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808 "balloon_multiline",
5809# endif
5810#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005811#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005812 "balloon_eval_term",
5813#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005814#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5815 "builtin_terms",
5816# ifdef ALL_BUILTIN_TCAPS
5817 "all_builtin_terms",
5818# endif
5819#endif
5820#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01005821 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005822 || defined(FEAT_GUI_MOTIF))
5823 "browsefilter",
5824#endif
5825#ifdef FEAT_BYTEOFF
5826 "byte_offset",
5827#endif
5828#ifdef FEAT_JOB_CHANNEL
5829 "channel",
5830#endif
5831#ifdef FEAT_CINDENT
5832 "cindent",
5833#endif
5834#ifdef FEAT_CLIENTSERVER
5835 "clientserver",
5836#endif
5837#ifdef FEAT_CLIPBOARD
5838 "clipboard",
5839#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005840 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005841 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005842#ifdef FEAT_COMMENTS
5843 "comments",
5844#endif
5845#ifdef FEAT_CONCEAL
5846 "conceal",
5847#endif
5848#ifdef FEAT_CRYPT
5849 "cryptv",
5850 "crypt-blowfish",
5851 "crypt-blowfish2",
5852#endif
5853#ifdef FEAT_CSCOPE
5854 "cscope",
5855#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005856 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005857#ifdef CURSOR_SHAPE
5858 "cursorshape",
5859#endif
5860#ifdef DEBUG
5861 "debug",
5862#endif
5863#ifdef FEAT_CON_DIALOG
5864 "dialog_con",
5865#endif
5866#ifdef FEAT_GUI_DIALOG
5867 "dialog_gui",
5868#endif
5869#ifdef FEAT_DIFF
5870 "diff",
5871#endif
5872#ifdef FEAT_DIGRAPHS
5873 "digraphs",
5874#endif
5875#ifdef FEAT_DIRECTX
5876 "directx",
5877#endif
5878#ifdef FEAT_DND
5879 "dnd",
5880#endif
5881#ifdef FEAT_EMACS_TAGS
5882 "emacs_tags",
5883#endif
5884 "eval", /* always present, of course! */
5885 "ex_extra", /* graduated feature */
5886#ifdef FEAT_SEARCH_EXTRA
5887 "extra_search",
5888#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005889#ifdef FEAT_SEARCHPATH
5890 "file_in_path",
5891#endif
5892#ifdef FEAT_FILTERPIPE
5893 "filterpipe",
5894#endif
5895#ifdef FEAT_FIND_ID
5896 "find_in_path",
5897#endif
5898#ifdef FEAT_FLOAT
5899 "float",
5900#endif
5901#ifdef FEAT_FOLDING
5902 "folding",
5903#endif
5904#ifdef FEAT_FOOTER
5905 "footer",
5906#endif
5907#if !defined(USE_SYSTEM) && defined(UNIX)
5908 "fork",
5909#endif
5910#ifdef FEAT_GETTEXT
5911 "gettext",
5912#endif
5913#ifdef FEAT_GUI
5914 "gui",
5915#endif
5916#ifdef FEAT_GUI_ATHENA
5917# ifdef FEAT_GUI_NEXTAW
5918 "gui_neXtaw",
5919# else
5920 "gui_athena",
5921# endif
5922#endif
5923#ifdef FEAT_GUI_GTK
5924 "gui_gtk",
5925# ifdef USE_GTK3
5926 "gui_gtk3",
5927# else
5928 "gui_gtk2",
5929# endif
5930#endif
5931#ifdef FEAT_GUI_GNOME
5932 "gui_gnome",
5933#endif
5934#ifdef FEAT_GUI_MAC
5935 "gui_mac",
5936#endif
5937#ifdef FEAT_GUI_MOTIF
5938 "gui_motif",
5939#endif
5940#ifdef FEAT_GUI_PHOTON
5941 "gui_photon",
5942#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005943#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005944 "gui_win32",
5945#endif
5946#ifdef FEAT_HANGULIN
5947 "hangul_input",
5948#endif
5949#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5950 "iconv",
5951#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005952 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005953#ifdef FEAT_JOB_CHANNEL
5954 "job",
5955#endif
5956#ifdef FEAT_JUMPLIST
5957 "jumplist",
5958#endif
5959#ifdef FEAT_KEYMAP
5960 "keymap",
5961#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005962 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005963#ifdef FEAT_LANGMAP
5964 "langmap",
5965#endif
5966#ifdef FEAT_LIBCALL
5967 "libcall",
5968#endif
5969#ifdef FEAT_LINEBREAK
5970 "linebreak",
5971#endif
5972#ifdef FEAT_LISP
5973 "lispindent",
5974#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005977#ifdef FEAT_LUA
5978# ifndef DYNAMIC_LUA
5979 "lua",
5980# endif
5981#endif
5982#ifdef FEAT_MENU
5983 "menu",
5984#endif
5985#ifdef FEAT_SESSION
5986 "mksession",
5987#endif
5988#ifdef FEAT_MODIFY_FNAME
5989 "modify_fname",
5990#endif
5991#ifdef FEAT_MOUSE
5992 "mouse",
5993#endif
5994#ifdef FEAT_MOUSESHAPE
5995 "mouseshape",
5996#endif
5997#if defined(UNIX) || defined(VMS)
5998# ifdef FEAT_MOUSE_DEC
5999 "mouse_dec",
6000# endif
6001# ifdef FEAT_MOUSE_GPM
6002 "mouse_gpm",
6003# endif
6004# ifdef FEAT_MOUSE_JSB
6005 "mouse_jsbterm",
6006# endif
6007# ifdef FEAT_MOUSE_NET
6008 "mouse_netterm",
6009# endif
6010# ifdef FEAT_MOUSE_PTERM
6011 "mouse_pterm",
6012# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006013# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006014 "mouse_sgr",
6015# endif
6016# ifdef FEAT_SYSMOUSE
6017 "mouse_sysmouse",
6018# endif
6019# ifdef FEAT_MOUSE_URXVT
6020 "mouse_urxvt",
6021# endif
6022# ifdef FEAT_MOUSE_XTERM
6023 "mouse_xterm",
6024# endif
6025#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006026 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006027#ifdef FEAT_MBYTE_IME
6028 "multi_byte_ime",
6029#endif
6030#ifdef FEAT_MULTI_LANG
6031 "multi_lang",
6032#endif
6033#ifdef FEAT_MZSCHEME
6034#ifndef DYNAMIC_MZSCHEME
6035 "mzscheme",
6036#endif
6037#endif
6038#ifdef FEAT_NUM64
6039 "num64",
6040#endif
6041#ifdef FEAT_OLE
6042 "ole",
6043#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006044#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006045 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006046#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006047#ifdef FEAT_PATH_EXTRA
6048 "path_extra",
6049#endif
6050#ifdef FEAT_PERL
6051#ifndef DYNAMIC_PERL
6052 "perl",
6053#endif
6054#endif
6055#ifdef FEAT_PERSISTENT_UNDO
6056 "persistent_undo",
6057#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006058#if defined(FEAT_PYTHON)
6059 "python_compiled",
6060# if defined(DYNAMIC_PYTHON)
6061 "python_dynamic",
6062# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006064 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006065# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006066#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006067#if defined(FEAT_PYTHON3)
6068 "python3_compiled",
6069# if defined(DYNAMIC_PYTHON3)
6070 "python3_dynamic",
6071# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006072 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006073 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006074# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075#endif
6076#ifdef FEAT_POSTSCRIPT
6077 "postscript",
6078#endif
6079#ifdef FEAT_PRINTER
6080 "printer",
6081#endif
6082#ifdef FEAT_PROFILE
6083 "profile",
6084#endif
6085#ifdef FEAT_RELTIME
6086 "reltime",
6087#endif
6088#ifdef FEAT_QUICKFIX
6089 "quickfix",
6090#endif
6091#ifdef FEAT_RIGHTLEFT
6092 "rightleft",
6093#endif
6094#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6095 "ruby",
6096#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006097 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006098#ifdef FEAT_CMDL_INFO
6099 "showcmd",
6100 "cmdline_info",
6101#endif
6102#ifdef FEAT_SIGNS
6103 "signs",
6104#endif
6105#ifdef FEAT_SMARTINDENT
6106 "smartindent",
6107#endif
6108#ifdef STARTUPTIME
6109 "startuptime",
6110#endif
6111#ifdef FEAT_STL_OPT
6112 "statusline",
6113#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006114#ifdef FEAT_NETBEANS_INTG
6115 "netbeans_intg",
6116#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006117#ifdef FEAT_SOUND
6118 "sound",
6119#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006120#ifdef FEAT_SPELL
6121 "spell",
6122#endif
6123#ifdef FEAT_SYN_HL
6124 "syntax",
6125#endif
6126#if defined(USE_SYSTEM) || !defined(UNIX)
6127 "system",
6128#endif
6129#ifdef FEAT_TAG_BINS
6130 "tag_binary",
6131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006132#ifdef FEAT_TCL
6133# ifndef DYNAMIC_TCL
6134 "tcl",
6135# endif
6136#endif
6137#ifdef FEAT_TERMGUICOLORS
6138 "termguicolors",
6139#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006140#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006141 "terminal",
6142#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143#ifdef TERMINFO
6144 "terminfo",
6145#endif
6146#ifdef FEAT_TERMRESPONSE
6147 "termresponse",
6148#endif
6149#ifdef FEAT_TEXTOBJ
6150 "textobjects",
6151#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006152#ifdef FEAT_TEXT_PROP
6153 "textprop",
6154#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006155#ifdef HAVE_TGETENT
6156 "tgetent",
6157#endif
6158#ifdef FEAT_TIMERS
6159 "timers",
6160#endif
6161#ifdef FEAT_TITLE
6162 "title",
6163#endif
6164#ifdef FEAT_TOOLBAR
6165 "toolbar",
6166#endif
6167#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6168 "unnamedplus",
6169#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006170 "user-commands", /* was accidentally included in 5.4 */
6171 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006172#ifdef FEAT_VARTABS
6173 "vartabs",
6174#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006175 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006176#ifdef FEAT_VIMINFO
6177 "viminfo",
6178#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006179 "vimscript-1",
6180 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006181 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006184 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006186#ifdef FEAT_VTP
6187 "vtp",
6188#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006189#ifdef FEAT_WILDIGN
6190 "wildignore",
6191#endif
6192#ifdef FEAT_WILDMENU
6193 "wildmenu",
6194#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196#ifdef FEAT_WAK
6197 "winaltkeys",
6198#endif
6199#ifdef FEAT_WRITEBACKUP
6200 "writebackup",
6201#endif
6202#ifdef FEAT_XIM
6203 "xim",
6204#endif
6205#ifdef FEAT_XFONTSET
6206 "xfontset",
6207#endif
6208#ifdef FEAT_XPM_W32
6209 "xpm",
6210 "xpm_w32", /* for backward compatibility */
6211#else
6212# if defined(HAVE_XPM)
6213 "xpm",
6214# endif
6215#endif
6216#ifdef USE_XSMP
6217 "xsmp",
6218#endif
6219#ifdef USE_XSMP_INTERACT
6220 "xsmp_interact",
6221#endif
6222#ifdef FEAT_XCLIPBOARD
6223 "xterm_clipboard",
6224#endif
6225#ifdef FEAT_XTERM_SAVE
6226 "xterm_save",
6227#endif
6228#if defined(UNIX) && defined(FEAT_X11)
6229 "X11",
6230#endif
6231 NULL
6232 };
6233
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006234 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006235 for (i = 0; has_list[i] != NULL; ++i)
6236 if (STRICMP(name, has_list[i]) == 0)
6237 {
6238 n = TRUE;
6239 break;
6240 }
6241
6242 if (n == FALSE)
6243 {
6244 if (STRNICMP(name, "patch", 5) == 0)
6245 {
6246 if (name[5] == '-'
6247 && STRLEN(name) >= 11
6248 && vim_isdigit(name[6])
6249 && vim_isdigit(name[8])
6250 && vim_isdigit(name[10]))
6251 {
6252 int major = atoi((char *)name + 6);
6253 int minor = atoi((char *)name + 8);
6254
6255 /* Expect "patch-9.9.01234". */
6256 n = (major < VIM_VERSION_MAJOR
6257 || (major == VIM_VERSION_MAJOR
6258 && (minor < VIM_VERSION_MINOR
6259 || (minor == VIM_VERSION_MINOR
6260 && has_patch(atoi((char *)name + 10))))));
6261 }
6262 else
6263 n = has_patch(atoi((char *)name + 5));
6264 }
6265 else if (STRICMP(name, "vim_starting") == 0)
6266 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006267 else if (STRICMP(name, "ttyin") == 0)
6268 n = mch_input_isatty();
6269 else if (STRICMP(name, "ttyout") == 0)
6270 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006271 else if (STRICMP(name, "multi_byte_encoding") == 0)
6272 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006273#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006274 else if (STRICMP(name, "balloon_multiline") == 0)
6275 n = multiline_balloon_available();
6276#endif
6277#ifdef DYNAMIC_TCL
6278 else if (STRICMP(name, "tcl") == 0)
6279 n = tcl_enabled(FALSE);
6280#endif
6281#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6282 else if (STRICMP(name, "iconv") == 0)
6283 n = iconv_enabled(FALSE);
6284#endif
6285#ifdef DYNAMIC_LUA
6286 else if (STRICMP(name, "lua") == 0)
6287 n = lua_enabled(FALSE);
6288#endif
6289#ifdef DYNAMIC_MZSCHEME
6290 else if (STRICMP(name, "mzscheme") == 0)
6291 n = mzscheme_enabled(FALSE);
6292#endif
6293#ifdef DYNAMIC_RUBY
6294 else if (STRICMP(name, "ruby") == 0)
6295 n = ruby_enabled(FALSE);
6296#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297#ifdef DYNAMIC_PYTHON
6298 else if (STRICMP(name, "python") == 0)
6299 n = python_enabled(FALSE);
6300#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006301#ifdef DYNAMIC_PYTHON3
6302 else if (STRICMP(name, "python3") == 0)
6303 n = python3_enabled(FALSE);
6304#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006305#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6306 else if (STRICMP(name, "pythonx") == 0)
6307 {
6308# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6309 if (p_pyx == 0)
6310 n = python3_enabled(FALSE) || python_enabled(FALSE);
6311 else if (p_pyx == 3)
6312 n = python3_enabled(FALSE);
6313 else if (p_pyx == 2)
6314 n = python_enabled(FALSE);
6315# elif defined(DYNAMIC_PYTHON)
6316 n = python_enabled(FALSE);
6317# elif defined(DYNAMIC_PYTHON3)
6318 n = python3_enabled(FALSE);
6319# endif
6320 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321#endif
6322#ifdef DYNAMIC_PERL
6323 else if (STRICMP(name, "perl") == 0)
6324 n = perl_enabled(FALSE);
6325#endif
6326#ifdef FEAT_GUI
6327 else if (STRICMP(name, "gui_running") == 0)
6328 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006329# ifdef FEAT_BROWSE
6330 else if (STRICMP(name, "browse") == 0)
6331 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6332# endif
6333#endif
6334#ifdef FEAT_SYN_HL
6335 else if (STRICMP(name, "syntax_items") == 0)
6336 n = syntax_present(curwin);
6337#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006338#ifdef FEAT_VTP
6339 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006340 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341#endif
6342#ifdef FEAT_NETBEANS_INTG
6343 else if (STRICMP(name, "netbeans_enabled") == 0)
6344 n = netbeans_active();
6345#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006346#ifdef FEAT_MOUSE_GPM
6347 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6348 n = gpm_enabled();
6349#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006350#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006351 else if (STRICMP(name, "terminal") == 0)
6352 n = terminal_enabled();
6353#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006354#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006355 else if (STRICMP(name, "conpty") == 0)
6356 n = use_conpty();
6357#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006358#ifdef FEAT_CLIPBOARD
6359 else if (STRICMP(name, "clipboard_working") == 0)
6360 n = clip_star.available;
6361#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006362 }
6363
6364 rettv->vval.v_number = n;
6365}
6366
6367/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006368 * "haslocaldir()" function
6369 */
6370 static void
6371f_haslocaldir(typval_T *argvars, typval_T *rettv)
6372{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006373 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006374 win_T *wp = NULL;
6375
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006376 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6377
6378 // Check for window-local and tab-local directories
6379 if (wp != NULL && wp->w_localdir != NULL)
6380 rettv->vval.v_number = 1;
6381 else if (tp != NULL && tp->tp_localdir != NULL)
6382 rettv->vval.v_number = 2;
6383 else
6384 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385}
6386
6387/*
6388 * "hasmapto()" function
6389 */
6390 static void
6391f_hasmapto(typval_T *argvars, typval_T *rettv)
6392{
6393 char_u *name;
6394 char_u *mode;
6395 char_u buf[NUMBUFLEN];
6396 int abbr = FALSE;
6397
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006398 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006399 if (argvars[1].v_type == VAR_UNKNOWN)
6400 mode = (char_u *)"nvo";
6401 else
6402 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006403 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006404 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006405 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406 }
6407
6408 if (map_to_exists(name, mode, abbr))
6409 rettv->vval.v_number = TRUE;
6410 else
6411 rettv->vval.v_number = FALSE;
6412}
6413
6414/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 * "highlightID(name)" function
6416 */
6417 static void
6418f_hlID(typval_T *argvars, typval_T *rettv)
6419{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006420 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421}
6422
6423/*
6424 * "highlight_exists()" function
6425 */
6426 static void
6427f_hlexists(typval_T *argvars, typval_T *rettv)
6428{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006429 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430}
6431
6432/*
6433 * "hostname()" function
6434 */
6435 static void
6436f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6437{
6438 char_u hostname[256];
6439
6440 mch_get_host_name(hostname, 256);
6441 rettv->v_type = VAR_STRING;
6442 rettv->vval.v_string = vim_strsave(hostname);
6443}
6444
6445/*
6446 * iconv() function
6447 */
6448 static void
6449f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6450{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451 char_u buf1[NUMBUFLEN];
6452 char_u buf2[NUMBUFLEN];
6453 char_u *from, *to, *str;
6454 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006455
6456 rettv->v_type = VAR_STRING;
6457 rettv->vval.v_string = NULL;
6458
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006459 str = tv_get_string(&argvars[0]);
6460 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6461 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 vimconv.vc_type = CONV_NONE;
6463 convert_setup(&vimconv, from, to);
6464
6465 /* If the encodings are equal, no conversion needed. */
6466 if (vimconv.vc_type == CONV_NONE)
6467 rettv->vval.v_string = vim_strsave(str);
6468 else
6469 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6470
6471 convert_setup(&vimconv, NULL, NULL);
6472 vim_free(from);
6473 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474}
6475
6476/*
6477 * "indent()" function
6478 */
6479 static void
6480f_indent(typval_T *argvars, typval_T *rettv)
6481{
6482 linenr_T lnum;
6483
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006484 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6486 rettv->vval.v_number = get_indent_lnum(lnum);
6487 else
6488 rettv->vval.v_number = -1;
6489}
6490
6491/*
6492 * "index()" function
6493 */
6494 static void
6495f_index(typval_T *argvars, typval_T *rettv)
6496{
6497 list_T *l;
6498 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006499 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500 long idx = 0;
6501 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006502 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503
6504 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006505 if (argvars[0].v_type == VAR_BLOB)
6506 {
6507 typval_T tv;
6508 int start = 0;
6509
6510 if (argvars[2].v_type != VAR_UNKNOWN)
6511 {
6512 start = tv_get_number_chk(&argvars[2], &error);
6513 if (error)
6514 return;
6515 }
6516 b = argvars[0].vval.v_blob;
6517 if (b == NULL)
6518 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006519 if (start < 0)
6520 {
6521 start = blob_len(b) + start;
6522 if (start < 0)
6523 start = 0;
6524 }
6525
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006526 for (idx = start; idx < blob_len(b); ++idx)
6527 {
6528 tv.v_type = VAR_NUMBER;
6529 tv.vval.v_number = blob_get(b, idx);
6530 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6531 {
6532 rettv->vval.v_number = idx;
6533 return;
6534 }
6535 }
6536 return;
6537 }
6538 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006540 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541 return;
6542 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006543
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006544 l = argvars[0].vval.v_list;
6545 if (l != NULL)
6546 {
6547 item = l->lv_first;
6548 if (argvars[2].v_type != VAR_UNKNOWN)
6549 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 /* Start at specified item. Use the cached index that list_find()
6551 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006552 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006553 idx = l->lv_idx;
6554 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006555 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006556 if (error)
6557 item = NULL;
6558 }
6559
6560 for ( ; item != NULL; item = item->li_next, ++idx)
6561 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6562 {
6563 rettv->vval.v_number = idx;
6564 break;
6565 }
6566 }
6567}
6568
6569static int inputsecret_flag = 0;
6570
6571/*
6572 * "input()" function
6573 * Also handles inputsecret() when inputsecret is set.
6574 */
6575 static void
6576f_input(typval_T *argvars, typval_T *rettv)
6577{
6578 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6579}
6580
6581/*
6582 * "inputdialog()" function
6583 */
6584 static void
6585f_inputdialog(typval_T *argvars, typval_T *rettv)
6586{
6587#if defined(FEAT_GUI_TEXTDIALOG)
6588 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6589 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6590 {
6591 char_u *message;
6592 char_u buf[NUMBUFLEN];
6593 char_u *defstr = (char_u *)"";
6594
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006595 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006596 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006597 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006598 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6599 else
6600 IObuff[0] = NUL;
6601 if (message != NULL && defstr != NULL
6602 && do_dialog(VIM_QUESTION, NULL, message,
6603 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6604 rettv->vval.v_string = vim_strsave(IObuff);
6605 else
6606 {
6607 if (message != NULL && defstr != NULL
6608 && argvars[1].v_type != VAR_UNKNOWN
6609 && argvars[2].v_type != VAR_UNKNOWN)
6610 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006611 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006612 else
6613 rettv->vval.v_string = NULL;
6614 }
6615 rettv->v_type = VAR_STRING;
6616 }
6617 else
6618#endif
6619 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6620}
6621
6622/*
6623 * "inputlist()" function
6624 */
6625 static void
6626f_inputlist(typval_T *argvars, typval_T *rettv)
6627{
6628 listitem_T *li;
6629 int selected;
6630 int mouse_used;
6631
6632#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006633 /* While starting up, there is no place to enter text. When running tests
6634 * with --not-a-term we assume feedkeys() will be used. */
6635 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006636 return;
6637#endif
6638 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6639 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006640 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 return;
6642 }
6643
6644 msg_start();
6645 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6646 lines_left = Rows; /* avoid more prompt */
6647 msg_scroll = TRUE;
6648 msg_clr_eos();
6649
6650 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6651 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006652 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006653 msg_putchar('\n');
6654 }
6655
6656 /* Ask for choice. */
6657 selected = prompt_for_number(&mouse_used);
6658 if (mouse_used)
6659 selected -= lines_left;
6660
6661 rettv->vval.v_number = selected;
6662}
6663
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006664static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6665
6666/*
6667 * "inputrestore()" function
6668 */
6669 static void
6670f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6671{
6672 if (ga_userinput.ga_len > 0)
6673 {
6674 --ga_userinput.ga_len;
6675 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6676 + ga_userinput.ga_len);
6677 /* default return is zero == OK */
6678 }
6679 else if (p_verbose > 1)
6680 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006681 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006682 rettv->vval.v_number = 1; /* Failed */
6683 }
6684}
6685
6686/*
6687 * "inputsave()" function
6688 */
6689 static void
6690f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6691{
6692 /* Add an entry to the stack of typeahead storage. */
6693 if (ga_grow(&ga_userinput, 1) == OK)
6694 {
6695 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6696 + ga_userinput.ga_len);
6697 ++ga_userinput.ga_len;
6698 /* default return is zero == OK */
6699 }
6700 else
6701 rettv->vval.v_number = 1; /* Failed */
6702}
6703
6704/*
6705 * "inputsecret()" function
6706 */
6707 static void
6708f_inputsecret(typval_T *argvars, typval_T *rettv)
6709{
6710 ++cmdline_star;
6711 ++inputsecret_flag;
6712 f_input(argvars, rettv);
6713 --cmdline_star;
6714 --inputsecret_flag;
6715}
6716
6717/*
6718 * "insert()" function
6719 */
6720 static void
6721f_insert(typval_T *argvars, typval_T *rettv)
6722{
6723 long before = 0;
6724 listitem_T *item;
6725 list_T *l;
6726 int error = FALSE;
6727
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006728 if (argvars[0].v_type == VAR_BLOB)
6729 {
6730 int val, len;
6731 char_u *p;
6732
6733 len = blob_len(argvars[0].vval.v_blob);
6734 if (argvars[2].v_type != VAR_UNKNOWN)
6735 {
6736 before = (long)tv_get_number_chk(&argvars[2], &error);
6737 if (error)
6738 return; // type error; errmsg already given
6739 if (before < 0 || before > len)
6740 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006741 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006742 return;
6743 }
6744 }
6745 val = tv_get_number_chk(&argvars[1], &error);
6746 if (error)
6747 return;
6748 if (val < 0 || val > 255)
6749 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006750 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006751 return;
6752 }
6753
6754 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6755 return;
6756 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6757 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6758 *(p + before) = val;
6759 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6760
6761 copy_tv(&argvars[0], rettv);
6762 }
6763 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006764 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006765 else if ((l = argvars[0].vval.v_list) != NULL
6766 && !var_check_lock(l->lv_lock,
6767 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 {
6769 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006770 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006771 if (error)
6772 return; /* type error; errmsg already given */
6773
6774 if (before == l->lv_len)
6775 item = NULL;
6776 else
6777 {
6778 item = list_find(l, before);
6779 if (item == NULL)
6780 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006781 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782 l = NULL;
6783 }
6784 }
6785 if (l != NULL)
6786 {
6787 list_insert_tv(l, &argvars[1], item);
6788 copy_tv(&argvars[0], rettv);
6789 }
6790 }
6791}
6792
6793/*
6794 * "invert(expr)" function
6795 */
6796 static void
6797f_invert(typval_T *argvars, typval_T *rettv)
6798{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006799 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006800}
6801
6802/*
6803 * "isdirectory()" function
6804 */
6805 static void
6806f_isdirectory(typval_T *argvars, typval_T *rettv)
6807{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006808 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006809}
6810
6811/*
6812 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6813 * or it refers to a List or Dictionary that is locked.
6814 */
6815 static int
6816tv_islocked(typval_T *tv)
6817{
6818 return (tv->v_lock & VAR_LOCKED)
6819 || (tv->v_type == VAR_LIST
6820 && tv->vval.v_list != NULL
6821 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6822 || (tv->v_type == VAR_DICT
6823 && tv->vval.v_dict != NULL
6824 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6825}
6826
6827/*
6828 * "islocked()" function
6829 */
6830 static void
6831f_islocked(typval_T *argvars, typval_T *rettv)
6832{
6833 lval_T lv;
6834 char_u *end;
6835 dictitem_T *di;
6836
6837 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006838 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006839 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840 if (end != NULL && lv.ll_name != NULL)
6841 {
6842 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006843 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006844 else
6845 {
6846 if (lv.ll_tv == NULL)
6847 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006848 di = find_var(lv.ll_name, NULL, TRUE);
6849 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006851 /* Consider a variable locked when:
6852 * 1. the variable itself is locked
6853 * 2. the value of the variable is locked.
6854 * 3. the List or Dict value is locked.
6855 */
6856 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6857 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006858 }
6859 }
6860 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006861 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006863 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006864 else if (lv.ll_list != NULL)
6865 /* List item. */
6866 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6867 else
6868 /* Dictionary item. */
6869 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6870 }
6871 }
6872
6873 clear_lval(&lv);
6874}
6875
6876#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6877/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006878 * "isinf()" function
6879 */
6880 static void
6881f_isinf(typval_T *argvars, typval_T *rettv)
6882{
6883 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6884 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6885}
6886
6887/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006888 * "isnan()" function
6889 */
6890 static void
6891f_isnan(typval_T *argvars, typval_T *rettv)
6892{
6893 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6894 && isnan(argvars[0].vval.v_float);
6895}
6896#endif
6897
6898/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006899 * "last_buffer_nr()" function.
6900 */
6901 static void
6902f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6903{
6904 int n = 0;
6905 buf_T *buf;
6906
Bram Moolenaar29323592016-07-24 22:04:11 +02006907 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 if (n < buf->b_fnum)
6909 n = buf->b_fnum;
6910
6911 rettv->vval.v_number = n;
6912}
6913
6914/*
6915 * "len()" function
6916 */
6917 static void
6918f_len(typval_T *argvars, typval_T *rettv)
6919{
6920 switch (argvars[0].v_type)
6921 {
6922 case VAR_STRING:
6923 case VAR_NUMBER:
6924 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006925 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006927 case VAR_BLOB:
6928 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6929 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006930 case VAR_LIST:
6931 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6932 break;
6933 case VAR_DICT:
6934 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6935 break;
6936 case VAR_UNKNOWN:
6937 case VAR_SPECIAL:
6938 case VAR_FLOAT:
6939 case VAR_FUNC:
6940 case VAR_PARTIAL:
6941 case VAR_JOB:
6942 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006943 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006944 break;
6945 }
6946}
6947
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006949libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950{
6951#ifdef FEAT_LIBCALL
6952 char_u *string_in;
6953 char_u **string_result;
6954 int nr_result;
6955#endif
6956
6957 rettv->v_type = type;
6958 if (type != VAR_NUMBER)
6959 rettv->vval.v_string = NULL;
6960
6961 if (check_restricted() || check_secure())
6962 return;
6963
6964#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006965 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6967 {
6968 string_in = NULL;
6969 if (argvars[2].v_type == VAR_STRING)
6970 string_in = argvars[2].vval.v_string;
6971 if (type == VAR_NUMBER)
6972 string_result = NULL;
6973 else
6974 string_result = &rettv->vval.v_string;
6975 if (mch_libcall(argvars[0].vval.v_string,
6976 argvars[1].vval.v_string,
6977 string_in,
6978 argvars[2].vval.v_number,
6979 string_result,
6980 &nr_result) == OK
6981 && type == VAR_NUMBER)
6982 rettv->vval.v_number = nr_result;
6983 }
6984#endif
6985}
6986
6987/*
6988 * "libcall()" function
6989 */
6990 static void
6991f_libcall(typval_T *argvars, typval_T *rettv)
6992{
6993 libcall_common(argvars, rettv, VAR_STRING);
6994}
6995
6996/*
6997 * "libcallnr()" function
6998 */
6999 static void
7000f_libcallnr(typval_T *argvars, typval_T *rettv)
7001{
7002 libcall_common(argvars, rettv, VAR_NUMBER);
7003}
7004
7005/*
7006 * "line(string)" function
7007 */
7008 static void
7009f_line(typval_T *argvars, typval_T *rettv)
7010{
7011 linenr_T lnum = 0;
7012 pos_T *fp;
7013 int fnum;
7014
7015 fp = var2fpos(&argvars[0], TRUE, &fnum);
7016 if (fp != NULL)
7017 lnum = fp->lnum;
7018 rettv->vval.v_number = lnum;
7019}
7020
7021/*
7022 * "line2byte(lnum)" function
7023 */
7024 static void
7025f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7026{
7027#ifndef FEAT_BYTEOFF
7028 rettv->vval.v_number = -1;
7029#else
7030 linenr_T lnum;
7031
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007032 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007033 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7034 rettv->vval.v_number = -1;
7035 else
7036 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7037 if (rettv->vval.v_number >= 0)
7038 ++rettv->vval.v_number;
7039#endif
7040}
7041
7042/*
7043 * "lispindent(lnum)" function
7044 */
7045 static void
7046f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7047{
7048#ifdef FEAT_LISP
7049 pos_T pos;
7050 linenr_T lnum;
7051
7052 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007053 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007054 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7055 {
7056 curwin->w_cursor.lnum = lnum;
7057 rettv->vval.v_number = get_lisp_indent();
7058 curwin->w_cursor = pos;
7059 }
7060 else
7061#endif
7062 rettv->vval.v_number = -1;
7063}
7064
7065/*
7066 * "localtime()" function
7067 */
7068 static void
7069f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7070{
7071 rettv->vval.v_number = (varnumber_T)time(NULL);
7072}
7073
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074#ifdef FEAT_FLOAT
7075/*
7076 * "log()" function
7077 */
7078 static void
7079f_log(typval_T *argvars, typval_T *rettv)
7080{
7081 float_T f = 0.0;
7082
7083 rettv->v_type = VAR_FLOAT;
7084 if (get_float_arg(argvars, &f) == OK)
7085 rettv->vval.v_float = log(f);
7086 else
7087 rettv->vval.v_float = 0.0;
7088}
7089
7090/*
7091 * "log10()" function
7092 */
7093 static void
7094f_log10(typval_T *argvars, typval_T *rettv)
7095{
7096 float_T f = 0.0;
7097
7098 rettv->v_type = VAR_FLOAT;
7099 if (get_float_arg(argvars, &f) == OK)
7100 rettv->vval.v_float = log10(f);
7101 else
7102 rettv->vval.v_float = 0.0;
7103}
7104#endif
7105
7106#ifdef FEAT_LUA
7107/*
7108 * "luaeval()" function
7109 */
7110 static void
7111f_luaeval(typval_T *argvars, typval_T *rettv)
7112{
7113 char_u *str;
7114 char_u buf[NUMBUFLEN];
7115
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007116 if (check_restricted() || check_secure())
7117 return;
7118
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007119 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007120 do_luaeval(str, argvars + 1, rettv);
7121}
7122#endif
7123
7124/*
7125 * "map()" function
7126 */
7127 static void
7128f_map(typval_T *argvars, typval_T *rettv)
7129{
7130 filter_map(argvars, rettv, TRUE);
7131}
7132
7133/*
7134 * "maparg()" function
7135 */
7136 static void
7137f_maparg(typval_T *argvars, typval_T *rettv)
7138{
7139 get_maparg(argvars, rettv, TRUE);
7140}
7141
7142/*
7143 * "mapcheck()" function
7144 */
7145 static void
7146f_mapcheck(typval_T *argvars, typval_T *rettv)
7147{
7148 get_maparg(argvars, rettv, FALSE);
7149}
7150
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007151typedef enum
7152{
7153 MATCH_END, /* matchend() */
7154 MATCH_MATCH, /* match() */
7155 MATCH_STR, /* matchstr() */
7156 MATCH_LIST, /* matchlist() */
7157 MATCH_POS /* matchstrpos() */
7158} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007159
7160 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007161find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007162{
7163 char_u *str = NULL;
7164 long len = 0;
7165 char_u *expr = NULL;
7166 char_u *pat;
7167 regmatch_T regmatch;
7168 char_u patbuf[NUMBUFLEN];
7169 char_u strbuf[NUMBUFLEN];
7170 char_u *save_cpo;
7171 long start = 0;
7172 long nth = 1;
7173 colnr_T startcol = 0;
7174 int match = 0;
7175 list_T *l = NULL;
7176 listitem_T *li = NULL;
7177 long idx = 0;
7178 char_u *tofree = NULL;
7179
7180 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7181 save_cpo = p_cpo;
7182 p_cpo = (char_u *)"";
7183
7184 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007185 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007186 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007187 /* type MATCH_LIST: return empty list when there are no matches.
7188 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007189 if (rettv_list_alloc(rettv) == FAIL)
7190 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007191 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007192 && (list_append_string(rettv->vval.v_list,
7193 (char_u *)"", 0) == FAIL
7194 || list_append_number(rettv->vval.v_list,
7195 (varnumber_T)-1) == FAIL
7196 || list_append_number(rettv->vval.v_list,
7197 (varnumber_T)-1) == FAIL
7198 || list_append_number(rettv->vval.v_list,
7199 (varnumber_T)-1) == FAIL))
7200 {
7201 list_free(rettv->vval.v_list);
7202 rettv->vval.v_list = NULL;
7203 goto theend;
7204 }
7205 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007206 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007207 {
7208 rettv->v_type = VAR_STRING;
7209 rettv->vval.v_string = NULL;
7210 }
7211
7212 if (argvars[0].v_type == VAR_LIST)
7213 {
7214 if ((l = argvars[0].vval.v_list) == NULL)
7215 goto theend;
7216 li = l->lv_first;
7217 }
7218 else
7219 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007220 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007221 len = (long)STRLEN(str);
7222 }
7223
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007224 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007225 if (pat == NULL)
7226 goto theend;
7227
7228 if (argvars[2].v_type != VAR_UNKNOWN)
7229 {
7230 int error = FALSE;
7231
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007232 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 if (error)
7234 goto theend;
7235 if (l != NULL)
7236 {
7237 li = list_find(l, start);
7238 if (li == NULL)
7239 goto theend;
7240 idx = l->lv_idx; /* use the cached index */
7241 }
7242 else
7243 {
7244 if (start < 0)
7245 start = 0;
7246 if (start > len)
7247 goto theend;
7248 /* When "count" argument is there ignore matches before "start",
7249 * otherwise skip part of the string. Differs when pattern is "^"
7250 * or "\<". */
7251 if (argvars[3].v_type != VAR_UNKNOWN)
7252 startcol = start;
7253 else
7254 {
7255 str += start;
7256 len -= start;
7257 }
7258 }
7259
7260 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007261 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007262 if (error)
7263 goto theend;
7264 }
7265
7266 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7267 if (regmatch.regprog != NULL)
7268 {
7269 regmatch.rm_ic = p_ic;
7270
7271 for (;;)
7272 {
7273 if (l != NULL)
7274 {
7275 if (li == NULL)
7276 {
7277 match = FALSE;
7278 break;
7279 }
7280 vim_free(tofree);
7281 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7282 if (str == NULL)
7283 break;
7284 }
7285
7286 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7287
7288 if (match && --nth <= 0)
7289 break;
7290 if (l == NULL && !match)
7291 break;
7292
7293 /* Advance to just after the match. */
7294 if (l != NULL)
7295 {
7296 li = li->li_next;
7297 ++idx;
7298 }
7299 else
7300 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007301 startcol = (colnr_T)(regmatch.startp[0]
7302 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007303 if (startcol > (colnr_T)len
7304 || str + startcol <= regmatch.startp[0])
7305 {
7306 match = FALSE;
7307 break;
7308 }
7309 }
7310 }
7311
7312 if (match)
7313 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007314 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007315 {
7316 listitem_T *li1 = rettv->vval.v_list->lv_first;
7317 listitem_T *li2 = li1->li_next;
7318 listitem_T *li3 = li2->li_next;
7319 listitem_T *li4 = li3->li_next;
7320
7321 vim_free(li1->li_tv.vval.v_string);
7322 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7323 (int)(regmatch.endp[0] - regmatch.startp[0]));
7324 li3->li_tv.vval.v_number =
7325 (varnumber_T)(regmatch.startp[0] - expr);
7326 li4->li_tv.vval.v_number =
7327 (varnumber_T)(regmatch.endp[0] - expr);
7328 if (l != NULL)
7329 li2->li_tv.vval.v_number = (varnumber_T)idx;
7330 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007331 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007332 {
7333 int i;
7334
7335 /* return list with matched string and submatches */
7336 for (i = 0; i < NSUBEXP; ++i)
7337 {
7338 if (regmatch.endp[i] == NULL)
7339 {
7340 if (list_append_string(rettv->vval.v_list,
7341 (char_u *)"", 0) == FAIL)
7342 break;
7343 }
7344 else if (list_append_string(rettv->vval.v_list,
7345 regmatch.startp[i],
7346 (int)(regmatch.endp[i] - regmatch.startp[i]))
7347 == FAIL)
7348 break;
7349 }
7350 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007351 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007352 {
7353 /* return matched string */
7354 if (l != NULL)
7355 copy_tv(&li->li_tv, rettv);
7356 else
7357 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7358 (int)(regmatch.endp[0] - regmatch.startp[0]));
7359 }
7360 else if (l != NULL)
7361 rettv->vval.v_number = idx;
7362 else
7363 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007364 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365 rettv->vval.v_number =
7366 (varnumber_T)(regmatch.startp[0] - str);
7367 else
7368 rettv->vval.v_number =
7369 (varnumber_T)(regmatch.endp[0] - str);
7370 rettv->vval.v_number += (varnumber_T)(str - expr);
7371 }
7372 }
7373 vim_regfree(regmatch.regprog);
7374 }
7375
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007376theend:
7377 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007378 /* matchstrpos() without a list: drop the second item. */
7379 listitem_remove(rettv->vval.v_list,
7380 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007381 vim_free(tofree);
7382 p_cpo = save_cpo;
7383}
7384
7385/*
7386 * "match()" function
7387 */
7388 static void
7389f_match(typval_T *argvars, typval_T *rettv)
7390{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007391 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392}
7393
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007394/*
7395 * "matchend()" function
7396 */
7397 static void
7398f_matchend(typval_T *argvars, typval_T *rettv)
7399{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007400 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007401}
7402
7403/*
7404 * "matchlist()" function
7405 */
7406 static void
7407f_matchlist(typval_T *argvars, typval_T *rettv)
7408{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007409 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410}
7411
7412/*
7413 * "matchstr()" function
7414 */
7415 static void
7416f_matchstr(typval_T *argvars, typval_T *rettv)
7417{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007418 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007419}
7420
7421/*
7422 * "matchstrpos()" function
7423 */
7424 static void
7425f_matchstrpos(typval_T *argvars, typval_T *rettv)
7426{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007427 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428}
7429
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007430 static void
7431max_min(typval_T *argvars, typval_T *rettv, int domax)
7432{
7433 varnumber_T n = 0;
7434 varnumber_T i;
7435 int error = FALSE;
7436
7437 if (argvars[0].v_type == VAR_LIST)
7438 {
7439 list_T *l;
7440 listitem_T *li;
7441
7442 l = argvars[0].vval.v_list;
7443 if (l != NULL)
7444 {
7445 li = l->lv_first;
7446 if (li != NULL)
7447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007448 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007449 for (;;)
7450 {
7451 li = li->li_next;
7452 if (li == NULL)
7453 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007454 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455 if (domax ? i > n : i < n)
7456 n = i;
7457 }
7458 }
7459 }
7460 }
7461 else if (argvars[0].v_type == VAR_DICT)
7462 {
7463 dict_T *d;
7464 int first = TRUE;
7465 hashitem_T *hi;
7466 int todo;
7467
7468 d = argvars[0].vval.v_dict;
7469 if (d != NULL)
7470 {
7471 todo = (int)d->dv_hashtab.ht_used;
7472 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7473 {
7474 if (!HASHITEM_EMPTY(hi))
7475 {
7476 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007477 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478 if (first)
7479 {
7480 n = i;
7481 first = FALSE;
7482 }
7483 else if (domax ? i > n : i < n)
7484 n = i;
7485 }
7486 }
7487 }
7488 }
7489 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007490 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491 rettv->vval.v_number = error ? 0 : n;
7492}
7493
7494/*
7495 * "max()" function
7496 */
7497 static void
7498f_max(typval_T *argvars, typval_T *rettv)
7499{
7500 max_min(argvars, rettv, TRUE);
7501}
7502
7503/*
7504 * "min()" function
7505 */
7506 static void
7507f_min(typval_T *argvars, typval_T *rettv)
7508{
7509 max_min(argvars, rettv, FALSE);
7510}
7511
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007512/*
7513 * Create the directory in which "dir" is located, and higher levels when
7514 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007515 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516 */
7517 static int
7518mkdir_recurse(char_u *dir, int prot)
7519{
7520 char_u *p;
7521 char_u *updir;
7522 int r = FAIL;
7523
7524 /* Get end of directory name in "dir".
7525 * We're done when it's "/" or "c:/". */
7526 p = gettail_sep(dir);
7527 if (p <= get_past_head(dir))
7528 return OK;
7529
7530 /* If the directory exists we're done. Otherwise: create it.*/
7531 updir = vim_strnsave(dir, (int)(p - dir));
7532 if (updir == NULL)
7533 return FAIL;
7534 if (mch_isdir(updir))
7535 r = OK;
7536 else if (mkdir_recurse(updir, prot) == OK)
7537 r = vim_mkdir_emsg(updir, prot);
7538 vim_free(updir);
7539 return r;
7540}
7541
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007542/*
7543 * "mkdir()" function
7544 */
7545 static void
7546f_mkdir(typval_T *argvars, typval_T *rettv)
7547{
7548 char_u *dir;
7549 char_u buf[NUMBUFLEN];
7550 int prot = 0755;
7551
7552 rettv->vval.v_number = FAIL;
7553 if (check_restricted() || check_secure())
7554 return;
7555
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007556 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007557 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007558 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007559
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007560 if (*gettail(dir) == NUL)
7561 /* remove trailing slashes */
7562 *gettail_sep(dir) = NUL;
7563
7564 if (argvars[1].v_type != VAR_UNKNOWN)
7565 {
7566 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007568 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007569 if (prot == -1)
7570 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007571 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007572 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007573 {
7574 if (mch_isdir(dir))
7575 {
7576 /* With the "p" flag it's OK if the dir already exists. */
7577 rettv->vval.v_number = OK;
7578 return;
7579 }
7580 mkdir_recurse(dir, prot);
7581 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007582 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007583 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007584}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585
7586/*
7587 * "mode()" function
7588 */
7589 static void
7590f_mode(typval_T *argvars, typval_T *rettv)
7591{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007592 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007593
Bram Moolenaar612cc382018-07-29 15:34:26 +02007594 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007595
7596 if (time_for_testing == 93784)
7597 {
7598 /* Testing the two-character code. */
7599 buf[0] = 'x';
7600 buf[1] = '!';
7601 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007602#ifdef FEAT_TERMINAL
7603 else if (term_use_loop())
7604 buf[0] = 't';
7605#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007606 else if (VIsual_active)
7607 {
7608 if (VIsual_select)
7609 buf[0] = VIsual_mode + 's' - 'v';
7610 else
7611 buf[0] = VIsual_mode;
7612 }
7613 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7614 || State == CONFIRM)
7615 {
7616 buf[0] = 'r';
7617 if (State == ASKMORE)
7618 buf[1] = 'm';
7619 else if (State == CONFIRM)
7620 buf[1] = '?';
7621 }
7622 else if (State == EXTERNCMD)
7623 buf[0] = '!';
7624 else if (State & INSERT)
7625 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626 if (State & VREPLACE_FLAG)
7627 {
7628 buf[0] = 'R';
7629 buf[1] = 'v';
7630 }
7631 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007632 {
7633 if (State & REPLACE_FLAG)
7634 buf[0] = 'R';
7635 else
7636 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007637 if (ins_compl_active())
7638 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007639 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007640 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007641 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007642 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007643 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007644 {
7645 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007646 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007648 else if (exmode_active == EXMODE_NORMAL)
7649 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650 }
7651 else
7652 {
7653 buf[0] = 'n';
7654 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007655 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007656 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007657 // to be able to detect force-linewise/blockwise/characterwise operations
7658 buf[2] = motion_force;
7659 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007660 else if (restart_edit == 'I' || restart_edit == 'R'
7661 || restart_edit == 'V')
7662 {
7663 buf[1] = 'i';
7664 buf[2] = restart_edit;
7665 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007666 }
7667
7668 /* Clear out the minor mode when the argument is not a non-zero number or
7669 * non-empty string. */
7670 if (!non_zero_arg(&argvars[0]))
7671 buf[1] = NUL;
7672
7673 rettv->vval.v_string = vim_strsave(buf);
7674 rettv->v_type = VAR_STRING;
7675}
7676
7677#if defined(FEAT_MZSCHEME) || defined(PROTO)
7678/*
7679 * "mzeval()" function
7680 */
7681 static void
7682f_mzeval(typval_T *argvars, typval_T *rettv)
7683{
7684 char_u *str;
7685 char_u buf[NUMBUFLEN];
7686
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007687 if (check_restricted() || check_secure())
7688 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007689 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007690 do_mzeval(str, rettv);
7691}
7692
7693 void
7694mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7695{
7696 typval_T argvars[3];
7697
7698 argvars[0].v_type = VAR_STRING;
7699 argvars[0].vval.v_string = name;
7700 copy_tv(args, &argvars[1]);
7701 argvars[2].v_type = VAR_UNKNOWN;
7702 f_call(argvars, rettv);
7703 clear_tv(&argvars[1]);
7704}
7705#endif
7706
7707/*
7708 * "nextnonblank()" function
7709 */
7710 static void
7711f_nextnonblank(typval_T *argvars, typval_T *rettv)
7712{
7713 linenr_T lnum;
7714
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007715 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716 {
7717 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7718 {
7719 lnum = 0;
7720 break;
7721 }
7722 if (*skipwhite(ml_get(lnum)) != NUL)
7723 break;
7724 }
7725 rettv->vval.v_number = lnum;
7726}
7727
7728/*
7729 * "nr2char()" function
7730 */
7731 static void
7732f_nr2char(typval_T *argvars, typval_T *rettv)
7733{
7734 char_u buf[NUMBUFLEN];
7735
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007736 if (has_mbyte)
7737 {
7738 int utf8 = 0;
7739
7740 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007741 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007742 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007743 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007745 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746 }
7747 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007749 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 buf[1] = NUL;
7751 }
7752 rettv->v_type = VAR_STRING;
7753 rettv->vval.v_string = vim_strsave(buf);
7754}
7755
7756/*
7757 * "or(expr, expr)" function
7758 */
7759 static void
7760f_or(typval_T *argvars, typval_T *rettv)
7761{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007762 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7763 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007764}
7765
7766/*
7767 * "pathshorten()" function
7768 */
7769 static void
7770f_pathshorten(typval_T *argvars, typval_T *rettv)
7771{
7772 char_u *p;
7773
7774 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007775 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 if (p == NULL)
7777 rettv->vval.v_string = NULL;
7778 else
7779 {
7780 p = vim_strsave(p);
7781 rettv->vval.v_string = p;
7782 if (p != NULL)
7783 shorten_dir(p);
7784 }
7785}
7786
7787#ifdef FEAT_PERL
7788/*
7789 * "perleval()" function
7790 */
7791 static void
7792f_perleval(typval_T *argvars, typval_T *rettv)
7793{
7794 char_u *str;
7795 char_u buf[NUMBUFLEN];
7796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007797 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798 do_perleval(str, rettv);
7799}
7800#endif
7801
7802#ifdef FEAT_FLOAT
7803/*
7804 * "pow()" function
7805 */
7806 static void
7807f_pow(typval_T *argvars, typval_T *rettv)
7808{
7809 float_T fx = 0.0, fy = 0.0;
7810
7811 rettv->v_type = VAR_FLOAT;
7812 if (get_float_arg(argvars, &fx) == OK
7813 && get_float_arg(&argvars[1], &fy) == OK)
7814 rettv->vval.v_float = pow(fx, fy);
7815 else
7816 rettv->vval.v_float = 0.0;
7817}
7818#endif
7819
7820/*
7821 * "prevnonblank()" function
7822 */
7823 static void
7824f_prevnonblank(typval_T *argvars, typval_T *rettv)
7825{
7826 linenr_T lnum;
7827
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007828 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007829 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7830 lnum = 0;
7831 else
7832 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7833 --lnum;
7834 rettv->vval.v_number = lnum;
7835}
7836
7837/* This dummy va_list is here because:
7838 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7839 * - locally in the function results in a "used before set" warning
7840 * - using va_start() to initialize it gives "function with fixed args" error */
7841static va_list ap;
7842
7843/*
7844 * "printf()" function
7845 */
7846 static void
7847f_printf(typval_T *argvars, typval_T *rettv)
7848{
7849 char_u buf[NUMBUFLEN];
7850 int len;
7851 char_u *s;
7852 int saved_did_emsg = did_emsg;
7853 char *fmt;
7854
7855 rettv->v_type = VAR_STRING;
7856 rettv->vval.v_string = NULL;
7857
7858 /* Get the required length, allocate the buffer and do it for real. */
7859 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007860 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007861 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007862 if (!did_emsg)
7863 {
7864 s = alloc(len + 1);
7865 if (s != NULL)
7866 {
7867 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007868 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7869 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007870 }
7871 }
7872 did_emsg |= saved_did_emsg;
7873}
7874
7875/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007876 * "pum_getpos()" function
7877 */
7878 static void
7879f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7880{
7881 if (rettv_dict_alloc(rettv) != OK)
7882 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007883 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007884}
7885
7886/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 * "pumvisible()" function
7888 */
7889 static void
7890f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7891{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892 if (pum_visible())
7893 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007894}
7895
7896#ifdef FEAT_PYTHON3
7897/*
7898 * "py3eval()" function
7899 */
7900 static void
7901f_py3eval(typval_T *argvars, typval_T *rettv)
7902{
7903 char_u *str;
7904 char_u buf[NUMBUFLEN];
7905
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007906 if (check_restricted() || check_secure())
7907 return;
7908
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007909 if (p_pyx == 0)
7910 p_pyx = 3;
7911
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007912 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007913 do_py3eval(str, rettv);
7914}
7915#endif
7916
7917#ifdef FEAT_PYTHON
7918/*
7919 * "pyeval()" function
7920 */
7921 static void
7922f_pyeval(typval_T *argvars, typval_T *rettv)
7923{
7924 char_u *str;
7925 char_u buf[NUMBUFLEN];
7926
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007927 if (check_restricted() || check_secure())
7928 return;
7929
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007930 if (p_pyx == 0)
7931 p_pyx = 2;
7932
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007933 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007934 do_pyeval(str, rettv);
7935}
7936#endif
7937
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007938#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7939/*
7940 * "pyxeval()" function
7941 */
7942 static void
7943f_pyxeval(typval_T *argvars, typval_T *rettv)
7944{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007945 if (check_restricted() || check_secure())
7946 return;
7947
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007948# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7949 init_pyxversion();
7950 if (p_pyx == 2)
7951 f_pyeval(argvars, rettv);
7952 else
7953 f_py3eval(argvars, rettv);
7954# elif defined(FEAT_PYTHON)
7955 f_pyeval(argvars, rettv);
7956# elif defined(FEAT_PYTHON3)
7957 f_py3eval(argvars, rettv);
7958# endif
7959}
7960#endif
7961
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007962/*
7963 * "range()" function
7964 */
7965 static void
7966f_range(typval_T *argvars, typval_T *rettv)
7967{
7968 varnumber_T start;
7969 varnumber_T end;
7970 varnumber_T stride = 1;
7971 varnumber_T i;
7972 int error = FALSE;
7973
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007974 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007975 if (argvars[1].v_type == VAR_UNKNOWN)
7976 {
7977 end = start - 1;
7978 start = 0;
7979 }
7980 else
7981 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007982 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007983 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007984 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007985 }
7986
7987 if (error)
7988 return; /* type error; errmsg already given */
7989 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007990 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007992 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 else
7994 {
7995 if (rettv_list_alloc(rettv) == OK)
7996 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7997 if (list_append_number(rettv->vval.v_list,
7998 (varnumber_T)i) == FAIL)
7999 break;
8000 }
8001}
8002
8003/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008004 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008005 */
8006 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008007readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008008{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008009 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008010 typval_T save_val;
8011 typval_T rettv;
8012 typval_T argv[2];
8013 int retval = 0;
8014 int error = FALSE;
8015
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008016 if (expr->v_type == VAR_UNKNOWN)
8017 return 1;
8018
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008019 prepare_vimvar(VV_VAL, &save_val);
8020 set_vim_var_string(VV_VAL, name, -1);
8021 argv[0].v_type = VAR_STRING;
8022 argv[0].vval.v_string = name;
8023
8024 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8025 goto theend;
8026
8027 retval = tv_get_number_chk(&rettv, &error);
8028 if (error)
8029 retval = -1;
8030 clear_tv(&rettv);
8031
8032theend:
8033 set_vim_var_string(VV_VAL, NULL, 0);
8034 restore_vimvar(VV_VAL, &save_val);
8035 return retval;
8036}
8037
8038/*
8039 * "readdir()" function
8040 */
8041 static void
8042f_readdir(typval_T *argvars, typval_T *rettv)
8043{
8044 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008045 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008046 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008047 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008048 garray_T ga;
8049 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008050
8051 if (rettv_list_alloc(rettv) == FAIL)
8052 return;
8053 path = tv_get_string(&argvars[0]);
8054 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008055
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008056 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8057 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008058 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008059 for (i = 0; i < ga.ga_len; i++)
8060 {
8061 p = ((char_u **)ga.ga_data)[i];
8062 list_append_string(rettv->vval.v_list, p, -1);
8063 }
8064 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008065 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008066}
8067
8068/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069 * "readfile()" function
8070 */
8071 static void
8072f_readfile(typval_T *argvars, typval_T *rettv)
8073{
8074 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008075 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008076 int failed = FALSE;
8077 char_u *fname;
8078 FILE *fd;
8079 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8080 int io_size = sizeof(buf);
8081 int readlen; /* size of last fread() */
8082 char_u *prev = NULL; /* previously read bytes, if any */
8083 long prevlen = 0; /* length of data in prev */
8084 long prevsize = 0; /* size of prev buffer */
8085 long maxline = MAXLNUM;
8086 long cnt = 0;
8087 char_u *p; /* position in buf */
8088 char_u *start; /* start of current line */
8089
8090 if (argvars[1].v_type != VAR_UNKNOWN)
8091 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008092 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008093 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008094 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8095 blob = TRUE;
8096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008097 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008098 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008099 }
8100
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008101 if (blob)
8102 {
8103 if (rettv_blob_alloc(rettv) == FAIL)
8104 return;
8105 }
8106 else
8107 {
8108 if (rettv_list_alloc(rettv) == FAIL)
8109 return;
8110 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111
8112 /* Always open the file in binary mode, library functions have a mind of
8113 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008114 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008115 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8116 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008117 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118 return;
8119 }
8120
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008121 if (blob)
8122 {
8123 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8124 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008125 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008126 blob_free(rettv->vval.v_blob);
8127 }
8128 fclose(fd);
8129 return;
8130 }
8131
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008132 while (cnt < maxline || maxline < 0)
8133 {
8134 readlen = (int)fread(buf, 1, io_size, fd);
8135
8136 /* This for loop processes what was read, but is also entered at end
8137 * of file so that either:
8138 * - an incomplete line gets written
8139 * - a "binary" file gets an empty line at the end if it ends in a
8140 * newline. */
8141 for (p = buf, start = buf;
8142 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8143 ++p)
8144 {
8145 if (*p == '\n' || readlen <= 0)
8146 {
8147 listitem_T *li;
8148 char_u *s = NULL;
8149 long_u len = p - start;
8150
8151 /* Finished a line. Remove CRs before NL. */
8152 if (readlen > 0 && !binary)
8153 {
8154 while (len > 0 && start[len - 1] == '\r')
8155 --len;
8156 /* removal may cross back to the "prev" string */
8157 if (len == 0)
8158 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8159 --prevlen;
8160 }
8161 if (prevlen == 0)
8162 s = vim_strnsave(start, (int)len);
8163 else
8164 {
8165 /* Change "prev" buffer to be the right size. This way
8166 * the bytes are only copied once, and very long lines are
8167 * allocated only once. */
8168 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8169 {
8170 mch_memmove(s + prevlen, start, len);
8171 s[prevlen + len] = NUL;
8172 prev = NULL; /* the list will own the string */
8173 prevlen = prevsize = 0;
8174 }
8175 }
8176 if (s == NULL)
8177 {
8178 do_outofmem_msg((long_u) prevlen + len + 1);
8179 failed = TRUE;
8180 break;
8181 }
8182
8183 if ((li = listitem_alloc()) == NULL)
8184 {
8185 vim_free(s);
8186 failed = TRUE;
8187 break;
8188 }
8189 li->li_tv.v_type = VAR_STRING;
8190 li->li_tv.v_lock = 0;
8191 li->li_tv.vval.v_string = s;
8192 list_append(rettv->vval.v_list, li);
8193
8194 start = p + 1; /* step over newline */
8195 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8196 break;
8197 }
8198 else if (*p == NUL)
8199 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008200 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8201 * when finding the BF and check the previous two bytes. */
8202 else if (*p == 0xbf && enc_utf8 && !binary)
8203 {
8204 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8205 * + 1, these may be in the "prev" string. */
8206 char_u back1 = p >= buf + 1 ? p[-1]
8207 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8208 char_u back2 = p >= buf + 2 ? p[-2]
8209 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8210 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8211
8212 if (back2 == 0xef && back1 == 0xbb)
8213 {
8214 char_u *dest = p - 2;
8215
8216 /* Usually a BOM is at the beginning of a file, and so at
8217 * the beginning of a line; then we can just step over it.
8218 */
8219 if (start == dest)
8220 start = p + 1;
8221 else
8222 {
8223 /* have to shuffle buf to close gap */
8224 int adjust_prevlen = 0;
8225
8226 if (dest < buf)
8227 {
8228 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8229 dest = buf;
8230 }
8231 if (readlen > p - buf + 1)
8232 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8233 readlen -= 3 - adjust_prevlen;
8234 prevlen -= adjust_prevlen;
8235 p = dest - 1;
8236 }
8237 }
8238 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239 } /* for */
8240
8241 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8242 break;
8243 if (start < p)
8244 {
8245 /* There's part of a line in buf, store it in "prev". */
8246 if (p - start + prevlen >= prevsize)
8247 {
8248 /* need bigger "prev" buffer */
8249 char_u *newprev;
8250
8251 /* A common use case is ordinary text files and "prev" gets a
8252 * fragment of a line, so the first allocation is made
8253 * small, to avoid repeatedly 'allocing' large and
8254 * 'reallocing' small. */
8255 if (prevsize == 0)
8256 prevsize = (long)(p - start);
8257 else
8258 {
8259 long grow50pc = (prevsize * 3) / 2;
8260 long growmin = (long)((p - start) * 2 + prevlen);
8261 prevsize = grow50pc > growmin ? grow50pc : growmin;
8262 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008263 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008264 if (newprev == NULL)
8265 {
8266 do_outofmem_msg((long_u)prevsize);
8267 failed = TRUE;
8268 break;
8269 }
8270 prev = newprev;
8271 }
8272 /* Add the line part to end of "prev". */
8273 mch_memmove(prev + prevlen, start, p - start);
8274 prevlen += (long)(p - start);
8275 }
8276 } /* while */
8277
8278 /*
8279 * For a negative line count use only the lines at the end of the file,
8280 * free the rest.
8281 */
8282 if (!failed && maxline < 0)
8283 while (cnt > -maxline)
8284 {
8285 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8286 --cnt;
8287 }
8288
8289 if (failed)
8290 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008291 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008292 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008293 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008294 }
8295
8296 vim_free(prev);
8297 fclose(fd);
8298}
8299
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008300 static void
8301return_register(int regname, typval_T *rettv)
8302{
8303 char_u buf[2] = {0, 0};
8304
8305 buf[0] = (char_u)regname;
8306 rettv->v_type = VAR_STRING;
8307 rettv->vval.v_string = vim_strsave(buf);
8308}
8309
8310/*
8311 * "reg_executing()" function
8312 */
8313 static void
8314f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8315{
8316 return_register(reg_executing, rettv);
8317}
8318
8319/*
8320 * "reg_recording()" function
8321 */
8322 static void
8323f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8324{
8325 return_register(reg_recording, rettv);
8326}
8327
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008328#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329/*
8330 * Convert a List to proftime_T.
8331 * Return FAIL when there is something wrong.
8332 */
8333 static int
8334list2proftime(typval_T *arg, proftime_T *tm)
8335{
8336 long n1, n2;
8337 int error = FALSE;
8338
8339 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8340 || arg->vval.v_list->lv_len != 2)
8341 return FAIL;
8342 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8343 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008344# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008345 tm->HighPart = n1;
8346 tm->LowPart = n2;
8347# else
8348 tm->tv_sec = n1;
8349 tm->tv_usec = n2;
8350# endif
8351 return error ? FAIL : OK;
8352}
8353#endif /* FEAT_RELTIME */
8354
8355/*
8356 * "reltime()" function
8357 */
8358 static void
8359f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8360{
8361#ifdef FEAT_RELTIME
8362 proftime_T res;
8363 proftime_T start;
8364
8365 if (argvars[0].v_type == VAR_UNKNOWN)
8366 {
8367 /* No arguments: get current time. */
8368 profile_start(&res);
8369 }
8370 else if (argvars[1].v_type == VAR_UNKNOWN)
8371 {
8372 if (list2proftime(&argvars[0], &res) == FAIL)
8373 return;
8374 profile_end(&res);
8375 }
8376 else
8377 {
8378 /* Two arguments: compute the difference. */
8379 if (list2proftime(&argvars[0], &start) == FAIL
8380 || list2proftime(&argvars[1], &res) == FAIL)
8381 return;
8382 profile_sub(&res, &start);
8383 }
8384
8385 if (rettv_list_alloc(rettv) == OK)
8386 {
8387 long n1, n2;
8388
Bram Moolenaar4f974752019-02-17 17:44:42 +01008389# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390 n1 = res.HighPart;
8391 n2 = res.LowPart;
8392# else
8393 n1 = res.tv_sec;
8394 n2 = res.tv_usec;
8395# endif
8396 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8397 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8398 }
8399#endif
8400}
8401
8402#ifdef FEAT_FLOAT
8403/*
8404 * "reltimefloat()" function
8405 */
8406 static void
8407f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8408{
8409# ifdef FEAT_RELTIME
8410 proftime_T tm;
8411# endif
8412
8413 rettv->v_type = VAR_FLOAT;
8414 rettv->vval.v_float = 0;
8415# ifdef FEAT_RELTIME
8416 if (list2proftime(&argvars[0], &tm) == OK)
8417 rettv->vval.v_float = profile_float(&tm);
8418# endif
8419}
8420#endif
8421
8422/*
8423 * "reltimestr()" function
8424 */
8425 static void
8426f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8427{
8428#ifdef FEAT_RELTIME
8429 proftime_T tm;
8430#endif
8431
8432 rettv->v_type = VAR_STRING;
8433 rettv->vval.v_string = NULL;
8434#ifdef FEAT_RELTIME
8435 if (list2proftime(&argvars[0], &tm) == OK)
8436 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8437#endif
8438}
8439
8440#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008441 static void
8442make_connection(void)
8443{
8444 if (X_DISPLAY == NULL
8445# ifdef FEAT_GUI
8446 && !gui.in_use
8447# endif
8448 )
8449 {
8450 x_force_connect = TRUE;
8451 setup_term_clip();
8452 x_force_connect = FALSE;
8453 }
8454}
8455
8456 static int
8457check_connection(void)
8458{
8459 make_connection();
8460 if (X_DISPLAY == NULL)
8461 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008462 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463 return FAIL;
8464 }
8465 return OK;
8466}
8467#endif
8468
8469#ifdef FEAT_CLIENTSERVER
8470 static void
8471remote_common(typval_T *argvars, typval_T *rettv, int expr)
8472{
8473 char_u *server_name;
8474 char_u *keys;
8475 char_u *r = NULL;
8476 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008477 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008478# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008479 HWND w;
8480# else
8481 Window w;
8482# endif
8483
8484 if (check_restricted() || check_secure())
8485 return;
8486
8487# ifdef FEAT_X11
8488 if (check_connection() == FAIL)
8489 return;
8490# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008491 if (argvars[2].v_type != VAR_UNKNOWN
8492 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008493 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008494
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008495 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008496 if (server_name == NULL)
8497 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008498 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008499# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008500 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008501# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008502 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8503 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008504# endif
8505 {
8506 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008507 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008508 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008509 vim_free(r);
8510 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008511 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008512 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008513 return;
8514 }
8515
8516 rettv->vval.v_string = r;
8517
8518 if (argvars[2].v_type != VAR_UNKNOWN)
8519 {
8520 dictitem_T v;
8521 char_u str[30];
8522 char_u *idvar;
8523
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008524 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008525 if (idvar != NULL && *idvar != NUL)
8526 {
8527 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8528 v.di_tv.v_type = VAR_STRING;
8529 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008531 vim_free(v.di_tv.vval.v_string);
8532 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008533 }
8534}
8535#endif
8536
8537/*
8538 * "remote_expr()" function
8539 */
8540 static void
8541f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8542{
8543 rettv->v_type = VAR_STRING;
8544 rettv->vval.v_string = NULL;
8545#ifdef FEAT_CLIENTSERVER
8546 remote_common(argvars, rettv, TRUE);
8547#endif
8548}
8549
8550/*
8551 * "remote_foreground()" function
8552 */
8553 static void
8554f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8555{
8556#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008557# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 /* On Win32 it's done in this application. */
8559 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008560 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008561
8562 if (server_name != NULL)
8563 serverForeground(server_name);
8564 }
8565# else
8566 /* Send a foreground() expression to the server. */
8567 argvars[1].v_type = VAR_STRING;
8568 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8569 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008570 rettv->v_type = VAR_STRING;
8571 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008572 remote_common(argvars, rettv, TRUE);
8573 vim_free(argvars[1].vval.v_string);
8574# endif
8575#endif
8576}
8577
8578 static void
8579f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8580{
8581#ifdef FEAT_CLIENTSERVER
8582 dictitem_T v;
8583 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008584# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008585 long_u n = 0;
8586# endif
8587 char_u *serverid;
8588
8589 if (check_restricted() || check_secure())
8590 {
8591 rettv->vval.v_number = -1;
8592 return;
8593 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008594 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595 if (serverid == NULL)
8596 {
8597 rettv->vval.v_number = -1;
8598 return; /* type error; errmsg already given */
8599 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008600# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008601 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8602 if (n == 0)
8603 rettv->vval.v_number = -1;
8604 else
8605 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008606 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 rettv->vval.v_number = (s != NULL);
8608 }
8609# else
8610 if (check_connection() == FAIL)
8611 return;
8612
8613 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8614 serverStrToWin(serverid), &s);
8615# endif
8616
8617 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8618 {
8619 char_u *retvar;
8620
8621 v.di_tv.v_type = VAR_STRING;
8622 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008623 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008624 if (retvar != NULL)
8625 set_var(retvar, &v.di_tv, FALSE);
8626 vim_free(v.di_tv.vval.v_string);
8627 }
8628#else
8629 rettv->vval.v_number = -1;
8630#endif
8631}
8632
8633 static void
8634f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8635{
8636 char_u *r = NULL;
8637
8638#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008639 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008640
8641 if (serverid != NULL && !check_restricted() && !check_secure())
8642 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008643 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008644# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008645 /* The server's HWND is encoded in the 'id' parameter */
8646 long_u n = 0;
8647# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008648
8649 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008650 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008651
Bram Moolenaar4f974752019-02-17 17:44:42 +01008652# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008653 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8654 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008655 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008656 if (r == NULL)
8657# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008658 if (check_connection() == FAIL
8659 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8660 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008661# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008662 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008663 }
8664#endif
8665 rettv->v_type = VAR_STRING;
8666 rettv->vval.v_string = r;
8667}
8668
8669/*
8670 * "remote_send()" function
8671 */
8672 static void
8673f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8674{
8675 rettv->v_type = VAR_STRING;
8676 rettv->vval.v_string = NULL;
8677#ifdef FEAT_CLIENTSERVER
8678 remote_common(argvars, rettv, FALSE);
8679#endif
8680}
8681
8682/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008683 * "remote_startserver()" function
8684 */
8685 static void
8686f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8687{
8688#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008689 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008690
8691 if (server == NULL)
8692 return; /* type error; errmsg already given */
8693 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008694 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008695 else
8696 {
8697# ifdef FEAT_X11
8698 if (check_connection() == OK)
8699 serverRegisterName(X_DISPLAY, server);
8700# else
8701 serverSetName(server);
8702# endif
8703 }
8704#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008705 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008706#endif
8707}
8708
8709/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008710 * "remove()" function
8711 */
8712 static void
8713f_remove(typval_T *argvars, typval_T *rettv)
8714{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008715 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8716
8717 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008718 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008719 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008720 blob_remove(argvars, rettv);
8721 else if (argvars[0].v_type == VAR_LIST)
8722 list_remove(argvars, rettv, arg_errmsg);
8723 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008724 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725}
8726
8727/*
8728 * "rename({from}, {to})" function
8729 */
8730 static void
8731f_rename(typval_T *argvars, typval_T *rettv)
8732{
8733 char_u buf[NUMBUFLEN];
8734
8735 if (check_restricted() || check_secure())
8736 rettv->vval.v_number = -1;
8737 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008738 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8739 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008740}
8741
8742/*
8743 * "repeat()" function
8744 */
8745 static void
8746f_repeat(typval_T *argvars, typval_T *rettv)
8747{
8748 char_u *p;
8749 int n;
8750 int slen;
8751 int len;
8752 char_u *r;
8753 int i;
8754
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008755 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008756 if (argvars[0].v_type == VAR_LIST)
8757 {
8758 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8759 while (n-- > 0)
8760 if (list_extend(rettv->vval.v_list,
8761 argvars[0].vval.v_list, NULL) == FAIL)
8762 break;
8763 }
8764 else
8765 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008766 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008767 rettv->v_type = VAR_STRING;
8768 rettv->vval.v_string = NULL;
8769
8770 slen = (int)STRLEN(p);
8771 len = slen * n;
8772 if (len <= 0)
8773 return;
8774
8775 r = alloc(len + 1);
8776 if (r != NULL)
8777 {
8778 for (i = 0; i < n; i++)
8779 mch_memmove(r + i * slen, p, (size_t)slen);
8780 r[len] = NUL;
8781 }
8782
8783 rettv->vval.v_string = r;
8784 }
8785}
8786
8787/*
8788 * "resolve()" function
8789 */
8790 static void
8791f_resolve(typval_T *argvars, typval_T *rettv)
8792{
8793 char_u *p;
8794#ifdef HAVE_READLINK
8795 char_u *buf = NULL;
8796#endif
8797
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008798 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008799#ifdef FEAT_SHORTCUT
8800 {
8801 char_u *v = NULL;
8802
Bram Moolenaardce1e892019-02-10 23:18:53 +01008803 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008804 if (v != NULL)
8805 rettv->vval.v_string = v;
8806 else
8807 rettv->vval.v_string = vim_strsave(p);
8808 }
8809#else
8810# ifdef HAVE_READLINK
8811 {
8812 char_u *cpy;
8813 int len;
8814 char_u *remain = NULL;
8815 char_u *q;
8816 int is_relative_to_current = FALSE;
8817 int has_trailing_pathsep = FALSE;
8818 int limit = 100;
8819
8820 p = vim_strsave(p);
8821
8822 if (p[0] == '.' && (vim_ispathsep(p[1])
8823 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8824 is_relative_to_current = TRUE;
8825
8826 len = STRLEN(p);
8827 if (len > 0 && after_pathsep(p, p + len))
8828 {
8829 has_trailing_pathsep = TRUE;
8830 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8831 }
8832
8833 q = getnextcomp(p);
8834 if (*q != NUL)
8835 {
8836 /* Separate the first path component in "p", and keep the
8837 * remainder (beginning with the path separator). */
8838 remain = vim_strsave(q - 1);
8839 q[-1] = NUL;
8840 }
8841
8842 buf = alloc(MAXPATHL + 1);
8843 if (buf == NULL)
8844 goto fail;
8845
8846 for (;;)
8847 {
8848 for (;;)
8849 {
8850 len = readlink((char *)p, (char *)buf, MAXPATHL);
8851 if (len <= 0)
8852 break;
8853 buf[len] = NUL;
8854
8855 if (limit-- == 0)
8856 {
8857 vim_free(p);
8858 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008859 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008860 rettv->vval.v_string = NULL;
8861 goto fail;
8862 }
8863
8864 /* Ensure that the result will have a trailing path separator
8865 * if the argument has one. */
8866 if (remain == NULL && has_trailing_pathsep)
8867 add_pathsep(buf);
8868
8869 /* Separate the first path component in the link value and
8870 * concatenate the remainders. */
8871 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8872 if (*q != NUL)
8873 {
8874 if (remain == NULL)
8875 remain = vim_strsave(q - 1);
8876 else
8877 {
8878 cpy = concat_str(q - 1, remain);
8879 if (cpy != NULL)
8880 {
8881 vim_free(remain);
8882 remain = cpy;
8883 }
8884 }
8885 q[-1] = NUL;
8886 }
8887
8888 q = gettail(p);
8889 if (q > p && *q == NUL)
8890 {
8891 /* Ignore trailing path separator. */
8892 q[-1] = NUL;
8893 q = gettail(p);
8894 }
8895 if (q > p && !mch_isFullName(buf))
8896 {
8897 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02008898 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008899 if (cpy != NULL)
8900 {
8901 STRCPY(cpy, p);
8902 STRCPY(gettail(cpy), buf);
8903 vim_free(p);
8904 p = cpy;
8905 }
8906 }
8907 else
8908 {
8909 vim_free(p);
8910 p = vim_strsave(buf);
8911 }
8912 }
8913
8914 if (remain == NULL)
8915 break;
8916
8917 /* Append the first path component of "remain" to "p". */
8918 q = getnextcomp(remain + 1);
8919 len = q - remain - (*q != NUL);
8920 cpy = vim_strnsave(p, STRLEN(p) + len);
8921 if (cpy != NULL)
8922 {
8923 STRNCAT(cpy, remain, len);
8924 vim_free(p);
8925 p = cpy;
8926 }
8927 /* Shorten "remain". */
8928 if (*q != NUL)
8929 STRMOVE(remain, q - 1);
8930 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01008931 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008932 }
8933
8934 /* If the result is a relative path name, make it explicitly relative to
8935 * the current directory if and only if the argument had this form. */
8936 if (!vim_ispathsep(*p))
8937 {
8938 if (is_relative_to_current
8939 && *p != NUL
8940 && !(p[0] == '.'
8941 && (p[1] == NUL
8942 || vim_ispathsep(p[1])
8943 || (p[1] == '.'
8944 && (p[2] == NUL
8945 || vim_ispathsep(p[2]))))))
8946 {
8947 /* Prepend "./". */
8948 cpy = concat_str((char_u *)"./", p);
8949 if (cpy != NULL)
8950 {
8951 vim_free(p);
8952 p = cpy;
8953 }
8954 }
8955 else if (!is_relative_to_current)
8956 {
8957 /* Strip leading "./". */
8958 q = p;
8959 while (q[0] == '.' && vim_ispathsep(q[1]))
8960 q += 2;
8961 if (q > p)
8962 STRMOVE(p, p + 2);
8963 }
8964 }
8965
8966 /* Ensure that the result will have no trailing path separator
8967 * if the argument had none. But keep "/" or "//". */
8968 if (!has_trailing_pathsep)
8969 {
8970 q = p + STRLEN(p);
8971 if (after_pathsep(p, q))
8972 *gettail_sep(p) = NUL;
8973 }
8974
8975 rettv->vval.v_string = p;
8976 }
8977# else
8978 rettv->vval.v_string = vim_strsave(p);
8979# endif
8980#endif
8981
8982 simplify_filename(rettv->vval.v_string);
8983
8984#ifdef HAVE_READLINK
8985fail:
8986 vim_free(buf);
8987#endif
8988 rettv->v_type = VAR_STRING;
8989}
8990
8991/*
8992 * "reverse({list})" function
8993 */
8994 static void
8995f_reverse(typval_T *argvars, typval_T *rettv)
8996{
8997 list_T *l;
8998 listitem_T *li, *ni;
8999
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009000 if (argvars[0].v_type == VAR_BLOB)
9001 {
9002 blob_T *b = argvars[0].vval.v_blob;
9003 int i, len = blob_len(b);
9004
9005 for (i = 0; i < len / 2; i++)
9006 {
9007 int tmp = blob_get(b, i);
9008
9009 blob_set(b, i, blob_get(b, len - i - 1));
9010 blob_set(b, len - i - 1, tmp);
9011 }
9012 rettv_blob_set(rettv, b);
9013 return;
9014 }
9015
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009016 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009017 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009018 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009019 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009020 (char_u *)N_("reverse() argument"), TRUE))
9021 {
9022 li = l->lv_last;
9023 l->lv_first = l->lv_last = NULL;
9024 l->lv_len = 0;
9025 while (li != NULL)
9026 {
9027 ni = li->li_prev;
9028 list_append(l, li);
9029 li = ni;
9030 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009031 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009032 l->lv_idx = l->lv_len - l->lv_idx - 1;
9033 }
9034}
9035
9036#define SP_NOMOVE 0x01 /* don't move cursor */
9037#define SP_REPEAT 0x02 /* repeat to find outer pair */
9038#define SP_RETCOUNT 0x04 /* return matchcount */
9039#define SP_SETPCMARK 0x08 /* set previous context mark */
9040#define SP_START 0x10 /* accept match at start position */
9041#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9042#define SP_END 0x40 /* leave cursor at end of match */
9043#define SP_COLUMN 0x80 /* start at cursor column */
9044
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009045/*
9046 * Get flags for a search function.
9047 * Possibly sets "p_ws".
9048 * Returns BACKWARD, FORWARD or zero (for an error).
9049 */
9050 static int
9051get_search_arg(typval_T *varp, int *flagsp)
9052{
9053 int dir = FORWARD;
9054 char_u *flags;
9055 char_u nbuf[NUMBUFLEN];
9056 int mask;
9057
9058 if (varp->v_type != VAR_UNKNOWN)
9059 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009060 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009061 if (flags == NULL)
9062 return 0; /* type error; errmsg already given */
9063 while (*flags != NUL)
9064 {
9065 switch (*flags)
9066 {
9067 case 'b': dir = BACKWARD; break;
9068 case 'w': p_ws = TRUE; break;
9069 case 'W': p_ws = FALSE; break;
9070 default: mask = 0;
9071 if (flagsp != NULL)
9072 switch (*flags)
9073 {
9074 case 'c': mask = SP_START; break;
9075 case 'e': mask = SP_END; break;
9076 case 'm': mask = SP_RETCOUNT; break;
9077 case 'n': mask = SP_NOMOVE; break;
9078 case 'p': mask = SP_SUBPAT; break;
9079 case 'r': mask = SP_REPEAT; break;
9080 case 's': mask = SP_SETPCMARK; break;
9081 case 'z': mask = SP_COLUMN; break;
9082 }
9083 if (mask == 0)
9084 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009085 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009086 dir = 0;
9087 }
9088 else
9089 *flagsp |= mask;
9090 }
9091 if (dir == 0)
9092 break;
9093 ++flags;
9094 }
9095 }
9096 return dir;
9097}
9098
9099/*
9100 * Shared by search() and searchpos() functions.
9101 */
9102 static int
9103search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9104{
9105 int flags;
9106 char_u *pat;
9107 pos_T pos;
9108 pos_T save_cursor;
9109 int save_p_ws = p_ws;
9110 int dir;
9111 int retval = 0; /* default: FAIL */
9112 long lnum_stop = 0;
9113 proftime_T tm;
9114#ifdef FEAT_RELTIME
9115 long time_limit = 0;
9116#endif
9117 int options = SEARCH_KEEP;
9118 int subpatnum;
9119
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009120 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009121 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9122 if (dir == 0)
9123 goto theend;
9124 flags = *flagsp;
9125 if (flags & SP_START)
9126 options |= SEARCH_START;
9127 if (flags & SP_END)
9128 options |= SEARCH_END;
9129 if (flags & SP_COLUMN)
9130 options |= SEARCH_COL;
9131
9132 /* Optional arguments: line number to stop searching and timeout. */
9133 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9134 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009135 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009136 if (lnum_stop < 0)
9137 goto theend;
9138#ifdef FEAT_RELTIME
9139 if (argvars[3].v_type != VAR_UNKNOWN)
9140 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009141 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009142 if (time_limit < 0)
9143 goto theend;
9144 }
9145#endif
9146 }
9147
9148#ifdef FEAT_RELTIME
9149 /* Set the time limit, if there is one. */
9150 profile_setlimit(time_limit, &tm);
9151#endif
9152
9153 /*
9154 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9155 * Check to make sure only those flags are set.
9156 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9157 * flags cannot be set. Check for that condition also.
9158 */
9159 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9160 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9161 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009162 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009163 goto theend;
9164 }
9165
9166 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009167 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009168 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009169 if (subpatnum != FAIL)
9170 {
9171 if (flags & SP_SUBPAT)
9172 retval = subpatnum;
9173 else
9174 retval = pos.lnum;
9175 if (flags & SP_SETPCMARK)
9176 setpcmark();
9177 curwin->w_cursor = pos;
9178 if (match_pos != NULL)
9179 {
9180 /* Store the match cursor position */
9181 match_pos->lnum = pos.lnum;
9182 match_pos->col = pos.col + 1;
9183 }
9184 /* "/$" will put the cursor after the end of the line, may need to
9185 * correct that here */
9186 check_cursor();
9187 }
9188
9189 /* If 'n' flag is used: restore cursor position. */
9190 if (flags & SP_NOMOVE)
9191 curwin->w_cursor = save_cursor;
9192 else
9193 curwin->w_set_curswant = TRUE;
9194theend:
9195 p_ws = save_p_ws;
9196
9197 return retval;
9198}
9199
9200#ifdef FEAT_FLOAT
9201
9202/*
9203 * round() is not in C90, use ceil() or floor() instead.
9204 */
9205 float_T
9206vim_round(float_T f)
9207{
9208 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9209}
9210
9211/*
9212 * "round({float})" function
9213 */
9214 static void
9215f_round(typval_T *argvars, typval_T *rettv)
9216{
9217 float_T f = 0.0;
9218
9219 rettv->v_type = VAR_FLOAT;
9220 if (get_float_arg(argvars, &f) == OK)
9221 rettv->vval.v_float = vim_round(f);
9222 else
9223 rettv->vval.v_float = 0.0;
9224}
9225#endif
9226
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009227#ifdef FEAT_RUBY
9228/*
9229 * "rubyeval()" function
9230 */
9231 static void
9232f_rubyeval(typval_T *argvars, typval_T *rettv)
9233{
9234 char_u *str;
9235 char_u buf[NUMBUFLEN];
9236
9237 str = tv_get_string_buf(&argvars[0], buf);
9238 do_rubyeval(str, rettv);
9239}
9240#endif
9241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009242/*
9243 * "screenattr()" function
9244 */
9245 static void
9246f_screenattr(typval_T *argvars, typval_T *rettv)
9247{
9248 int row;
9249 int col;
9250 int c;
9251
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009252 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9253 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009254 if (row < 0 || row >= screen_Rows
9255 || col < 0 || col >= screen_Columns)
9256 c = -1;
9257 else
9258 c = ScreenAttrs[LineOffset[row] + col];
9259 rettv->vval.v_number = c;
9260}
9261
9262/*
9263 * "screenchar()" function
9264 */
9265 static void
9266f_screenchar(typval_T *argvars, typval_T *rettv)
9267{
9268 int row;
9269 int col;
9270 int off;
9271 int c;
9272
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009273 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9274 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009275 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009276 c = -1;
9277 else
9278 {
9279 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009280 if (enc_utf8 && ScreenLinesUC[off] != 0)
9281 c = ScreenLinesUC[off];
9282 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009283 c = ScreenLines[off];
9284 }
9285 rettv->vval.v_number = c;
9286}
9287
9288/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009289 * "screenchars()" function
9290 */
9291 static void
9292f_screenchars(typval_T *argvars, typval_T *rettv)
9293{
9294 int row;
9295 int col;
9296 int off;
9297 int c;
9298 int i;
9299
9300 if (rettv_list_alloc(rettv) == FAIL)
9301 return;
9302 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9303 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9304 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9305 return;
9306
9307 off = LineOffset[row] + col;
9308 if (enc_utf8 && ScreenLinesUC[off] != 0)
9309 c = ScreenLinesUC[off];
9310 else
9311 c = ScreenLines[off];
9312 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9313
9314 if (enc_utf8)
9315
9316 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9317 list_append_number(rettv->vval.v_list,
9318 (varnumber_T)ScreenLinesC[i][off]);
9319}
9320
9321/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009322 * "screencol()" function
9323 *
9324 * First column is 1 to be consistent with virtcol().
9325 */
9326 static void
9327f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9328{
9329 rettv->vval.v_number = screen_screencol() + 1;
9330}
9331
9332/*
9333 * "screenrow()" function
9334 */
9335 static void
9336f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9337{
9338 rettv->vval.v_number = screen_screenrow() + 1;
9339}
9340
9341/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009342 * "screenstring()" function
9343 */
9344 static void
9345f_screenstring(typval_T *argvars, typval_T *rettv)
9346{
9347 int row;
9348 int col;
9349 int off;
9350 int c;
9351 int i;
9352 char_u buf[MB_MAXBYTES + 1];
9353 int buflen = 0;
9354
9355 rettv->vval.v_string = NULL;
9356 rettv->v_type = VAR_STRING;
9357
9358 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9359 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9360 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9361 return;
9362
9363 off = LineOffset[row] + col;
9364 if (enc_utf8 && ScreenLinesUC[off] != 0)
9365 c = ScreenLinesUC[off];
9366 else
9367 c = ScreenLines[off];
9368 buflen += mb_char2bytes(c, buf);
9369
9370 if (enc_utf8)
9371 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9372 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9373
9374 buf[buflen] = NUL;
9375 rettv->vval.v_string = vim_strsave(buf);
9376}
9377
9378/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009379 * "search()" function
9380 */
9381 static void
9382f_search(typval_T *argvars, typval_T *rettv)
9383{
9384 int flags = 0;
9385
9386 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9387}
9388
9389/*
9390 * "searchdecl()" function
9391 */
9392 static void
9393f_searchdecl(typval_T *argvars, typval_T *rettv)
9394{
9395 int locally = 1;
9396 int thisblock = 0;
9397 int error = FALSE;
9398 char_u *name;
9399
9400 rettv->vval.v_number = 1; /* default: FAIL */
9401
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009402 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009403 if (argvars[1].v_type != VAR_UNKNOWN)
9404 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009405 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009406 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009407 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009408 }
9409 if (!error && name != NULL)
9410 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9411 locally, thisblock, SEARCH_KEEP) == FAIL;
9412}
9413
9414/*
9415 * Used by searchpair() and searchpairpos()
9416 */
9417 static int
9418searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9419{
9420 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009421 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009422 int save_p_ws = p_ws;
9423 int dir;
9424 int flags = 0;
9425 char_u nbuf1[NUMBUFLEN];
9426 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009427 int retval = 0; /* default: FAIL */
9428 long lnum_stop = 0;
9429 long time_limit = 0;
9430
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009431 /* Get the three pattern arguments: start, middle, end. Will result in an
9432 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009433 spat = tv_get_string_chk(&argvars[0]);
9434 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9435 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009436 if (spat == NULL || mpat == NULL || epat == NULL)
9437 goto theend; /* type error */
9438
9439 /* Handle the optional fourth argument: flags */
9440 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9441 if (dir == 0)
9442 goto theend;
9443
9444 /* Don't accept SP_END or SP_SUBPAT.
9445 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9446 */
9447 if ((flags & (SP_END | SP_SUBPAT)) != 0
9448 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9449 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009450 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009451 goto theend;
9452 }
9453
9454 /* Using 'r' implies 'W', otherwise it doesn't work. */
9455 if (flags & SP_REPEAT)
9456 p_ws = FALSE;
9457
9458 /* Optional fifth argument: skip expression */
9459 if (argvars[3].v_type == VAR_UNKNOWN
9460 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009461 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009462 else
9463 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009464 skip = &argvars[4];
9465 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9466 && skip->v_type != VAR_STRING)
9467 {
9468 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009469 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009470 goto theend;
9471 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009472 if (argvars[5].v_type != VAR_UNKNOWN)
9473 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009474 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009475 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009476 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009477 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009478 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009479 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009480#ifdef FEAT_RELTIME
9481 if (argvars[6].v_type != VAR_UNKNOWN)
9482 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009483 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009484 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009485 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009486 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009488 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009489 }
9490#endif
9491 }
9492 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009493
9494 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9495 match_pos, lnum_stop, time_limit);
9496
9497theend:
9498 p_ws = save_p_ws;
9499
9500 return retval;
9501}
9502
9503/*
9504 * "searchpair()" function
9505 */
9506 static void
9507f_searchpair(typval_T *argvars, typval_T *rettv)
9508{
9509 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9510}
9511
9512/*
9513 * "searchpairpos()" function
9514 */
9515 static void
9516f_searchpairpos(typval_T *argvars, typval_T *rettv)
9517{
9518 pos_T match_pos;
9519 int lnum = 0;
9520 int col = 0;
9521
9522 if (rettv_list_alloc(rettv) == FAIL)
9523 return;
9524
9525 if (searchpair_cmn(argvars, &match_pos) > 0)
9526 {
9527 lnum = match_pos.lnum;
9528 col = match_pos.col;
9529 }
9530
9531 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9532 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9533}
9534
9535/*
9536 * Search for a start/middle/end thing.
9537 * Used by searchpair(), see its documentation for the details.
9538 * Returns 0 or -1 for no match,
9539 */
9540 long
9541do_searchpair(
9542 char_u *spat, /* start pattern */
9543 char_u *mpat, /* middle pattern */
9544 char_u *epat, /* end pattern */
9545 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009546 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009547 int flags, /* SP_SETPCMARK and other SP_ values */
9548 pos_T *match_pos,
9549 linenr_T lnum_stop, /* stop at this line if not zero */
9550 long time_limit UNUSED) /* stop after this many msec */
9551{
9552 char_u *save_cpo;
9553 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9554 long retval = 0;
9555 pos_T pos;
9556 pos_T firstpos;
9557 pos_T foundpos;
9558 pos_T save_cursor;
9559 pos_T save_pos;
9560 int n;
9561 int r;
9562 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009563 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009564 int err;
9565 int options = SEARCH_KEEP;
9566 proftime_T tm;
9567
9568 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9569 save_cpo = p_cpo;
9570 p_cpo = empty_option;
9571
9572#ifdef FEAT_RELTIME
9573 /* Set the time limit, if there is one. */
9574 profile_setlimit(time_limit, &tm);
9575#endif
9576
9577 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9578 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009579 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9580 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009581 if (pat2 == NULL || pat3 == NULL)
9582 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009583 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009584 if (*mpat == NUL)
9585 STRCPY(pat3, pat2);
9586 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009587 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009588 spat, epat, mpat);
9589 if (flags & SP_START)
9590 options |= SEARCH_START;
9591
Bram Moolenaar48570482017-10-30 21:48:41 +01009592 if (skip != NULL)
9593 {
9594 /* Empty string means to not use the skip expression. */
9595 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9596 use_skip = skip->vval.v_string != NULL
9597 && *skip->vval.v_string != NUL;
9598 }
9599
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009600 save_cursor = curwin->w_cursor;
9601 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009602 CLEAR_POS(&firstpos);
9603 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009604 pat = pat3;
9605 for (;;)
9606 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009607 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009608 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009609 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009610 /* didn't find it or found the first match again: FAIL */
9611 break;
9612
9613 if (firstpos.lnum == 0)
9614 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009615 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009616 {
9617 /* Found the same position again. Can happen with a pattern that
9618 * has "\zs" at the end and searching backwards. Advance one
9619 * character and try again. */
9620 if (dir == BACKWARD)
9621 decl(&pos);
9622 else
9623 incl(&pos);
9624 }
9625 foundpos = pos;
9626
9627 /* clear the start flag to avoid getting stuck here */
9628 options &= ~SEARCH_START;
9629
9630 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009631 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009632 {
9633 save_pos = curwin->w_cursor;
9634 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009635 err = FALSE;
9636 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009637 curwin->w_cursor = save_pos;
9638 if (err)
9639 {
9640 /* Evaluating {skip} caused an error, break here. */
9641 curwin->w_cursor = save_cursor;
9642 retval = -1;
9643 break;
9644 }
9645 if (r)
9646 continue;
9647 }
9648
9649 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9650 {
9651 /* Found end when searching backwards or start when searching
9652 * forward: nested pair. */
9653 ++nest;
9654 pat = pat2; /* nested, don't search for middle */
9655 }
9656 else
9657 {
9658 /* Found end when searching forward or start when searching
9659 * backward: end of (nested) pair; or found middle in outer pair. */
9660 if (--nest == 1)
9661 pat = pat3; /* outer level, search for middle */
9662 }
9663
9664 if (nest == 0)
9665 {
9666 /* Found the match: return matchcount or line number. */
9667 if (flags & SP_RETCOUNT)
9668 ++retval;
9669 else
9670 retval = pos.lnum;
9671 if (flags & SP_SETPCMARK)
9672 setpcmark();
9673 curwin->w_cursor = pos;
9674 if (!(flags & SP_REPEAT))
9675 break;
9676 nest = 1; /* search for next unmatched */
9677 }
9678 }
9679
9680 if (match_pos != NULL)
9681 {
9682 /* Store the match cursor position */
9683 match_pos->lnum = curwin->w_cursor.lnum;
9684 match_pos->col = curwin->w_cursor.col + 1;
9685 }
9686
9687 /* If 'n' flag is used or search failed: restore cursor position. */
9688 if ((flags & SP_NOMOVE) || retval == 0)
9689 curwin->w_cursor = save_cursor;
9690
9691theend:
9692 vim_free(pat2);
9693 vim_free(pat3);
9694 if (p_cpo == empty_option)
9695 p_cpo = save_cpo;
9696 else
9697 /* Darn, evaluating the {skip} expression changed the value. */
9698 free_string_option(save_cpo);
9699
9700 return retval;
9701}
9702
9703/*
9704 * "searchpos()" function
9705 */
9706 static void
9707f_searchpos(typval_T *argvars, typval_T *rettv)
9708{
9709 pos_T match_pos;
9710 int lnum = 0;
9711 int col = 0;
9712 int n;
9713 int flags = 0;
9714
9715 if (rettv_list_alloc(rettv) == FAIL)
9716 return;
9717
9718 n = search_cmn(argvars, &match_pos, &flags);
9719 if (n > 0)
9720 {
9721 lnum = match_pos.lnum;
9722 col = match_pos.col;
9723 }
9724
9725 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9726 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9727 if (flags & SP_SUBPAT)
9728 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9729}
9730
9731 static void
9732f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9733{
9734#ifdef FEAT_CLIENTSERVER
9735 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009736 char_u *server = tv_get_string_chk(&argvars[0]);
9737 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009738
9739 rettv->vval.v_number = -1;
9740 if (server == NULL || reply == NULL)
9741 return;
9742 if (check_restricted() || check_secure())
9743 return;
9744# ifdef FEAT_X11
9745 if (check_connection() == FAIL)
9746 return;
9747# endif
9748
9749 if (serverSendReply(server, reply) < 0)
9750 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009751 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009752 return;
9753 }
9754 rettv->vval.v_number = 0;
9755#else
9756 rettv->vval.v_number = -1;
9757#endif
9758}
9759
9760 static void
9761f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9762{
9763 char_u *r = NULL;
9764
9765#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009766# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009767 r = serverGetVimNames();
9768# else
9769 make_connection();
9770 if (X_DISPLAY != NULL)
9771 r = serverGetVimNames(X_DISPLAY);
9772# endif
9773#endif
9774 rettv->v_type = VAR_STRING;
9775 rettv->vval.v_string = r;
9776}
9777
9778/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009779 * "setbufline()" function
9780 */
9781 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009782f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009783{
9784 linenr_T lnum;
9785 buf_T *buf;
9786
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009787 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009788 if (buf == NULL)
9789 rettv->vval.v_number = 1; /* FAIL */
9790 else
9791 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009792 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009793 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009794 }
9795}
9796
9797/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009798 * "setbufvar()" function
9799 */
9800 static void
9801f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9802{
9803 buf_T *buf;
9804 char_u *varname, *bufvarname;
9805 typval_T *varp;
9806 char_u nbuf[NUMBUFLEN];
9807
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009808 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009810 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
9811 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009812 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009813 varp = &argvars[2];
9814
9815 if (buf != NULL && varname != NULL && varp != NULL)
9816 {
9817 if (*varname == '&')
9818 {
9819 long numval;
9820 char_u *strval;
9821 int error = FALSE;
9822 aco_save_T aco;
9823
9824 /* set curbuf to be our buf, temporarily */
9825 aucmd_prepbuf(&aco, buf);
9826
9827 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009828 numval = (long)tv_get_number_chk(varp, &error);
9829 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009830 if (!error && strval != NULL)
9831 set_option_value(varname, numval, strval, OPT_LOCAL);
9832
9833 /* reset notion of buffer */
9834 aucmd_restbuf(&aco);
9835 }
9836 else
9837 {
9838 buf_T *save_curbuf = curbuf;
9839
Bram Moolenaar964b3742019-05-24 18:54:09 +02009840 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009841 if (bufvarname != NULL)
9842 {
9843 curbuf = buf;
9844 STRCPY(bufvarname, "b:");
9845 STRCPY(bufvarname + 2, varname);
9846 set_var(bufvarname, varp, TRUE);
9847 vim_free(bufvarname);
9848 curbuf = save_curbuf;
9849 }
9850 }
9851 }
9852}
9853
9854 static void
9855f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9856{
9857 dict_T *d;
9858 dictitem_T *di;
9859 char_u *csearch;
9860
9861 if (argvars[0].v_type != VAR_DICT)
9862 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009863 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009864 return;
9865 }
9866
9867 if ((d = argvars[0].vval.v_dict) != NULL)
9868 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009869 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009870 if (csearch != NULL)
9871 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009872 if (enc_utf8)
9873 {
9874 int pcc[MAX_MCO];
9875 int c = utfc_ptr2char(csearch, pcc);
9876
9877 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9878 }
9879 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009880 set_last_csearch(PTR2CHAR(csearch),
9881 csearch, MB_PTR2LEN(csearch));
9882 }
9883
9884 di = dict_find(d, (char_u *)"forward", -1);
9885 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009886 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009887 ? FORWARD : BACKWARD);
9888
9889 di = dict_find(d, (char_u *)"until", -1);
9890 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009891 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009892 }
9893}
9894
9895/*
9896 * "setcmdpos()" function
9897 */
9898 static void
9899f_setcmdpos(typval_T *argvars, typval_T *rettv)
9900{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009901 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009902
9903 if (pos >= 0)
9904 rettv->vval.v_number = set_cmdline_pos(pos);
9905}
9906
9907/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02009908 * "setenv()" function
9909 */
9910 static void
9911f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
9912{
9913 char_u namebuf[NUMBUFLEN];
9914 char_u valbuf[NUMBUFLEN];
9915 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
9916
9917 if (argvars[1].v_type == VAR_SPECIAL
9918 && argvars[1].vval.v_number == VVAL_NULL)
9919 vim_unsetenv(name);
9920 else
9921 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
9922}
9923
9924/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009925 * "setfperm({fname}, {mode})" function
9926 */
9927 static void
9928f_setfperm(typval_T *argvars, typval_T *rettv)
9929{
9930 char_u *fname;
9931 char_u modebuf[NUMBUFLEN];
9932 char_u *mode_str;
9933 int i;
9934 int mask;
9935 int mode = 0;
9936
9937 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009938 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009939 if (fname == NULL)
9940 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009941 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009942 if (mode_str == NULL)
9943 return;
9944 if (STRLEN(mode_str) != 9)
9945 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009946 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009947 return;
9948 }
9949
9950 mask = 1;
9951 for (i = 8; i >= 0; --i)
9952 {
9953 if (mode_str[i] != '-')
9954 mode |= mask;
9955 mask = mask << 1;
9956 }
9957 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9958}
9959
9960/*
9961 * "setline()" function
9962 */
9963 static void
9964f_setline(typval_T *argvars, typval_T *rettv)
9965{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009966 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009967
Bram Moolenaarca851592018-06-06 21:04:07 +02009968 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009969}
9970
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009971/*
9972 * Used by "setqflist()" and "setloclist()" functions
9973 */
9974 static void
9975set_qf_ll_list(
9976 win_T *wp UNUSED,
9977 typval_T *list_arg UNUSED,
9978 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +02009979 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009980 typval_T *rettv)
9981{
9982#ifdef FEAT_QUICKFIX
9983 static char *e_invact = N_("E927: Invalid action: '%s'");
9984 char_u *act;
9985 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009986 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009987#endif
9988
9989 rettv->vval.v_number = -1;
9990
9991#ifdef FEAT_QUICKFIX
9992 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009993 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009994 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009995 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009996 else
9997 {
9998 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +02009999 dict_T *d = NULL;
10000 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010001
10002 if (action_arg->v_type == VAR_STRING)
10003 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010004 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010005 if (act == NULL)
10006 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010007 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10008 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010009 action = *act;
10010 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010011 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010012 }
10013 else if (action_arg->v_type == VAR_UNKNOWN)
10014 action = ' ';
10015 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010016 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010017
Bram Moolenaard823fa92016-08-12 16:29:27 +020010018 if (action_arg->v_type != VAR_UNKNOWN
10019 && what_arg->v_type != VAR_UNKNOWN)
10020 {
10021 if (what_arg->v_type == VAR_DICT)
10022 d = what_arg->vval.v_dict;
10023 else
10024 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010025 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010026 valid_dict = FALSE;
10027 }
10028 }
10029
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010030 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010031 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010032 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10033 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010034 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010035 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010036 }
10037#endif
10038}
10039
10040/*
10041 * "setloclist()" function
10042 */
10043 static void
10044f_setloclist(typval_T *argvars, typval_T *rettv)
10045{
10046 win_T *win;
10047
10048 rettv->vval.v_number = -1;
10049
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010050 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010051 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010052 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010053}
10054
10055/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010056 * "setpos()" function
10057 */
10058 static void
10059f_setpos(typval_T *argvars, typval_T *rettv)
10060{
10061 pos_T pos;
10062 int fnum;
10063 char_u *name;
10064 colnr_T curswant = -1;
10065
10066 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010067 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010068 if (name != NULL)
10069 {
10070 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10071 {
10072 if (--pos.col < 0)
10073 pos.col = 0;
10074 if (name[0] == '.' && name[1] == NUL)
10075 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010076 /* set cursor; "fnum" is ignored */
10077 curwin->w_cursor = pos;
10078 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010079 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010080 curwin->w_curswant = curswant - 1;
10081 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010082 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010083 check_cursor();
10084 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010085 }
10086 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10087 {
10088 /* set mark */
10089 if (setmark_pos(name[1], &pos, fnum) == OK)
10090 rettv->vval.v_number = 0;
10091 }
10092 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010093 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010094 }
10095 }
10096}
10097
10098/*
10099 * "setqflist()" function
10100 */
10101 static void
10102f_setqflist(typval_T *argvars, typval_T *rettv)
10103{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010104 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010105}
10106
10107/*
10108 * "setreg()" function
10109 */
10110 static void
10111f_setreg(typval_T *argvars, typval_T *rettv)
10112{
10113 int regname;
10114 char_u *strregname;
10115 char_u *stropt;
10116 char_u *strval;
10117 int append;
10118 char_u yank_type;
10119 long block_len;
10120
10121 block_len = -1;
10122 yank_type = MAUTO;
10123 append = FALSE;
10124
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010125 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010126 rettv->vval.v_number = 1; /* FAIL is default */
10127
10128 if (strregname == NULL)
10129 return; /* type error; errmsg already given */
10130 regname = *strregname;
10131 if (regname == 0 || regname == '@')
10132 regname = '"';
10133
10134 if (argvars[2].v_type != VAR_UNKNOWN)
10135 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010136 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010137 if (stropt == NULL)
10138 return; /* type error */
10139 for (; *stropt != NUL; ++stropt)
10140 switch (*stropt)
10141 {
10142 case 'a': case 'A': /* append */
10143 append = TRUE;
10144 break;
10145 case 'v': case 'c': /* character-wise selection */
10146 yank_type = MCHAR;
10147 break;
10148 case 'V': case 'l': /* line-wise selection */
10149 yank_type = MLINE;
10150 break;
10151 case 'b': case Ctrl_V: /* block-wise selection */
10152 yank_type = MBLOCK;
10153 if (VIM_ISDIGIT(stropt[1]))
10154 {
10155 ++stropt;
10156 block_len = getdigits(&stropt) - 1;
10157 --stropt;
10158 }
10159 break;
10160 }
10161 }
10162
10163 if (argvars[1].v_type == VAR_LIST)
10164 {
10165 char_u **lstval;
10166 char_u **allocval;
10167 char_u buf[NUMBUFLEN];
10168 char_u **curval;
10169 char_u **curallocval;
10170 list_T *ll = argvars[1].vval.v_list;
10171 listitem_T *li;
10172 int len;
10173
10174 /* If the list is NULL handle like an empty list. */
10175 len = ll == NULL ? 0 : ll->lv_len;
10176
10177 /* First half: use for pointers to result lines; second half: use for
10178 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010179 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010180 if (lstval == NULL)
10181 return;
10182 curval = lstval;
10183 allocval = lstval + len + 2;
10184 curallocval = allocval;
10185
10186 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10187 li = li->li_next)
10188 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010189 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010190 if (strval == NULL)
10191 goto free_lstval;
10192 if (strval == buf)
10193 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010194 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010195 * overwrite the string. */
10196 strval = vim_strsave(buf);
10197 if (strval == NULL)
10198 goto free_lstval;
10199 *curallocval++ = strval;
10200 }
10201 *curval++ = strval;
10202 }
10203 *curval++ = NULL;
10204
10205 write_reg_contents_lst(regname, lstval, -1,
10206 append, yank_type, block_len);
10207free_lstval:
10208 while (curallocval > allocval)
10209 vim_free(*--curallocval);
10210 vim_free(lstval);
10211 }
10212 else
10213 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010214 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010215 if (strval == NULL)
10216 return;
10217 write_reg_contents_ex(regname, strval, -1,
10218 append, yank_type, block_len);
10219 }
10220 rettv->vval.v_number = 0;
10221}
10222
10223/*
10224 * "settabvar()" function
10225 */
10226 static void
10227f_settabvar(typval_T *argvars, typval_T *rettv)
10228{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010229 tabpage_T *save_curtab;
10230 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010231 char_u *varname, *tabvarname;
10232 typval_T *varp;
10233
10234 rettv->vval.v_number = 0;
10235
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010236 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010237 return;
10238
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010239 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10240 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010241 varp = &argvars[2];
10242
Bram Moolenaar4033c552017-09-16 20:54:51 +020010243 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010245 save_curtab = curtab;
10246 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010247
Bram Moolenaar964b3742019-05-24 18:54:09 +020010248 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010249 if (tabvarname != NULL)
10250 {
10251 STRCPY(tabvarname, "t:");
10252 STRCPY(tabvarname + 2, varname);
10253 set_var(tabvarname, varp, TRUE);
10254 vim_free(tabvarname);
10255 }
10256
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010257 /* Restore current tabpage */
10258 if (valid_tabpage(save_curtab))
10259 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010260 }
10261}
10262
10263/*
10264 * "settabwinvar()" function
10265 */
10266 static void
10267f_settabwinvar(typval_T *argvars, typval_T *rettv)
10268{
10269 setwinvar(argvars, rettv, 1);
10270}
10271
10272/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010273 * "settagstack()" function
10274 */
10275 static void
10276f_settagstack(typval_T *argvars, typval_T *rettv)
10277{
10278 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10279 win_T *wp;
10280 dict_T *d;
10281 int action = 'r';
10282
10283 rettv->vval.v_number = -1;
10284
10285 // first argument: window number or id
10286 wp = find_win_by_nr_or_id(&argvars[0]);
10287 if (wp == NULL)
10288 return;
10289
10290 // second argument: dict with items to set in the tag stack
10291 if (argvars[1].v_type != VAR_DICT)
10292 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010293 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010294 return;
10295 }
10296 d = argvars[1].vval.v_dict;
10297 if (d == NULL)
10298 return;
10299
10300 // third argument: action - 'a' for append and 'r' for replace.
10301 // default is to replace the stack.
10302 if (argvars[2].v_type == VAR_UNKNOWN)
10303 action = 'r';
10304 else if (argvars[2].v_type == VAR_STRING)
10305 {
10306 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010307 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010308 if (actstr == NULL)
10309 return;
10310 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10311 action = *actstr;
10312 else
10313 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010314 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010315 return;
10316 }
10317 }
10318 else
10319 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010320 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010321 return;
10322 }
10323
10324 if (set_tagstack(wp, d, action) == OK)
10325 rettv->vval.v_number = 0;
10326}
10327
10328/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010329 * "setwinvar()" function
10330 */
10331 static void
10332f_setwinvar(typval_T *argvars, typval_T *rettv)
10333{
10334 setwinvar(argvars, rettv, 0);
10335}
10336
10337#ifdef FEAT_CRYPT
10338/*
10339 * "sha256({string})" function
10340 */
10341 static void
10342f_sha256(typval_T *argvars, typval_T *rettv)
10343{
10344 char_u *p;
10345
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010346 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010347 rettv->vval.v_string = vim_strsave(
10348 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10349 rettv->v_type = VAR_STRING;
10350}
10351#endif /* FEAT_CRYPT */
10352
10353/*
10354 * "shellescape({string})" function
10355 */
10356 static void
10357f_shellescape(typval_T *argvars, typval_T *rettv)
10358{
Bram Moolenaar20615522017-06-05 18:46:26 +020010359 int do_special = non_zero_arg(&argvars[1]);
10360
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010361 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010362 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010363 rettv->v_type = VAR_STRING;
10364}
10365
10366/*
10367 * shiftwidth() function
10368 */
10369 static void
10370f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10371{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010372 rettv->vval.v_number = 0;
10373
10374 if (argvars[0].v_type != VAR_UNKNOWN)
10375 {
10376 long col;
10377
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010378 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010379 if (col < 0)
10380 return; // type error; errmsg already given
10381#ifdef FEAT_VARTABS
10382 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10383 return;
10384#endif
10385 }
10386
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010387 rettv->vval.v_number = get_sw_value(curbuf);
10388}
10389
10390/*
10391 * "simplify()" function
10392 */
10393 static void
10394f_simplify(typval_T *argvars, typval_T *rettv)
10395{
10396 char_u *p;
10397
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010398 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010399 rettv->vval.v_string = vim_strsave(p);
10400 simplify_filename(rettv->vval.v_string); /* simplify in place */
10401 rettv->v_type = VAR_STRING;
10402}
10403
10404#ifdef FEAT_FLOAT
10405/*
10406 * "sin()" function
10407 */
10408 static void
10409f_sin(typval_T *argvars, typval_T *rettv)
10410{
10411 float_T f = 0.0;
10412
10413 rettv->v_type = VAR_FLOAT;
10414 if (get_float_arg(argvars, &f) == OK)
10415 rettv->vval.v_float = sin(f);
10416 else
10417 rettv->vval.v_float = 0.0;
10418}
10419
10420/*
10421 * "sinh()" function
10422 */
10423 static void
10424f_sinh(typval_T *argvars, typval_T *rettv)
10425{
10426 float_T f = 0.0;
10427
10428 rettv->v_type = VAR_FLOAT;
10429 if (get_float_arg(argvars, &f) == OK)
10430 rettv->vval.v_float = sinh(f);
10431 else
10432 rettv->vval.v_float = 0.0;
10433}
10434#endif
10435
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010436/*
10437 * "soundfold({word})" function
10438 */
10439 static void
10440f_soundfold(typval_T *argvars, typval_T *rettv)
10441{
10442 char_u *s;
10443
10444 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010445 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010446#ifdef FEAT_SPELL
10447 rettv->vval.v_string = eval_soundfold(s);
10448#else
10449 rettv->vval.v_string = vim_strsave(s);
10450#endif
10451}
10452
10453/*
10454 * "spellbadword()" function
10455 */
10456 static void
10457f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10458{
10459 char_u *word = (char_u *)"";
10460 hlf_T attr = HLF_COUNT;
10461 int len = 0;
10462
10463 if (rettv_list_alloc(rettv) == FAIL)
10464 return;
10465
10466#ifdef FEAT_SPELL
10467 if (argvars[0].v_type == VAR_UNKNOWN)
10468 {
10469 /* Find the start and length of the badly spelled word. */
10470 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10471 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010472 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010473 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010474 curwin->w_set_curswant = TRUE;
10475 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010476 }
10477 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10478 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010479 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010480 int capcol = -1;
10481
10482 if (str != NULL)
10483 {
10484 /* Check the argument for spelling. */
10485 while (*str != NUL)
10486 {
10487 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10488 if (attr != HLF_COUNT)
10489 {
10490 word = str;
10491 break;
10492 }
10493 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010494 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010495 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010496 }
10497 }
10498 }
10499#endif
10500
10501 list_append_string(rettv->vval.v_list, word, len);
10502 list_append_string(rettv->vval.v_list, (char_u *)(
10503 attr == HLF_SPB ? "bad" :
10504 attr == HLF_SPR ? "rare" :
10505 attr == HLF_SPL ? "local" :
10506 attr == HLF_SPC ? "caps" :
10507 ""), -1);
10508}
10509
10510/*
10511 * "spellsuggest()" function
10512 */
10513 static void
10514f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10515{
10516#ifdef FEAT_SPELL
10517 char_u *str;
10518 int typeerr = FALSE;
10519 int maxcount;
10520 garray_T ga;
10521 int i;
10522 listitem_T *li;
10523 int need_capital = FALSE;
10524#endif
10525
10526 if (rettv_list_alloc(rettv) == FAIL)
10527 return;
10528
10529#ifdef FEAT_SPELL
10530 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10531 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010532 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010533 if (argvars[1].v_type != VAR_UNKNOWN)
10534 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010535 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010536 if (maxcount <= 0)
10537 return;
10538 if (argvars[2].v_type != VAR_UNKNOWN)
10539 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010540 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010541 if (typeerr)
10542 return;
10543 }
10544 }
10545 else
10546 maxcount = 25;
10547
10548 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10549
10550 for (i = 0; i < ga.ga_len; ++i)
10551 {
10552 str = ((char_u **)ga.ga_data)[i];
10553
10554 li = listitem_alloc();
10555 if (li == NULL)
10556 vim_free(str);
10557 else
10558 {
10559 li->li_tv.v_type = VAR_STRING;
10560 li->li_tv.v_lock = 0;
10561 li->li_tv.vval.v_string = str;
10562 list_append(rettv->vval.v_list, li);
10563 }
10564 }
10565 ga_clear(&ga);
10566 }
10567#endif
10568}
10569
10570 static void
10571f_split(typval_T *argvars, typval_T *rettv)
10572{
10573 char_u *str;
10574 char_u *end;
10575 char_u *pat = NULL;
10576 regmatch_T regmatch;
10577 char_u patbuf[NUMBUFLEN];
10578 char_u *save_cpo;
10579 int match;
10580 colnr_T col = 0;
10581 int keepempty = FALSE;
10582 int typeerr = FALSE;
10583
10584 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10585 save_cpo = p_cpo;
10586 p_cpo = (char_u *)"";
10587
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010588 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010589 if (argvars[1].v_type != VAR_UNKNOWN)
10590 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010591 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010592 if (pat == NULL)
10593 typeerr = TRUE;
10594 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010595 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010596 }
10597 if (pat == NULL || *pat == NUL)
10598 pat = (char_u *)"[\\x01- ]\\+";
10599
10600 if (rettv_list_alloc(rettv) == FAIL)
10601 return;
10602 if (typeerr)
10603 return;
10604
10605 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10606 if (regmatch.regprog != NULL)
10607 {
10608 regmatch.rm_ic = FALSE;
10609 while (*str != NUL || keepempty)
10610 {
10611 if (*str == NUL)
10612 match = FALSE; /* empty item at the end */
10613 else
10614 match = vim_regexec_nl(&regmatch, str, col);
10615 if (match)
10616 end = regmatch.startp[0];
10617 else
10618 end = str + STRLEN(str);
10619 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10620 && *str != NUL && match && end < regmatch.endp[0]))
10621 {
10622 if (list_append_string(rettv->vval.v_list, str,
10623 (int)(end - str)) == FAIL)
10624 break;
10625 }
10626 if (!match)
10627 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010628 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010629 if (regmatch.endp[0] > str)
10630 col = 0;
10631 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010632 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010633 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010634 str = regmatch.endp[0];
10635 }
10636
10637 vim_regfree(regmatch.regprog);
10638 }
10639
10640 p_cpo = save_cpo;
10641}
10642
10643#ifdef FEAT_FLOAT
10644/*
10645 * "sqrt()" function
10646 */
10647 static void
10648f_sqrt(typval_T *argvars, typval_T *rettv)
10649{
10650 float_T f = 0.0;
10651
10652 rettv->v_type = VAR_FLOAT;
10653 if (get_float_arg(argvars, &f) == OK)
10654 rettv->vval.v_float = sqrt(f);
10655 else
10656 rettv->vval.v_float = 0.0;
10657}
10658
10659/*
10660 * "str2float()" function
10661 */
10662 static void
10663f_str2float(typval_T *argvars, typval_T *rettv)
10664{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010665 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010666 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010667
Bram Moolenaar08243d22017-01-10 16:12:29 +010010668 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010669 p = skipwhite(p + 1);
10670 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010671 if (isneg)
10672 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010673 rettv->v_type = VAR_FLOAT;
10674}
10675#endif
10676
10677/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010678 * "str2list()" function
10679 */
10680 static void
10681f_str2list(typval_T *argvars, typval_T *rettv)
10682{
10683 char_u *p;
10684 int utf8 = FALSE;
10685
10686 if (rettv_list_alloc(rettv) == FAIL)
10687 return;
10688
10689 if (argvars[1].v_type != VAR_UNKNOWN)
10690 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10691
10692 p = tv_get_string(&argvars[0]);
10693
10694 if (has_mbyte || utf8)
10695 {
10696 int (*ptr2len)(char_u *);
10697 int (*ptr2char)(char_u *);
10698
10699 if (utf8 || enc_utf8)
10700 {
10701 ptr2len = utf_ptr2len;
10702 ptr2char = utf_ptr2char;
10703 }
10704 else
10705 {
10706 ptr2len = mb_ptr2len;
10707 ptr2char = mb_ptr2char;
10708 }
10709
10710 for ( ; *p != NUL; p += (*ptr2len)(p))
10711 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10712 }
10713 else
10714 for ( ; *p != NUL; ++p)
10715 list_append_number(rettv->vval.v_list, *p);
10716}
10717
10718/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010719 * "str2nr()" function
10720 */
10721 static void
10722f_str2nr(typval_T *argvars, typval_T *rettv)
10723{
10724 int base = 10;
10725 char_u *p;
10726 varnumber_T n;
10727 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010728 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010729
10730 if (argvars[1].v_type != VAR_UNKNOWN)
10731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010732 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010733 if (base != 2 && base != 8 && base != 10 && base != 16)
10734 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010735 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010736 return;
10737 }
10738 }
10739
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010740 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010741 isneg = (*p == '-');
10742 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010743 p = skipwhite(p + 1);
10744 switch (base)
10745 {
10746 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10747 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10748 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10749 default: what = 0;
10750 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010751 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10752 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010753 if (isneg)
10754 rettv->vval.v_number = -n;
10755 else
10756 rettv->vval.v_number = n;
10757
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010758}
10759
10760#ifdef HAVE_STRFTIME
10761/*
10762 * "strftime({format}[, {time}])" function
10763 */
10764 static void
10765f_strftime(typval_T *argvars, typval_T *rettv)
10766{
10767 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010768 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010769 struct tm *curtime;
10770 time_t seconds;
10771 char_u *p;
10772
10773 rettv->v_type = VAR_STRING;
10774
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010775 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010776 if (argvars[1].v_type == VAR_UNKNOWN)
10777 seconds = time(NULL);
10778 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010779 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010780 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010781 /* MSVC returns NULL for an invalid value of seconds. */
10782 if (curtime == NULL)
10783 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10784 else
10785 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010786 vimconv_T conv;
10787 char_u *enc;
10788
10789 conv.vc_type = CONV_NONE;
10790 enc = enc_locale();
10791 convert_setup(&conv, p_enc, enc);
10792 if (conv.vc_type != CONV_NONE)
10793 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010794 if (p != NULL)
10795 (void)strftime((char *)result_buf, sizeof(result_buf),
10796 (char *)p, curtime);
10797 else
10798 result_buf[0] = NUL;
10799
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010800 if (conv.vc_type != CONV_NONE)
10801 vim_free(p);
10802 convert_setup(&conv, enc, p_enc);
10803 if (conv.vc_type != CONV_NONE)
10804 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10805 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010806 rettv->vval.v_string = vim_strsave(result_buf);
10807
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010808 /* Release conversion descriptors */
10809 convert_setup(&conv, NULL, NULL);
10810 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010811 }
10812}
10813#endif
10814
10815/*
10816 * "strgetchar()" function
10817 */
10818 static void
10819f_strgetchar(typval_T *argvars, typval_T *rettv)
10820{
10821 char_u *str;
10822 int len;
10823 int error = FALSE;
10824 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010010825 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010826
10827 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010828 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010829 if (str == NULL)
10830 return;
10831 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010832 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010833 if (error)
10834 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010835
Bram Moolenaar13505972019-01-24 15:04:48 +010010836 while (charidx >= 0 && byteidx < len)
10837 {
10838 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010839 {
Bram Moolenaar13505972019-01-24 15:04:48 +010010840 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10841 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010842 }
Bram Moolenaar13505972019-01-24 15:04:48 +010010843 --charidx;
10844 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010845 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010846}
10847
10848/*
10849 * "stridx()" function
10850 */
10851 static void
10852f_stridx(typval_T *argvars, typval_T *rettv)
10853{
10854 char_u buf[NUMBUFLEN];
10855 char_u *needle;
10856 char_u *haystack;
10857 char_u *save_haystack;
10858 char_u *pos;
10859 int start_idx;
10860
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010861 needle = tv_get_string_chk(&argvars[1]);
10862 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010863 rettv->vval.v_number = -1;
10864 if (needle == NULL || haystack == NULL)
10865 return; /* type error; errmsg already given */
10866
10867 if (argvars[2].v_type != VAR_UNKNOWN)
10868 {
10869 int error = FALSE;
10870
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010871 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010872 if (error || start_idx >= (int)STRLEN(haystack))
10873 return;
10874 if (start_idx >= 0)
10875 haystack += start_idx;
10876 }
10877
10878 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10879 if (pos != NULL)
10880 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10881}
10882
10883/*
10884 * "string()" function
10885 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010010886 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010887f_string(typval_T *argvars, typval_T *rettv)
10888{
10889 char_u *tofree;
10890 char_u numbuf[NUMBUFLEN];
10891
10892 rettv->v_type = VAR_STRING;
10893 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10894 get_copyID());
10895 /* Make a copy if we have a value but it's not in allocated memory. */
10896 if (rettv->vval.v_string != NULL && tofree == NULL)
10897 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10898}
10899
10900/*
10901 * "strlen()" function
10902 */
10903 static void
10904f_strlen(typval_T *argvars, typval_T *rettv)
10905{
10906 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010907 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010908}
10909
10910/*
10911 * "strchars()" function
10912 */
10913 static void
10914f_strchars(typval_T *argvars, typval_T *rettv)
10915{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010916 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010917 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010918 varnumber_T len = 0;
10919 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010920
10921 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010922 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010923 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010924 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010925 else
10926 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010927 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10928 while (*s != NUL)
10929 {
10930 func_mb_ptr2char_adv(&s);
10931 ++len;
10932 }
10933 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010934 }
10935}
10936
10937/*
10938 * "strdisplaywidth()" function
10939 */
10940 static void
10941f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10942{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010943 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010944 int col = 0;
10945
10946 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010947 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010948
10949 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10950}
10951
10952/*
10953 * "strwidth()" function
10954 */
10955 static void
10956f_strwidth(typval_T *argvars, typval_T *rettv)
10957{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010958 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010959
Bram Moolenaar13505972019-01-24 15:04:48 +010010960 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010961}
10962
10963/*
10964 * "strcharpart()" function
10965 */
10966 static void
10967f_strcharpart(typval_T *argvars, typval_T *rettv)
10968{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010969 char_u *p;
10970 int nchar;
10971 int nbyte = 0;
10972 int charlen;
10973 int len = 0;
10974 int slen;
10975 int error = FALSE;
10976
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010977 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010978 slen = (int)STRLEN(p);
10979
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010980 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010981 if (!error)
10982 {
10983 if (nchar > 0)
10984 while (nchar > 0 && nbyte < slen)
10985 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010986 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010987 --nchar;
10988 }
10989 else
10990 nbyte = nchar;
10991 if (argvars[2].v_type != VAR_UNKNOWN)
10992 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010993 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010994 while (charlen > 0 && nbyte + len < slen)
10995 {
10996 int off = nbyte + len;
10997
10998 if (off < 0)
10999 len += 1;
11000 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011001 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011002 --charlen;
11003 }
11004 }
11005 else
11006 len = slen - nbyte; /* default: all bytes that are available. */
11007 }
11008
11009 /*
11010 * Only return the overlap between the specified part and the actual
11011 * string.
11012 */
11013 if (nbyte < 0)
11014 {
11015 len += nbyte;
11016 nbyte = 0;
11017 }
11018 else if (nbyte > slen)
11019 nbyte = slen;
11020 if (len < 0)
11021 len = 0;
11022 else if (nbyte + len > slen)
11023 len = slen - nbyte;
11024
11025 rettv->v_type = VAR_STRING;
11026 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011027}
11028
11029/*
11030 * "strpart()" function
11031 */
11032 static void
11033f_strpart(typval_T *argvars, typval_T *rettv)
11034{
11035 char_u *p;
11036 int n;
11037 int len;
11038 int slen;
11039 int error = FALSE;
11040
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011041 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011042 slen = (int)STRLEN(p);
11043
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011044 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011045 if (error)
11046 len = 0;
11047 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011048 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011049 else
11050 len = slen - n; /* default len: all bytes that are available. */
11051
11052 /*
11053 * Only return the overlap between the specified part and the actual
11054 * string.
11055 */
11056 if (n < 0)
11057 {
11058 len += n;
11059 n = 0;
11060 }
11061 else if (n > slen)
11062 n = slen;
11063 if (len < 0)
11064 len = 0;
11065 else if (n + len > slen)
11066 len = slen - n;
11067
11068 rettv->v_type = VAR_STRING;
11069 rettv->vval.v_string = vim_strnsave(p + n, len);
11070}
11071
11072/*
11073 * "strridx()" function
11074 */
11075 static void
11076f_strridx(typval_T *argvars, typval_T *rettv)
11077{
11078 char_u buf[NUMBUFLEN];
11079 char_u *needle;
11080 char_u *haystack;
11081 char_u *rest;
11082 char_u *lastmatch = NULL;
11083 int haystack_len, end_idx;
11084
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011085 needle = tv_get_string_chk(&argvars[1]);
11086 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011087
11088 rettv->vval.v_number = -1;
11089 if (needle == NULL || haystack == NULL)
11090 return; /* type error; errmsg already given */
11091
11092 haystack_len = (int)STRLEN(haystack);
11093 if (argvars[2].v_type != VAR_UNKNOWN)
11094 {
11095 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011096 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011097 if (end_idx < 0)
11098 return; /* can never find a match */
11099 }
11100 else
11101 end_idx = haystack_len;
11102
11103 if (*needle == NUL)
11104 {
11105 /* Empty string matches past the end. */
11106 lastmatch = haystack + end_idx;
11107 }
11108 else
11109 {
11110 for (rest = haystack; *rest != '\0'; ++rest)
11111 {
11112 rest = (char_u *)strstr((char *)rest, (char *)needle);
11113 if (rest == NULL || rest > haystack + end_idx)
11114 break;
11115 lastmatch = rest;
11116 }
11117 }
11118
11119 if (lastmatch == NULL)
11120 rettv->vval.v_number = -1;
11121 else
11122 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11123}
11124
11125/*
11126 * "strtrans()" function
11127 */
11128 static void
11129f_strtrans(typval_T *argvars, typval_T *rettv)
11130{
11131 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011132 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011133}
11134
11135/*
11136 * "submatch()" function
11137 */
11138 static void
11139f_submatch(typval_T *argvars, typval_T *rettv)
11140{
11141 int error = FALSE;
11142 int no;
11143 int retList = 0;
11144
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011145 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011146 if (error)
11147 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011148 if (no < 0 || no >= NSUBEXP)
11149 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011150 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011151 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011152 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011153 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011154 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011155 if (error)
11156 return;
11157
11158 if (retList == 0)
11159 {
11160 rettv->v_type = VAR_STRING;
11161 rettv->vval.v_string = reg_submatch(no);
11162 }
11163 else
11164 {
11165 rettv->v_type = VAR_LIST;
11166 rettv->vval.v_list = reg_submatch_list(no);
11167 }
11168}
11169
11170/*
11171 * "substitute()" function
11172 */
11173 static void
11174f_substitute(typval_T *argvars, typval_T *rettv)
11175{
11176 char_u patbuf[NUMBUFLEN];
11177 char_u subbuf[NUMBUFLEN];
11178 char_u flagsbuf[NUMBUFLEN];
11179
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011180 char_u *str = tv_get_string_chk(&argvars[0]);
11181 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011182 char_u *sub = NULL;
11183 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011184 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011185
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011186 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11187 expr = &argvars[2];
11188 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011189 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011190
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011191 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011192 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11193 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011194 rettv->vval.v_string = NULL;
11195 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011196 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011197}
11198
11199/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011200 * "swapinfo(swap_filename)" function
11201 */
11202 static void
11203f_swapinfo(typval_T *argvars, typval_T *rettv)
11204{
11205 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011206 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011207}
11208
11209/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011210 * "swapname(expr)" function
11211 */
11212 static void
11213f_swapname(typval_T *argvars, typval_T *rettv)
11214{
11215 buf_T *buf;
11216
11217 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011218 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011219 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11220 || buf->b_ml.ml_mfp->mf_fname == NULL)
11221 rettv->vval.v_string = NULL;
11222 else
11223 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11224}
11225
11226/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011227 * "synID(lnum, col, trans)" function
11228 */
11229 static void
11230f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11231{
11232 int id = 0;
11233#ifdef FEAT_SYN_HL
11234 linenr_T lnum;
11235 colnr_T col;
11236 int trans;
11237 int transerr = FALSE;
11238
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011239 lnum = tv_get_lnum(argvars); /* -1 on type error */
11240 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11241 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011242
11243 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11244 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11245 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11246#endif
11247
11248 rettv->vval.v_number = id;
11249}
11250
11251/*
11252 * "synIDattr(id, what [, mode])" function
11253 */
11254 static void
11255f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11256{
11257 char_u *p = NULL;
11258#ifdef FEAT_SYN_HL
11259 int id;
11260 char_u *what;
11261 char_u *mode;
11262 char_u modebuf[NUMBUFLEN];
11263 int modec;
11264
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011265 id = (int)tv_get_number(&argvars[0]);
11266 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011267 if (argvars[2].v_type != VAR_UNKNOWN)
11268 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011269 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011270 modec = TOLOWER_ASC(mode[0]);
11271 if (modec != 't' && modec != 'c' && modec != 'g')
11272 modec = 0; /* replace invalid with current */
11273 }
11274 else
11275 {
11276#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11277 if (USE_24BIT)
11278 modec = 'g';
11279 else
11280#endif
11281 if (t_colors > 1)
11282 modec = 'c';
11283 else
11284 modec = 't';
11285 }
11286
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011287 switch (TOLOWER_ASC(what[0]))
11288 {
11289 case 'b':
11290 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11291 p = highlight_color(id, what, modec);
11292 else /* bold */
11293 p = highlight_has_attr(id, HL_BOLD, modec);
11294 break;
11295
11296 case 'f': /* fg[#] or font */
11297 p = highlight_color(id, what, modec);
11298 break;
11299
11300 case 'i':
11301 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11302 p = highlight_has_attr(id, HL_INVERSE, modec);
11303 else /* italic */
11304 p = highlight_has_attr(id, HL_ITALIC, modec);
11305 break;
11306
11307 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011308 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011309 break;
11310
11311 case 'r': /* reverse */
11312 p = highlight_has_attr(id, HL_INVERSE, modec);
11313 break;
11314
11315 case 's':
11316 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11317 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011318 /* strikeout */
11319 else if (TOLOWER_ASC(what[1]) == 't' &&
11320 TOLOWER_ASC(what[2]) == 'r')
11321 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011322 else /* standout */
11323 p = highlight_has_attr(id, HL_STANDOUT, modec);
11324 break;
11325
11326 case 'u':
11327 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11328 /* underline */
11329 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11330 else
11331 /* undercurl */
11332 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11333 break;
11334 }
11335
11336 if (p != NULL)
11337 p = vim_strsave(p);
11338#endif
11339 rettv->v_type = VAR_STRING;
11340 rettv->vval.v_string = p;
11341}
11342
11343/*
11344 * "synIDtrans(id)" function
11345 */
11346 static void
11347f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11348{
11349 int id;
11350
11351#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011352 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011353
11354 if (id > 0)
11355 id = syn_get_final_id(id);
11356 else
11357#endif
11358 id = 0;
11359
11360 rettv->vval.v_number = id;
11361}
11362
11363/*
11364 * "synconcealed(lnum, col)" function
11365 */
11366 static void
11367f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11368{
11369#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11370 linenr_T lnum;
11371 colnr_T col;
11372 int syntax_flags = 0;
11373 int cchar;
11374 int matchid = 0;
11375 char_u str[NUMBUFLEN];
11376#endif
11377
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011378 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011379
11380#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011381 lnum = tv_get_lnum(argvars); /* -1 on type error */
11382 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011383
11384 vim_memset(str, NUL, sizeof(str));
11385
11386 if (rettv_list_alloc(rettv) != FAIL)
11387 {
11388 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11389 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11390 && curwin->w_p_cole > 0)
11391 {
11392 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11393 syntax_flags = get_syntax_info(&matchid);
11394
11395 /* get the conceal character */
11396 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11397 {
11398 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011399 if (cchar == NUL && curwin->w_p_cole == 1)
11400 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011401 if (cchar != NUL)
11402 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011403 if (has_mbyte)
11404 (*mb_char2bytes)(cchar, str);
11405 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011406 str[0] = cchar;
11407 }
11408 }
11409 }
11410
11411 list_append_number(rettv->vval.v_list,
11412 (syntax_flags & HL_CONCEAL) != 0);
11413 /* -1 to auto-determine strlen */
11414 list_append_string(rettv->vval.v_list, str, -1);
11415 list_append_number(rettv->vval.v_list, matchid);
11416 }
11417#endif
11418}
11419
11420/*
11421 * "synstack(lnum, col)" function
11422 */
11423 static void
11424f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11425{
11426#ifdef FEAT_SYN_HL
11427 linenr_T lnum;
11428 colnr_T col;
11429 int i;
11430 int id;
11431#endif
11432
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011433 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011434
11435#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011436 lnum = tv_get_lnum(argvars); /* -1 on type error */
11437 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011438
11439 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11440 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11441 && rettv_list_alloc(rettv) != FAIL)
11442 {
11443 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11444 for (i = 0; ; ++i)
11445 {
11446 id = syn_get_stack_item(i);
11447 if (id < 0)
11448 break;
11449 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11450 break;
11451 }
11452 }
11453#endif
11454}
11455
11456 static void
11457get_cmd_output_as_rettv(
11458 typval_T *argvars,
11459 typval_T *rettv,
11460 int retlist)
11461{
11462 char_u *res = NULL;
11463 char_u *p;
11464 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011465 int err = FALSE;
11466 FILE *fd;
11467 list_T *list = NULL;
11468 int flags = SHELL_SILENT;
11469
11470 rettv->v_type = VAR_STRING;
11471 rettv->vval.v_string = NULL;
11472 if (check_restricted() || check_secure())
11473 goto errret;
11474
11475 if (argvars[1].v_type != VAR_UNKNOWN)
11476 {
11477 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011478 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011479 * command.
11480 */
11481 if ((infile = vim_tempname('i', TRUE)) == NULL)
11482 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011483 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011484 goto errret;
11485 }
11486
11487 fd = mch_fopen((char *)infile, WRITEBIN);
11488 if (fd == NULL)
11489 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011490 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011491 goto errret;
11492 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011493 if (argvars[1].v_type == VAR_NUMBER)
11494 {
11495 linenr_T lnum;
11496 buf_T *buf;
11497
11498 buf = buflist_findnr(argvars[1].vval.v_number);
11499 if (buf == NULL)
11500 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011501 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011502 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011503 goto errret;
11504 }
11505
11506 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11507 {
11508 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11509 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11510 {
11511 err = TRUE;
11512 break;
11513 }
11514 if (putc(NL, fd) == EOF)
11515 {
11516 err = TRUE;
11517 break;
11518 }
11519 }
11520 }
11521 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011522 {
11523 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11524 err = TRUE;
11525 }
11526 else
11527 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011528 size_t len;
11529 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011530
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011531 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011532 if (p == NULL)
11533 {
11534 fclose(fd);
11535 goto errret; /* type error; errmsg already given */
11536 }
11537 len = STRLEN(p);
11538 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11539 err = TRUE;
11540 }
11541 if (fclose(fd) != 0)
11542 err = TRUE;
11543 if (err)
11544 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011545 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011546 goto errret;
11547 }
11548 }
11549
11550 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11551 * echoes typeahead, that messes up the display. */
11552 if (!msg_silent)
11553 flags += SHELL_COOKED;
11554
11555 if (retlist)
11556 {
11557 int len;
11558 listitem_T *li;
11559 char_u *s = NULL;
11560 char_u *start;
11561 char_u *end;
11562 int i;
11563
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011564 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011565 if (res == NULL)
11566 goto errret;
11567
11568 list = list_alloc();
11569 if (list == NULL)
11570 goto errret;
11571
11572 for (i = 0; i < len; ++i)
11573 {
11574 start = res + i;
11575 while (i < len && res[i] != NL)
11576 ++i;
11577 end = res + i;
11578
Bram Moolenaar964b3742019-05-24 18:54:09 +020011579 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011580 if (s == NULL)
11581 goto errret;
11582
11583 for (p = s; start < end; ++p, ++start)
11584 *p = *start == NUL ? NL : *start;
11585 *p = NUL;
11586
11587 li = listitem_alloc();
11588 if (li == NULL)
11589 {
11590 vim_free(s);
11591 goto errret;
11592 }
11593 li->li_tv.v_type = VAR_STRING;
11594 li->li_tv.v_lock = 0;
11595 li->li_tv.vval.v_string = s;
11596 list_append(list, li);
11597 }
11598
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011599 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011600 list = NULL;
11601 }
11602 else
11603 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011604 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011605#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011606 /* translate <CR><NL> into <NL> */
11607 if (res != NULL)
11608 {
11609 char_u *s, *d;
11610
11611 d = res;
11612 for (s = res; *s; ++s)
11613 {
11614 if (s[0] == CAR && s[1] == NL)
11615 ++s;
11616 *d++ = *s;
11617 }
11618 *d = NUL;
11619 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011620#endif
11621 rettv->vval.v_string = res;
11622 res = NULL;
11623 }
11624
11625errret:
11626 if (infile != NULL)
11627 {
11628 mch_remove(infile);
11629 vim_free(infile);
11630 }
11631 if (res != NULL)
11632 vim_free(res);
11633 if (list != NULL)
11634 list_free(list);
11635}
11636
11637/*
11638 * "system()" function
11639 */
11640 static void
11641f_system(typval_T *argvars, typval_T *rettv)
11642{
11643 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11644}
11645
11646/*
11647 * "systemlist()" function
11648 */
11649 static void
11650f_systemlist(typval_T *argvars, typval_T *rettv)
11651{
11652 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11653}
11654
11655/*
11656 * "tabpagebuflist()" function
11657 */
11658 static void
11659f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11660{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011661 tabpage_T *tp;
11662 win_T *wp = NULL;
11663
11664 if (argvars[0].v_type == VAR_UNKNOWN)
11665 wp = firstwin;
11666 else
11667 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011668 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011669 if (tp != NULL)
11670 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11671 }
11672 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11673 {
11674 for (; wp != NULL; wp = wp->w_next)
11675 if (list_append_number(rettv->vval.v_list,
11676 wp->w_buffer->b_fnum) == FAIL)
11677 break;
11678 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011679}
11680
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011681/*
11682 * "tabpagenr()" function
11683 */
11684 static void
11685f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11686{
11687 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011688 char_u *arg;
11689
11690 if (argvars[0].v_type != VAR_UNKNOWN)
11691 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011692 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011693 nr = 0;
11694 if (arg != NULL)
11695 {
11696 if (STRCMP(arg, "$") == 0)
11697 nr = tabpage_index(NULL) - 1;
11698 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011699 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011700 }
11701 }
11702 else
11703 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011704 rettv->vval.v_number = nr;
11705}
11706
11707
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011708/*
11709 * Common code for tabpagewinnr() and winnr().
11710 */
11711 static int
11712get_winnr(tabpage_T *tp, typval_T *argvar)
11713{
11714 win_T *twin;
11715 int nr = 1;
11716 win_T *wp;
11717 char_u *arg;
11718
11719 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11720 if (argvar->v_type != VAR_UNKNOWN)
11721 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011722 int invalid_arg = FALSE;
11723
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011724 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011725 if (arg == NULL)
11726 nr = 0; /* type error; errmsg already given */
11727 else if (STRCMP(arg, "$") == 0)
11728 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11729 else if (STRCMP(arg, "#") == 0)
11730 {
11731 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11732 if (twin == NULL)
11733 nr = 0;
11734 }
11735 else
11736 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011737 long count;
11738 char_u *endp;
11739
11740 // Extract the window count (if specified). e.g. winnr('3j')
11741 count = strtol((char *)arg, (char **)&endp, 10);
11742 if (count <= 0)
11743 count = 1; // if count is not specified, default to 1
11744 if (endp != NULL && *endp != '\0')
11745 {
11746 if (STRCMP(endp, "j") == 0)
11747 twin = win_vert_neighbor(tp, twin, FALSE, count);
11748 else if (STRCMP(endp, "k") == 0)
11749 twin = win_vert_neighbor(tp, twin, TRUE, count);
11750 else if (STRCMP(endp, "h") == 0)
11751 twin = win_horz_neighbor(tp, twin, TRUE, count);
11752 else if (STRCMP(endp, "l") == 0)
11753 twin = win_horz_neighbor(tp, twin, FALSE, count);
11754 else
11755 invalid_arg = TRUE;
11756 }
11757 else
11758 invalid_arg = TRUE;
11759 }
11760
11761 if (invalid_arg)
11762 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011763 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011764 nr = 0;
11765 }
11766 }
11767
11768 if (nr > 0)
11769 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11770 wp != twin; wp = wp->w_next)
11771 {
11772 if (wp == NULL)
11773 {
11774 /* didn't find it in this tabpage */
11775 nr = 0;
11776 break;
11777 }
11778 ++nr;
11779 }
11780 return nr;
11781}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011782
11783/*
11784 * "tabpagewinnr()" function
11785 */
11786 static void
11787f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11788{
11789 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011790 tabpage_T *tp;
11791
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011792 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011793 if (tp == NULL)
11794 nr = 0;
11795 else
11796 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011797 rettv->vval.v_number = nr;
11798}
11799
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011800/*
11801 * "tagfiles()" function
11802 */
11803 static void
11804f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11805{
11806 char_u *fname;
11807 tagname_T tn;
11808 int first;
11809
11810 if (rettv_list_alloc(rettv) == FAIL)
11811 return;
11812 fname = alloc(MAXPATHL);
11813 if (fname == NULL)
11814 return;
11815
11816 for (first = TRUE; ; first = FALSE)
11817 if (get_tagfname(&tn, first, fname) == FAIL
11818 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11819 break;
11820 tagname_free(&tn);
11821 vim_free(fname);
11822}
11823
11824/*
11825 * "taglist()" function
11826 */
11827 static void
11828f_taglist(typval_T *argvars, typval_T *rettv)
11829{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011830 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011831 char_u *tag_pattern;
11832
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011833 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011834
11835 rettv->vval.v_number = FALSE;
11836 if (*tag_pattern == NUL)
11837 return;
11838
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011839 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011840 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011841 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011842 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011843}
11844
11845/*
11846 * "tempname()" function
11847 */
11848 static void
11849f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11850{
11851 static int x = 'A';
11852
11853 rettv->v_type = VAR_STRING;
11854 rettv->vval.v_string = vim_tempname(x, FALSE);
11855
11856 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11857 * names. Skip 'I' and 'O', they are used for shell redirection. */
11858 do
11859 {
11860 if (x == 'Z')
11861 x = '0';
11862 else if (x == '9')
11863 x = 'A';
11864 else
11865 {
11866#ifdef EBCDIC
11867 if (x == 'I')
11868 x = 'J';
11869 else if (x == 'R')
11870 x = 'S';
11871 else
11872#endif
11873 ++x;
11874 }
11875 } while (x == 'I' || x == 'O');
11876}
11877
11878#ifdef FEAT_FLOAT
11879/*
11880 * "tan()" function
11881 */
11882 static void
11883f_tan(typval_T *argvars, typval_T *rettv)
11884{
11885 float_T f = 0.0;
11886
11887 rettv->v_type = VAR_FLOAT;
11888 if (get_float_arg(argvars, &f) == OK)
11889 rettv->vval.v_float = tan(f);
11890 else
11891 rettv->vval.v_float = 0.0;
11892}
11893
11894/*
11895 * "tanh()" function
11896 */
11897 static void
11898f_tanh(typval_T *argvars, typval_T *rettv)
11899{
11900 float_T f = 0.0;
11901
11902 rettv->v_type = VAR_FLOAT;
11903 if (get_float_arg(argvars, &f) == OK)
11904 rettv->vval.v_float = tanh(f);
11905 else
11906 rettv->vval.v_float = 0.0;
11907}
11908#endif
11909
11910/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011911 * Get a callback from "arg". It can be a Funcref or a function name.
11912 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011913 * "cb_name" is not allocated.
11914 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011915 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011916 callback_T
11917get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011918{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011919 callback_T res;
11920
11921 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011922 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11923 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011924 res.cb_partial = arg->vval.v_partial;
11925 ++res.cb_partial->pt_refcount;
11926 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011927 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011928 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011929 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011930 res.cb_partial = NULL;
11931 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
11932 {
11933 // Note that we don't make a copy of the string.
11934 res.cb_name = arg->vval.v_string;
11935 func_ref(res.cb_name);
11936 }
11937 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11938 {
11939 res.cb_name = (char_u *)"";
11940 }
11941 else
11942 {
11943 emsg(_("E921: Invalid callback argument"));
11944 res.cb_name = NULL;
11945 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011946 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011947 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011948}
11949
11950/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011951 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011952 */
11953 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011954put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011955{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011956 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011957 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011958 tv->v_type = VAR_PARTIAL;
11959 tv->vval.v_partial = cb->cb_partial;
11960 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011961 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011962 else
11963 {
11964 tv->v_type = VAR_FUNC;
11965 tv->vval.v_string = vim_strsave(cb->cb_name);
11966 func_ref(cb->cb_name);
11967 }
11968}
11969
11970/*
11971 * Make a copy of "src" into "dest", allocating the function name if needed,
11972 * without incrementing the refcount.
11973 */
11974 void
11975set_callback(callback_T *dest, callback_T *src)
11976{
11977 if (src->cb_partial == NULL)
11978 {
11979 // just a function name, make a copy
11980 dest->cb_name = vim_strsave(src->cb_name);
11981 dest->cb_free_name = TRUE;
11982 }
11983 else
11984 {
11985 // cb_name is a pointer into cb_partial
11986 dest->cb_name = src->cb_name;
11987 dest->cb_free_name = FALSE;
11988 }
11989 dest->cb_partial = src->cb_partial;
11990}
11991
11992/*
11993 * Unref/free "callback" returned by get_callback() or set_callback().
11994 */
11995 void
11996free_callback(callback_T *callback)
11997{
11998 if (callback->cb_partial != NULL)
11999 {
12000 partial_unref(callback->cb_partial);
12001 callback->cb_partial = NULL;
12002 }
12003 else if (callback->cb_name != NULL)
12004 func_unref(callback->cb_name);
12005 if (callback->cb_free_name)
12006 {
12007 vim_free(callback->cb_name);
12008 callback->cb_free_name = FALSE;
12009 }
12010 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012011}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012012
12013#ifdef FEAT_TIMERS
12014/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012015 * "timer_info([timer])" function
12016 */
12017 static void
12018f_timer_info(typval_T *argvars, typval_T *rettv)
12019{
12020 timer_T *timer = NULL;
12021
12022 if (rettv_list_alloc(rettv) != OK)
12023 return;
12024 if (argvars[0].v_type != VAR_UNKNOWN)
12025 {
12026 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012027 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012028 else
12029 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012030 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012031 if (timer != NULL)
12032 add_timer_info(rettv, timer);
12033 }
12034 }
12035 else
12036 add_timer_info_all(rettv);
12037}
12038
12039/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012040 * "timer_pause(timer, paused)" function
12041 */
12042 static void
12043f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12044{
12045 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012046 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012047
12048 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012049 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012050 else
12051 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012052 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012053 if (timer != NULL)
12054 timer->tr_paused = paused;
12055 }
12056}
12057
12058/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012059 * "timer_start(time, callback [, options])" function
12060 */
12061 static void
12062f_timer_start(typval_T *argvars, typval_T *rettv)
12063{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012064 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012065 timer_T *timer;
12066 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012067 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012068 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012069
Bram Moolenaar75537a92016-09-05 22:45:28 +020012070 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012071 if (check_secure())
12072 return;
12073 if (argvars[2].v_type != VAR_UNKNOWN)
12074 {
12075 if (argvars[2].v_type != VAR_DICT
12076 || (dict = argvars[2].vval.v_dict) == NULL)
12077 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012078 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012079 return;
12080 }
12081 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012082 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012083 }
12084
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012085 callback = get_callback(&argvars[1]);
12086 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012087 return;
12088
12089 timer = create_timer(msec, repeat);
12090 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012091 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012092 else
12093 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012094 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012095 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012096 }
12097}
12098
12099/*
12100 * "timer_stop(timer)" function
12101 */
12102 static void
12103f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12104{
12105 timer_T *timer;
12106
12107 if (argvars[0].v_type != VAR_NUMBER)
12108 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012109 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012110 return;
12111 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012112 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012113 if (timer != NULL)
12114 stop_timer(timer);
12115}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012116
12117/*
12118 * "timer_stopall()" function
12119 */
12120 static void
12121f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12122{
12123 stop_all_timers();
12124}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012125#endif
12126
12127/*
12128 * "tolower(string)" function
12129 */
12130 static void
12131f_tolower(typval_T *argvars, typval_T *rettv)
12132{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012133 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012134 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012135}
12136
12137/*
12138 * "toupper(string)" function
12139 */
12140 static void
12141f_toupper(typval_T *argvars, typval_T *rettv)
12142{
12143 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012144 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012145}
12146
12147/*
12148 * "tr(string, fromstr, tostr)" function
12149 */
12150 static void
12151f_tr(typval_T *argvars, typval_T *rettv)
12152{
12153 char_u *in_str;
12154 char_u *fromstr;
12155 char_u *tostr;
12156 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012157 int inlen;
12158 int fromlen;
12159 int tolen;
12160 int idx;
12161 char_u *cpstr;
12162 int cplen;
12163 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012164 char_u buf[NUMBUFLEN];
12165 char_u buf2[NUMBUFLEN];
12166 garray_T ga;
12167
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012168 in_str = tv_get_string(&argvars[0]);
12169 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12170 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012171
12172 /* Default return value: empty string. */
12173 rettv->v_type = VAR_STRING;
12174 rettv->vval.v_string = NULL;
12175 if (fromstr == NULL || tostr == NULL)
12176 return; /* type error; errmsg already given */
12177 ga_init2(&ga, (int)sizeof(char), 80);
12178
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012179 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012180 /* not multi-byte: fromstr and tostr must be the same length */
12181 if (STRLEN(fromstr) != STRLEN(tostr))
12182 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012183error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012184 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012185 ga_clear(&ga);
12186 return;
12187 }
12188
12189 /* fromstr and tostr have to contain the same number of chars */
12190 while (*in_str != NUL)
12191 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012192 if (has_mbyte)
12193 {
12194 inlen = (*mb_ptr2len)(in_str);
12195 cpstr = in_str;
12196 cplen = inlen;
12197 idx = 0;
12198 for (p = fromstr; *p != NUL; p += fromlen)
12199 {
12200 fromlen = (*mb_ptr2len)(p);
12201 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12202 {
12203 for (p = tostr; *p != NUL; p += tolen)
12204 {
12205 tolen = (*mb_ptr2len)(p);
12206 if (idx-- == 0)
12207 {
12208 cplen = tolen;
12209 cpstr = p;
12210 break;
12211 }
12212 }
12213 if (*p == NUL) /* tostr is shorter than fromstr */
12214 goto error;
12215 break;
12216 }
12217 ++idx;
12218 }
12219
12220 if (first && cpstr == in_str)
12221 {
12222 /* Check that fromstr and tostr have the same number of
12223 * (multi-byte) characters. Done only once when a character
12224 * of in_str doesn't appear in fromstr. */
12225 first = FALSE;
12226 for (p = tostr; *p != NUL; p += tolen)
12227 {
12228 tolen = (*mb_ptr2len)(p);
12229 --idx;
12230 }
12231 if (idx != 0)
12232 goto error;
12233 }
12234
12235 (void)ga_grow(&ga, cplen);
12236 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12237 ga.ga_len += cplen;
12238
12239 in_str += inlen;
12240 }
12241 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012242 {
12243 /* When not using multi-byte chars we can do it faster. */
12244 p = vim_strchr(fromstr, *in_str);
12245 if (p != NULL)
12246 ga_append(&ga, tostr[p - fromstr]);
12247 else
12248 ga_append(&ga, *in_str);
12249 ++in_str;
12250 }
12251 }
12252
12253 /* add a terminating NUL */
12254 (void)ga_grow(&ga, 1);
12255 ga_append(&ga, NUL);
12256
12257 rettv->vval.v_string = ga.ga_data;
12258}
12259
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012260/*
12261 * "trim({expr})" function
12262 */
12263 static void
12264f_trim(typval_T *argvars, typval_T *rettv)
12265{
12266 char_u buf1[NUMBUFLEN];
12267 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012268 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012269 char_u *mask = NULL;
12270 char_u *tail;
12271 char_u *prev;
12272 char_u *p;
12273 int c1;
12274
12275 rettv->v_type = VAR_STRING;
12276 if (head == NULL)
12277 {
12278 rettv->vval.v_string = NULL;
12279 return;
12280 }
12281
12282 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012283 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012284
12285 while (*head != NUL)
12286 {
12287 c1 = PTR2CHAR(head);
12288 if (mask == NULL)
12289 {
12290 if (c1 > ' ' && c1 != 0xa0)
12291 break;
12292 }
12293 else
12294 {
12295 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12296 if (c1 == PTR2CHAR(p))
12297 break;
12298 if (*p == NUL)
12299 break;
12300 }
12301 MB_PTR_ADV(head);
12302 }
12303
12304 for (tail = head + STRLEN(head); tail > head; tail = prev)
12305 {
12306 prev = tail;
12307 MB_PTR_BACK(head, prev);
12308 c1 = PTR2CHAR(prev);
12309 if (mask == NULL)
12310 {
12311 if (c1 > ' ' && c1 != 0xa0)
12312 break;
12313 }
12314 else
12315 {
12316 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12317 if (c1 == PTR2CHAR(p))
12318 break;
12319 if (*p == NUL)
12320 break;
12321 }
12322 }
12323 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12324}
12325
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012326#ifdef FEAT_FLOAT
12327/*
12328 * "trunc({float})" function
12329 */
12330 static void
12331f_trunc(typval_T *argvars, typval_T *rettv)
12332{
12333 float_T f = 0.0;
12334
12335 rettv->v_type = VAR_FLOAT;
12336 if (get_float_arg(argvars, &f) == OK)
12337 /* trunc() is not in C90, use floor() or ceil() instead. */
12338 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12339 else
12340 rettv->vval.v_float = 0.0;
12341}
12342#endif
12343
12344/*
12345 * "type(expr)" function
12346 */
12347 static void
12348f_type(typval_T *argvars, typval_T *rettv)
12349{
12350 int n = -1;
12351
12352 switch (argvars[0].v_type)
12353 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012354 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12355 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012356 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012357 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12358 case VAR_LIST: n = VAR_TYPE_LIST; break;
12359 case VAR_DICT: n = VAR_TYPE_DICT; break;
12360 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012361 case VAR_SPECIAL:
12362 if (argvars[0].vval.v_number == VVAL_FALSE
12363 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012364 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012365 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012366 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012367 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012368 case VAR_JOB: n = VAR_TYPE_JOB; break;
12369 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012370 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012371 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012372 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012373 n = -1;
12374 break;
12375 }
12376 rettv->vval.v_number = n;
12377}
12378
12379/*
12380 * "undofile(name)" function
12381 */
12382 static void
12383f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12384{
12385 rettv->v_type = VAR_STRING;
12386#ifdef FEAT_PERSISTENT_UNDO
12387 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012388 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012389
12390 if (*fname == NUL)
12391 {
12392 /* If there is no file name there will be no undo file. */
12393 rettv->vval.v_string = NULL;
12394 }
12395 else
12396 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012397 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012398
12399 if (ffname != NULL)
12400 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12401 vim_free(ffname);
12402 }
12403 }
12404#else
12405 rettv->vval.v_string = NULL;
12406#endif
12407}
12408
12409/*
12410 * "undotree()" function
12411 */
12412 static void
12413f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12414{
12415 if (rettv_dict_alloc(rettv) == OK)
12416 {
12417 dict_T *dict = rettv->vval.v_dict;
12418 list_T *list;
12419
Bram Moolenaare0be1672018-07-08 16:50:37 +020012420 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12421 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12422 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12423 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12424 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12425 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012426
12427 list = list_alloc();
12428 if (list != NULL)
12429 {
12430 u_eval_tree(curbuf->b_u_oldhead, list);
12431 dict_add_list(dict, "entries", list);
12432 }
12433 }
12434}
12435
12436/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012437 * "virtcol(string)" function
12438 */
12439 static void
12440f_virtcol(typval_T *argvars, typval_T *rettv)
12441{
12442 colnr_T vcol = 0;
12443 pos_T *fp;
12444 int fnum = curbuf->b_fnum;
12445
12446 fp = var2fpos(&argvars[0], FALSE, &fnum);
12447 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12448 && fnum == curbuf->b_fnum)
12449 {
12450 getvvcol(curwin, fp, NULL, NULL, &vcol);
12451 ++vcol;
12452 }
12453
12454 rettv->vval.v_number = vcol;
12455}
12456
12457/*
12458 * "visualmode()" function
12459 */
12460 static void
12461f_visualmode(typval_T *argvars, typval_T *rettv)
12462{
12463 char_u str[2];
12464
12465 rettv->v_type = VAR_STRING;
12466 str[0] = curbuf->b_visual_mode_eval;
12467 str[1] = NUL;
12468 rettv->vval.v_string = vim_strsave(str);
12469
12470 /* A non-zero number or non-empty string argument: reset mode. */
12471 if (non_zero_arg(&argvars[0]))
12472 curbuf->b_visual_mode_eval = NUL;
12473}
12474
12475/*
12476 * "wildmenumode()" function
12477 */
12478 static void
12479f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12480{
12481#ifdef FEAT_WILDMENU
12482 if (wild_menu_showing)
12483 rettv->vval.v_number = 1;
12484#endif
12485}
12486
12487/*
12488 * "winbufnr(nr)" function
12489 */
12490 static void
12491f_winbufnr(typval_T *argvars, typval_T *rettv)
12492{
12493 win_T *wp;
12494
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012495 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012496 if (wp == NULL)
12497 rettv->vval.v_number = -1;
12498 else
12499 rettv->vval.v_number = wp->w_buffer->b_fnum;
12500}
12501
12502/*
12503 * "wincol()" function
12504 */
12505 static void
12506f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12507{
12508 validate_cursor();
12509 rettv->vval.v_number = curwin->w_wcol + 1;
12510}
12511
12512/*
12513 * "winheight(nr)" function
12514 */
12515 static void
12516f_winheight(typval_T *argvars, typval_T *rettv)
12517{
12518 win_T *wp;
12519
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012520 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012521 if (wp == NULL)
12522 rettv->vval.v_number = -1;
12523 else
12524 rettv->vval.v_number = wp->w_height;
12525}
12526
12527/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012528 * "winlayout()" function
12529 */
12530 static void
12531f_winlayout(typval_T *argvars, typval_T *rettv)
12532{
12533 tabpage_T *tp;
12534
12535 if (rettv_list_alloc(rettv) != OK)
12536 return;
12537
12538 if (argvars[0].v_type == VAR_UNKNOWN)
12539 tp = curtab;
12540 else
12541 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012542 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012543 if (tp == NULL)
12544 return;
12545 }
12546
12547 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12548}
12549
12550/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012551 * "winline()" function
12552 */
12553 static void
12554f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12555{
12556 validate_cursor();
12557 rettv->vval.v_number = curwin->w_wrow + 1;
12558}
12559
12560/*
12561 * "winnr()" function
12562 */
12563 static void
12564f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12565{
12566 int nr = 1;
12567
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012568 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012569 rettv->vval.v_number = nr;
12570}
12571
12572/*
12573 * "winrestcmd()" function
12574 */
12575 static void
12576f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12577{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012578 win_T *wp;
12579 int winnr = 1;
12580 garray_T ga;
12581 char_u buf[50];
12582
12583 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012584 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012585 {
12586 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12587 ga_concat(&ga, buf);
12588 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12589 ga_concat(&ga, buf);
12590 ++winnr;
12591 }
12592 ga_append(&ga, NUL);
12593
12594 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012595 rettv->v_type = VAR_STRING;
12596}
12597
12598/*
12599 * "winrestview()" function
12600 */
12601 static void
12602f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12603{
12604 dict_T *dict;
12605
12606 if (argvars[0].v_type != VAR_DICT
12607 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012608 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012609 else
12610 {
12611 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012612 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012613 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012614 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012615 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012616 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012617 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12618 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012619 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012620 curwin->w_set_curswant = FALSE;
12621 }
12622
12623 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012624 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012625#ifdef FEAT_DIFF
12626 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012627 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012628#endif
12629 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012630 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012631 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012632 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012633
12634 check_cursor();
12635 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012636 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012637 changed_window_setting();
12638
12639 if (curwin->w_topline <= 0)
12640 curwin->w_topline = 1;
12641 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12642 curwin->w_topline = curbuf->b_ml.ml_line_count;
12643#ifdef FEAT_DIFF
12644 check_topfill(curwin, TRUE);
12645#endif
12646 }
12647}
12648
12649/*
12650 * "winsaveview()" function
12651 */
12652 static void
12653f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12654{
12655 dict_T *dict;
12656
12657 if (rettv_dict_alloc(rettv) == FAIL)
12658 return;
12659 dict = rettv->vval.v_dict;
12660
Bram Moolenaare0be1672018-07-08 16:50:37 +020012661 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12662 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012663 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012664 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012665 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012666
Bram Moolenaare0be1672018-07-08 16:50:37 +020012667 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012668#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012669 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012670#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012671 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12672 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012673}
12674
12675/*
12676 * "winwidth(nr)" function
12677 */
12678 static void
12679f_winwidth(typval_T *argvars, typval_T *rettv)
12680{
12681 win_T *wp;
12682
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012683 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012684 if (wp == NULL)
12685 rettv->vval.v_number = -1;
12686 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012687 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012688}
12689
12690/*
12691 * "wordcount()" function
12692 */
12693 static void
12694f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12695{
12696 if (rettv_dict_alloc(rettv) == FAIL)
12697 return;
12698 cursor_pos_info(rettv->vval.v_dict);
12699}
12700
12701/*
12702 * "writefile()" function
12703 */
12704 static void
12705f_writefile(typval_T *argvars, typval_T *rettv)
12706{
12707 int binary = FALSE;
12708 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012709#ifdef HAVE_FSYNC
12710 int do_fsync = p_fs;
12711#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012712 char_u *fname;
12713 FILE *fd;
12714 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012715 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012716 list_T *list = NULL;
12717 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012718
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012719 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012720 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012721 return;
12722
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012723 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012724 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012725 list = argvars[0].vval.v_list;
12726 if (list == NULL)
12727 return;
12728 for (li = list->lv_first; li != NULL; li = li->li_next)
12729 if (tv_get_string_chk(&li->li_tv) == NULL)
12730 return;
12731 }
12732 else if (argvars[0].v_type == VAR_BLOB)
12733 {
12734 blob = argvars[0].vval.v_blob;
12735 if (blob == NULL)
12736 return;
12737 }
12738 else
12739 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012740 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012741 return;
12742 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012743
12744 if (argvars[2].v_type != VAR_UNKNOWN)
12745 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012746 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012747
12748 if (arg2 == NULL)
12749 return;
12750 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012751 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012752 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012753 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012754#ifdef HAVE_FSYNC
12755 if (vim_strchr(arg2, 's') != NULL)
12756 do_fsync = TRUE;
12757 else if (vim_strchr(arg2, 'S') != NULL)
12758 do_fsync = FALSE;
12759#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012760 }
12761
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012762 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012763 if (fname == NULL)
12764 return;
12765
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012766 /* Always open the file in binary mode, library functions have a mind of
12767 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012768 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12769 append ? APPENDBIN : WRITEBIN)) == NULL)
12770 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012771 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012772 ret = -1;
12773 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012774 else if (blob)
12775 {
12776 if (write_blob(fd, blob) == FAIL)
12777 ret = -1;
12778#ifdef HAVE_FSYNC
12779 else if (do_fsync)
12780 // Ignore the error, the user wouldn't know what to do about it.
12781 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012782 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012783#endif
12784 fclose(fd);
12785 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012786 else
12787 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012788 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012789 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012790#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012791 else if (do_fsync)
12792 /* Ignore the error, the user wouldn't know what to do about it.
12793 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012794 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012795#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012796 fclose(fd);
12797 }
12798
12799 rettv->vval.v_number = ret;
12800}
12801
12802/*
12803 * "xor(expr, expr)" function
12804 */
12805 static void
12806f_xor(typval_T *argvars, typval_T *rettv)
12807{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012808 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
12809 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012810}
12811
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012812#endif /* FEAT_EVAL */