blob: 07e5993de600d7d8fb5b0a2e88fee8ba9822ec76 [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},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200434 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200435 {"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 Moolenaare49fbff2019-08-21 22:50:07 +0200442 {"assert_report", 1, 1, FEARG_1, 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 Moolenaara8eee212019-08-24 22:14:58 +0200460 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
461 {"buffer_number", 0, 1, FEARG_1, 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},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200465 {"bufname", 0, 1, FEARG_1, f_bufname},
466 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200467 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
468 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200469 {"byte2line", 1, 1, FEARG_1, f_byte2line},
470 {"byteidx", 2, 2, FEARG_1, f_byteidx},
471 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
472 {"call", 2, 3, FEARG_1, 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 Moolenaar570497a2019-08-22 22:55:13 +0200477 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
478 {"ch_close", 1, 1, FEARG_1, f_ch_close},
479 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
480 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
481 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
482 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
483 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
484 {"ch_info", 1, 1, FEARG_1, f_ch_info},
485 {"ch_log", 1, 2, FEARG_1, f_ch_log},
486 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
487 {"ch_open", 1, 2, FEARG_1, f_ch_open},
488 {"ch_read", 1, 2, FEARG_1, f_ch_read},
489 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
490 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
491 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
492 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
493 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
494 {"ch_status", 1, 2, FEARG_1, 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},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200497 {"char2nr", 1, 2, FEARG_1, f_char2nr},
498 {"chdir", 1, 1, FEARG_1, f_chdir},
499 {"cindent", 1, 1, FEARG_1, f_cindent},
500 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
501 {"col", 1, 1, FEARG_1, f_col},
502 {"complete", 2, 2, FEARG_2, f_complete},
503 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200505 {"complete_info", 0, 1, FEARG_1, f_complete_info},
506 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"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},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200514 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100515#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200516 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200517#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200518 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
519 {"delete", 1, 2, FEARG_1, f_delete},
520 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200521 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200522 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
523 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200524 {"empty", 1, 1, FEARG_1, f_empty},
525 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200526 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200527 {"eval", 1, 1, FEARG_1, f_eval},
528 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200529 {"executable", 1, 1, FEARG_1, f_executable},
530 {"execute", 1, 2, FEARG_1, f_execute},
531 {"exepath", 1, 1, FEARG_1, f_exepath},
532 {"exists", 1, 1, FEARG_1, 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 Moolenaara4208962019-08-24 20:50:19 +0200536 {"expand", 1, 3, FEARG_1, f_expand},
537 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200538 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200539 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
540 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
541 {"filereadable", 1, 1, FEARG_1, f_filereadable},
542 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200543 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200544 {"finddir", 1, 3, FEARG_1, f_finddir},
545 {"findfile", 1, 3, FEARG_1, 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 Moolenaara4208962019-08-24 20:50:19 +0200551 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
552 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
553 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
554 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
555 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200556 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200557 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200558 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200559 {"funcref", 1, 3, FEARG_1, f_funcref},
560 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200561 {"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 Moolenaar570497a2019-08-22 22:55:13 +0200638 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
639 {"job_info", 0, 1, FEARG_1, f_job_info},
640 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
641 {"job_start", 1, 2, FEARG_1, f_job_start},
642 {"job_status", 1, 1, FEARG_1, f_job_status},
643 {"job_stop", 1, 2, FEARG_1, 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},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200705 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
706 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200707 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
708 {"popup_getpos", 1, 1, 0, f_popup_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200709 {"popup_hide", 1, 1, 0, f_popup_hide},
710 {"popup_locate", 2, 2, 0, f_popup_locate},
711 {"popup_menu", 2, 2, 0, f_popup_menu},
712 {"popup_move", 2, 2, 0, f_popup_move},
713 {"popup_notification", 2, 2, 0, f_popup_notification},
714 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
715 {"popup_settext", 2, 2, 0, f_popup_settext},
716 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200717#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200718#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200719 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200720#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200721 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200722 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200723#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200724 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
725 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
726 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200727#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100728#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200729 {"prop_add", 3, 3, 0, f_prop_add},
730 {"prop_clear", 1, 3, 0, f_prop_clear},
731 {"prop_list", 1, 2, 0, f_prop_list},
732 {"prop_remove", 1, 3, 0, f_prop_remove},
733 {"prop_type_add", 2, 2, 0, f_prop_type_add},
734 {"prop_type_change", 2, 2, 0, f_prop_type_change},
735 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
736 {"prop_type_get", 1, 2, 0, f_prop_type_get},
737 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100738#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200739 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200740 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200741#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200742 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200743#endif
744#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200745 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200746#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100747#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200748 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100749#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200750 {"range", 1, 3, 0, f_range},
751 {"readdir", 1, 2, 0, f_readdir},
752 {"readfile", 1, 3, 0, f_readfile},
753 {"reg_executing", 0, 0, 0, f_reg_executing},
754 {"reg_recording", 0, 0, 0, f_reg_recording},
755 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200756#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200757 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200758#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200759 {"reltimestr", 1, 1, 0, f_reltimestr},
760 {"remote_expr", 2, 4, 0, f_remote_expr},
761 {"remote_foreground", 1, 1, 0, f_remote_foreground},
762 {"remote_peek", 1, 2, 0, f_remote_peek},
763 {"remote_read", 1, 2, 0, f_remote_read},
764 {"remote_send", 2, 3, 0, f_remote_send},
765 {"remote_startserver", 1, 1, 0, f_remote_startserver},
766 {"remove", 2, 3, FEARG_1, f_remove},
767 {"rename", 2, 2, 0, f_rename},
768 {"repeat", 2, 2, FEARG_1, f_repeat},
769 {"resolve", 1, 1, 0, f_resolve},
770 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200771#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200772 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200773#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100774#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200775 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100776#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200777 {"screenattr", 2, 2, 0, f_screenattr},
778 {"screenchar", 2, 2, 0, f_screenchar},
779 {"screenchars", 2, 2, 0, f_screenchars},
780 {"screencol", 0, 0, 0, f_screencol},
781 {"screenpos", 3, 3, 0, f_screenpos},
782 {"screenrow", 0, 0, 0, f_screenrow},
783 {"screenstring", 2, 2, 0, f_screenstring},
784 {"search", 1, 4, 0, f_search},
785 {"searchdecl", 1, 3, 0, f_searchdecl},
786 {"searchpair", 3, 7, 0, f_searchpair},
787 {"searchpairpos", 3, 7, 0, f_searchpairpos},
788 {"searchpos", 1, 4, 0, f_searchpos},
789 {"server2client", 2, 2, 0, f_server2client},
790 {"serverlist", 0, 0, 0, f_serverlist},
791 {"setbufline", 3, 3, 0, f_setbufline},
792 {"setbufvar", 3, 3, 0, f_setbufvar},
793 {"setcharsearch", 1, 1, 0, f_setcharsearch},
794 {"setcmdpos", 1, 1, 0, f_setcmdpos},
795 {"setenv", 2, 2, 0, f_setenv},
796 {"setfperm", 2, 2, 0, f_setfperm},
797 {"setline", 2, 2, 0, f_setline},
798 {"setloclist", 2, 4, 0, f_setloclist},
799 {"setmatches", 1, 2, 0, f_setmatches},
800 {"setpos", 2, 2, 0, f_setpos},
801 {"setqflist", 1, 3, 0, f_setqflist},
802 {"setreg", 2, 3, 0, f_setreg},
803 {"settabvar", 3, 3, 0, f_settabvar},
804 {"settabwinvar", 4, 4, 0, f_settabwinvar},
805 {"settagstack", 2, 3, 0, f_settagstack},
806 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200808 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200809#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200810 {"shellescape", 1, 2, 0, f_shellescape},
811 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100812#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200813 {"sign_define", 1, 2, 0, f_sign_define},
814 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
815 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
816 {"sign_jump", 3, 3, 0, f_sign_jump},
817 {"sign_place", 4, 5, 0, f_sign_place},
818 {"sign_placelist", 1, 1, 0, f_sign_placelist},
819 {"sign_undefine", 0, 1, 0, f_sign_undefine},
820 {"sign_unplace", 1, 2, 0, f_sign_unplace},
821 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100822#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200823 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200825 {"sin", 1, 1, FEARG_1, f_sin},
826 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200828 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200829#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200830 {"sound_clear", 0, 0, 0, f_sound_clear},
831 {"sound_playevent", 1, 2, 0, f_sound_playevent},
832 {"sound_playfile", 1, 2, 0, f_sound_playfile},
833 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200834#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200835 {"soundfold", 1, 1, 0, f_soundfold},
836 {"spellbadword", 0, 1, 0, f_spellbadword},
837 {"spellsuggest", 1, 3, 0, f_spellsuggest},
838 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200840 {"sqrt", 1, 1, FEARG_1, f_sqrt},
841 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200842#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200843 {"str2list", 1, 2, FEARG_1, f_str2list},
844 {"str2nr", 1, 2, 0, f_str2nr},
845 {"strcharpart", 2, 3, 0, f_strcharpart},
846 {"strchars", 1, 2, 0, f_strchars},
847 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200849 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200851 {"strgetchar", 2, 2, 0, f_strgetchar},
852 {"stridx", 2, 3, 0, f_stridx},
853 {"string", 1, 1, FEARG_1, f_string},
854 {"strlen", 1, 1, FEARG_1, f_strlen},
855 {"strpart", 2, 3, 0, f_strpart},
856 {"strridx", 2, 3, 0, f_strridx},
857 {"strtrans", 1, 1, FEARG_1, f_strtrans},
858 {"strwidth", 1, 1, FEARG_1, f_strwidth},
859 {"submatch", 1, 2, 0, f_submatch},
860 {"substitute", 4, 4, FEARG_1, f_substitute},
861 {"swapinfo", 1, 1, 0, f_swapinfo},
862 {"swapname", 1, 1, 0, f_swapname},
863 {"synID", 3, 3, 0, f_synID},
864 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
865 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
866 {"synconcealed", 2, 2, 0, f_synconcealed},
867 {"synstack", 2, 2, 0, f_synstack},
868 {"system", 1, 2, FEARG_1, f_system},
869 {"systemlist", 1, 2, FEARG_1, f_systemlist},
870 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
871 {"tabpagenr", 0, 1, 0, f_tabpagenr},
872 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
873 {"tagfiles", 0, 0, 0, f_tagfiles},
874 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200875#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200876 {"tan", 1, 1, FEARG_1, f_tan},
877 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200878#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200879 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200880#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200881 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
882 {"term_dumpload", 1, 2, 0, f_term_dumpload},
883 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
884 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200885# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200886 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200887# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200888 {"term_getattr", 2, 2, 0, f_term_getattr},
889 {"term_getcursor", 1, 1, 0, f_term_getcursor},
890 {"term_getjob", 1, 1, 0, f_term_getjob},
891 {"term_getline", 2, 2, 0, f_term_getline},
892 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
893 {"term_getsize", 1, 1, 0, f_term_getsize},
894 {"term_getstatus", 1, 1, 0, f_term_getstatus},
895 {"term_gettitle", 1, 1, 0, f_term_gettitle},
896 {"term_gettty", 1, 2, 0, f_term_gettty},
897 {"term_list", 0, 0, 0, f_term_list},
898 {"term_scrape", 2, 2, 0, f_term_scrape},
899 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200900# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200901 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200902# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200903 {"term_setkill", 2, 2, 0, f_term_setkill},
904 {"term_setrestore", 2, 2, 0, f_term_setrestore},
905 {"term_setsize", 3, 3, 0, f_term_setsize},
906 {"term_start", 1, 2, 0, f_term_start},
907 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200908#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200909 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
910 {"test_autochdir", 0, 0, 0, f_test_autochdir},
911 {"test_feedinput", 1, 1, 0, f_test_feedinput},
912 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
913 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
914 {"test_getvalue", 1, 1, 0, f_test_getvalue},
915 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
916 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200918 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200919#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200920 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200921#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200922 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200924 {"test_null_list", 0, 0, 0, f_test_null_list},
925 {"test_null_partial", 0, 0, 0, f_test_null_partial},
926 {"test_null_string", 0, 0, 0, f_test_null_string},
927 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
928 {"test_override", 2, 2, 0, f_test_override},
929 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200930#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200931 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200932#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200933#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200934 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200935#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200936 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200937#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200938 {"timer_info", 0, 1, 0, f_timer_info},
939 {"timer_pause", 2, 2, 0, f_timer_pause},
940 {"timer_start", 2, 3, 0, f_timer_start},
941 {"timer_stop", 1, 1, 0, f_timer_stop},
942 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200944 {"tolower", 1, 1, 0, f_tolower},
945 {"toupper", 1, 1, 0, f_toupper},
946 {"tr", 3, 3, 0, f_tr},
947 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200949 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200950#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200951 {"type", 1, 1, FEARG_1, f_type},
952 {"undofile", 1, 1, 0, f_undofile},
953 {"undotree", 0, 0, 0, f_undotree},
954 {"uniq", 1, 3, FEARG_1, f_uniq},
955 {"values", 1, 1, FEARG_1, f_values},
956 {"virtcol", 1, 1, 0, f_virtcol},
957 {"visualmode", 0, 1, 0, f_visualmode},
958 {"wildmenumode", 0, 0, 0, f_wildmenumode},
959 {"win_execute", 2, 3, 0, f_win_execute},
960 {"win_findbuf", 1, 1, 0, f_win_findbuf},
961 {"win_getid", 0, 2, 0, f_win_getid},
962 {"win_gotoid", 1, 1, 0, f_win_gotoid},
963 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
964 {"win_id2win", 1, 1, 0, f_win_id2win},
965 {"win_screenpos", 1, 1, 0, f_win_screenpos},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200966 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200967 {"wincol", 0, 0, 0, f_wincol},
968 {"winheight", 1, 1, 0, f_winheight},
969 {"winlayout", 0, 1, 0, f_winlayout},
970 {"winline", 0, 0, 0, f_winline},
971 {"winnr", 0, 1, 0, f_winnr},
972 {"winrestcmd", 0, 0, 0, f_winrestcmd},
973 {"winrestview", 1, 1, 0, f_winrestview},
974 {"winsaveview", 0, 0, 0, f_winsaveview},
975 {"winwidth", 1, 1, 0, f_winwidth},
976 {"wordcount", 0, 0, 0, f_wordcount},
977 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200978 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200979};
980
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200981/*
982 * Function given to ExpandGeneric() to obtain the list of internal
983 * or user defined function names.
984 */
985 char_u *
986get_function_name(expand_T *xp, int idx)
987{
988 static int intidx = -1;
989 char_u *name;
990
991 if (idx == 0)
992 intidx = -1;
993 if (intidx < 0)
994 {
995 name = get_user_func_name(xp, idx);
996 if (name != NULL)
997 return name;
998 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200999 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001000 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001001 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001002 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001003 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001004 STRCAT(IObuff, ")");
1005 return IObuff;
1006 }
1007
1008 return NULL;
1009}
1010
1011/*
1012 * Function given to ExpandGeneric() to obtain the list of internal or
1013 * user defined variable or function names.
1014 */
1015 char_u *
1016get_expr_name(expand_T *xp, int idx)
1017{
1018 static int intidx = -1;
1019 char_u *name;
1020
1021 if (idx == 0)
1022 intidx = -1;
1023 if (intidx < 0)
1024 {
1025 name = get_function_name(xp, idx);
1026 if (name != NULL)
1027 return name;
1028 }
1029 return get_user_var_name(xp, ++intidx);
1030}
1031
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001032/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001033 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001034 * Return index, or -1 if not found
1035 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001036 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001037find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001038{
1039 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001040 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001041 int cmp;
1042 int x;
1043
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001044 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001045
1046 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001047 while (first <= last)
1048 {
1049 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001050 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001051 if (cmp < 0)
1052 last = x - 1;
1053 else if (cmp > 0)
1054 first = x + 1;
1055 else
1056 return x;
1057 }
1058 return -1;
1059}
1060
1061 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001062has_internal_func(char_u *name)
1063{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001064 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001065}
1066
1067 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001068call_internal_func(
1069 char_u *name,
1070 int argcount,
1071 typval_T *argvars,
1072 typval_T *rettv)
1073{
1074 int i;
1075
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001076 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001077 if (i < 0)
1078 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001079 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001081 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001082 return ERROR_TOOMANY;
1083 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001084 global_functions[i].f_func(argvars, rettv);
1085 return ERROR_NONE;
1086}
1087
1088/*
1089 * Invoke a method for base->method().
1090 */
1091 int
1092call_internal_method(
1093 char_u *name,
1094 int argcount,
1095 typval_T *argvars,
1096 typval_T *rettv,
1097 typval_T *basetv)
1098{
1099 int i;
1100 int fi;
1101 typval_T argv[MAX_FUNC_ARGS + 1];
1102
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001103 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001104 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001105 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001106 if (global_functions[fi].f_argtype == 0)
1107 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001108 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001109 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001110 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001111 return ERROR_TOOMANY;
1112
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001113 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001114 {
1115 // base value goes last
1116 for (i = 0; i < argcount; ++i)
1117 argv[i] = argvars[i];
1118 argv[argcount] = *basetv;
1119 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001120 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001121 {
1122 // base value goes second
1123 argv[0] = argvars[0];
1124 argv[1] = *basetv;
1125 for (i = 1; i < argcount; ++i)
1126 argv[i + 1] = argvars[i];
1127 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001128 else if (global_functions[fi].f_argtype == FEARG_3)
1129 {
1130 // base value goes third
1131 argv[0] = argvars[0];
1132 argv[1] = argvars[1];
1133 argv[2] = *basetv;
1134 for (i = 2; i < argcount; ++i)
1135 argv[i + 1] = argvars[i];
1136 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001137 else
1138 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001139 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001140 argv[0] = *basetv;
1141 for (i = 0; i < argcount; ++i)
1142 argv[i + 1] = argvars[i];
1143 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001144 argv[argcount + 1].v_type = VAR_UNKNOWN;
1145
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001146 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001147 return ERROR_NONE;
1148}
1149
1150/*
1151 * Return TRUE for a non-zero Number and a non-empty String.
1152 */
1153 static int
1154non_zero_arg(typval_T *argvars)
1155{
1156 return ((argvars[0].v_type == VAR_NUMBER
1157 && argvars[0].vval.v_number != 0)
1158 || (argvars[0].v_type == VAR_SPECIAL
1159 && argvars[0].vval.v_number == VVAL_TRUE)
1160 || (argvars[0].v_type == VAR_STRING
1161 && argvars[0].vval.v_string != NULL
1162 && *argvars[0].vval.v_string != NUL));
1163}
1164
1165/*
1166 * Get the lnum from the first argument.
1167 * Also accepts ".", "$", etc., but that only works for the current buffer.
1168 * Returns -1 on error.
1169 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001170 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001171tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001172{
1173 typval_T rettv;
1174 linenr_T lnum;
1175
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001176 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001177 if (lnum == 0) /* no valid number, try using line() */
1178 {
1179 rettv.v_type = VAR_NUMBER;
1180 f_line(argvars, &rettv);
1181 lnum = (linenr_T)rettv.vval.v_number;
1182 clear_tv(&rettv);
1183 }
1184 return lnum;
1185}
1186
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001187/*
1188 * Get the lnum from the first argument.
1189 * Also accepts "$", then "buf" is used.
1190 * Returns 0 on error.
1191 */
1192 static linenr_T
1193tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1194{
1195 if (argvars[0].v_type == VAR_STRING
1196 && argvars[0].vval.v_string != NULL
1197 && argvars[0].vval.v_string[0] == '$'
1198 && buf != NULL)
1199 return buf->b_ml.ml_line_count;
1200 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1201}
1202
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001203#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001204/*
1205 * Get the float value of "argvars[0]" into "f".
1206 * Returns FAIL when the argument is not a Number or Float.
1207 */
1208 static int
1209get_float_arg(typval_T *argvars, float_T *f)
1210{
1211 if (argvars[0].v_type == VAR_FLOAT)
1212 {
1213 *f = argvars[0].vval.v_float;
1214 return OK;
1215 }
1216 if (argvars[0].v_type == VAR_NUMBER)
1217 {
1218 *f = (float_T)argvars[0].vval.v_number;
1219 return OK;
1220 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001221 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001222 return FAIL;
1223}
1224
1225/*
1226 * "abs(expr)" function
1227 */
1228 static void
1229f_abs(typval_T *argvars, typval_T *rettv)
1230{
1231 if (argvars[0].v_type == VAR_FLOAT)
1232 {
1233 rettv->v_type = VAR_FLOAT;
1234 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1235 }
1236 else
1237 {
1238 varnumber_T n;
1239 int error = FALSE;
1240
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001241 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242 if (error)
1243 rettv->vval.v_number = -1;
1244 else if (n > 0)
1245 rettv->vval.v_number = n;
1246 else
1247 rettv->vval.v_number = -n;
1248 }
1249}
1250
1251/*
1252 * "acos()" function
1253 */
1254 static void
1255f_acos(typval_T *argvars, typval_T *rettv)
1256{
1257 float_T f = 0.0;
1258
1259 rettv->v_type = VAR_FLOAT;
1260 if (get_float_arg(argvars, &f) == OK)
1261 rettv->vval.v_float = acos(f);
1262 else
1263 rettv->vval.v_float = 0.0;
1264}
1265#endif
1266
1267/*
1268 * "add(list, item)" function
1269 */
1270 static void
1271f_add(typval_T *argvars, typval_T *rettv)
1272{
1273 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001274 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001275
1276 rettv->vval.v_number = 1; /* Default: Failed */
1277 if (argvars[0].v_type == VAR_LIST)
1278 {
1279 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001280 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001281 (char_u *)N_("add() argument"), TRUE)
1282 && list_append_tv(l, &argvars[1]) == OK)
1283 copy_tv(&argvars[0], rettv);
1284 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001285 else if (argvars[0].v_type == VAR_BLOB)
1286 {
1287 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001288 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001289 (char_u *)N_("add() argument"), TRUE))
1290 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001291 int error = FALSE;
1292 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1293
1294 if (!error)
1295 {
1296 ga_append(&b->bv_ga, (int)n);
1297 copy_tv(&argvars[0], rettv);
1298 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001299 }
1300 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001301 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001302 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001303}
1304
1305/*
1306 * "and(expr, expr)" function
1307 */
1308 static void
1309f_and(typval_T *argvars, typval_T *rettv)
1310{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001311 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1312 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001313}
1314
1315/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001316 * If there is a window for "curbuf", make it the current window.
1317 */
1318 static void
1319find_win_for_curbuf(void)
1320{
1321 wininfo_T *wip;
1322
1323 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1324 {
1325 if (wip->wi_win != NULL)
1326 {
1327 curwin = wip->wi_win;
1328 break;
1329 }
1330 }
1331}
1332
1333/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001334 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001335 */
1336 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001337set_buffer_lines(
1338 buf_T *buf,
1339 linenr_T lnum_arg,
1340 int append,
1341 typval_T *lines,
1342 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343{
Bram Moolenaarca851592018-06-06 21:04:07 +02001344 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1345 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001346 list_T *l = NULL;
1347 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001348 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001349 linenr_T append_lnum;
1350 buf_T *curbuf_save = NULL;
1351 win_T *curwin_save = NULL;
1352 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353
Bram Moolenaarca851592018-06-06 21:04:07 +02001354 /* When using the current buffer ml_mfp will be set if needed. Useful when
1355 * setline() is used on startup. For other buffers the buffer must be
1356 * loaded. */
1357 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001359 rettv->vval.v_number = 1; /* FAIL */
1360 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 }
1362
Bram Moolenaarca851592018-06-06 21:04:07 +02001363 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001365 curbuf_save = curbuf;
1366 curwin_save = curwin;
1367 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001368 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001369 }
1370
1371 if (append)
1372 // appendbufline() uses the line number below which we insert
1373 append_lnum = lnum - 1;
1374 else
1375 // setbufline() uses the line number above which we insert, we only
1376 // append if it's below the last line
1377 append_lnum = curbuf->b_ml.ml_line_count;
1378
1379 if (lines->v_type == VAR_LIST)
1380 {
1381 l = lines->vval.v_list;
1382 li = l->lv_first;
1383 }
1384 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001385 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001386
1387 /* default result is zero == OK */
1388 for (;;)
1389 {
1390 if (l != NULL)
1391 {
1392 /* list argument, get next string */
1393 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001394 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001395 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001396 li = li->li_next;
1397 }
1398
Bram Moolenaarca851592018-06-06 21:04:07 +02001399 rettv->vval.v_number = 1; /* FAIL */
1400 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1401 break;
1402
1403 /* When coming here from Insert mode, sync undo, so that this can be
1404 * undone separately from what was previously inserted. */
1405 if (u_sync_once == 2)
1406 {
1407 u_sync_once = 1; /* notify that u_sync() was called */
1408 u_sync(TRUE);
1409 }
1410
1411 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1412 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001413 // Existing line, replace it.
1414 // Removes any existing text properties.
1415 if (u_savesub(lnum) == OK && ml_replace_len(
1416 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001417 {
1418 changed_bytes(lnum, 0);
1419 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1420 check_cursor_col();
1421 rettv->vval.v_number = 0; /* OK */
1422 }
1423 }
1424 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1425 {
1426 /* append the line */
1427 ++added;
1428 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1429 rettv->vval.v_number = 0; /* OK */
1430 }
1431
1432 if (l == NULL) /* only one string argument */
1433 break;
1434 ++lnum;
1435 }
1436
1437 if (added > 0)
1438 {
1439 win_T *wp;
1440 tabpage_T *tp;
1441
1442 appended_lines_mark(append_lnum, added);
1443 FOR_ALL_TAB_WINDOWS(tp, wp)
1444 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1445 wp->w_cursor.lnum += added;
1446 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001447 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001448 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001449
1450 if (!is_curbuf)
1451 {
1452 curbuf = curbuf_save;
1453 curwin = curwin_save;
1454 }
1455}
1456
1457/*
1458 * "append(lnum, string/list)" function
1459 */
1460 static void
1461f_append(typval_T *argvars, typval_T *rettv)
1462{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001463 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001464
1465 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1466}
1467
1468/*
1469 * "appendbufline(buf, lnum, string/list)" function
1470 */
1471 static void
1472f_appendbufline(typval_T *argvars, typval_T *rettv)
1473{
1474 linenr_T lnum;
1475 buf_T *buf;
1476
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001477 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001478 if (buf == NULL)
1479 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001481 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001482 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001483 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1484 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001485}
1486
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001487#ifdef FEAT_FLOAT
1488/*
1489 * "asin()" function
1490 */
1491 static void
1492f_asin(typval_T *argvars, typval_T *rettv)
1493{
1494 float_T f = 0.0;
1495
1496 rettv->v_type = VAR_FLOAT;
1497 if (get_float_arg(argvars, &f) == OK)
1498 rettv->vval.v_float = asin(f);
1499 else
1500 rettv->vval.v_float = 0.0;
1501}
1502
1503/*
1504 * "atan()" function
1505 */
1506 static void
1507f_atan(typval_T *argvars, typval_T *rettv)
1508{
1509 float_T f = 0.0;
1510
1511 rettv->v_type = VAR_FLOAT;
1512 if (get_float_arg(argvars, &f) == OK)
1513 rettv->vval.v_float = atan(f);
1514 else
1515 rettv->vval.v_float = 0.0;
1516}
1517
1518/*
1519 * "atan2()" function
1520 */
1521 static void
1522f_atan2(typval_T *argvars, typval_T *rettv)
1523{
1524 float_T fx = 0.0, fy = 0.0;
1525
1526 rettv->v_type = VAR_FLOAT;
1527 if (get_float_arg(argvars, &fx) == OK
1528 && get_float_arg(&argvars[1], &fy) == OK)
1529 rettv->vval.v_float = atan2(fx, fy);
1530 else
1531 rettv->vval.v_float = 0.0;
1532}
1533#endif
1534
1535/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001536 * "balloon_show()" function
1537 */
1538#ifdef FEAT_BEVAL
1539 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001540f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1541{
1542 rettv->v_type = VAR_STRING;
1543 if (balloonEval != NULL)
1544 {
1545 if (balloonEval->msg == NULL)
1546 rettv->vval.v_string = NULL;
1547 else
1548 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1549 }
1550}
1551
1552 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001553f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1554{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001555 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001556 {
1557 if (argvars[0].v_type == VAR_LIST
1558# ifdef FEAT_GUI
1559 && !gui.in_use
1560# endif
1561 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001562 {
1563 list_T *l = argvars[0].vval.v_list;
1564
1565 // empty list removes the balloon
1566 post_balloon(balloonEval, NULL,
1567 l == NULL || l->lv_len == 0 ? NULL : l);
1568 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001569 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001570 {
1571 char_u *mesg = tv_get_string_chk(&argvars[0]);
1572
1573 if (mesg != NULL)
1574 // empty string removes the balloon
1575 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1576 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001577 }
1578}
1579
Bram Moolenaar669a8282017-11-19 20:13:05 +01001580# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001581 static void
1582f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1583{
1584 if (rettv_list_alloc(rettv) == OK)
1585 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001586 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001587
1588 if (msg != NULL)
1589 {
1590 pumitem_T *array;
1591 int size = split_message(msg, &array);
1592 int i;
1593
1594 /* Skip the first and last item, they are always empty. */
1595 for (i = 1; i < size - 1; ++i)
1596 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001597 while (size > 0)
1598 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001599 vim_free(array);
1600 }
1601 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001602}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001603# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001604#endif
1605
1606/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607 * "browse(save, title, initdir, default)" function
1608 */
1609 static void
1610f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1611{
1612#ifdef FEAT_BROWSE
1613 int save;
1614 char_u *title;
1615 char_u *initdir;
1616 char_u *defname;
1617 char_u buf[NUMBUFLEN];
1618 char_u buf2[NUMBUFLEN];
1619 int error = FALSE;
1620
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001621 save = (int)tv_get_number_chk(&argvars[0], &error);
1622 title = tv_get_string_chk(&argvars[1]);
1623 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1624 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625
1626 if (error || title == NULL || initdir == NULL || defname == NULL)
1627 rettv->vval.v_string = NULL;
1628 else
1629 rettv->vval.v_string =
1630 do_browse(save ? BROWSE_SAVE : 0,
1631 title, defname, NULL, initdir, NULL, curbuf);
1632#else
1633 rettv->vval.v_string = NULL;
1634#endif
1635 rettv->v_type = VAR_STRING;
1636}
1637
1638/*
1639 * "browsedir(title, initdir)" function
1640 */
1641 static void
1642f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1643{
1644#ifdef FEAT_BROWSE
1645 char_u *title;
1646 char_u *initdir;
1647 char_u buf[NUMBUFLEN];
1648
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001649 title = tv_get_string_chk(&argvars[0]);
1650 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651
1652 if (title == NULL || initdir == NULL)
1653 rettv->vval.v_string = NULL;
1654 else
1655 rettv->vval.v_string = do_browse(BROWSE_DIR,
1656 title, NULL, NULL, initdir, NULL, curbuf);
1657#else
1658 rettv->vval.v_string = NULL;
1659#endif
1660 rettv->v_type = VAR_STRING;
1661}
1662
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001663/*
1664 * Find a buffer by number or exact name.
1665 */
1666 static buf_T *
1667find_buffer(typval_T *avar)
1668{
1669 buf_T *buf = NULL;
1670
1671 if (avar->v_type == VAR_NUMBER)
1672 buf = buflist_findnr((int)avar->vval.v_number);
1673 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1674 {
1675 buf = buflist_findname_exp(avar->vval.v_string);
1676 if (buf == NULL)
1677 {
1678 /* No full path name match, try a match with a URL or a "nofile"
1679 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001680 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 if (buf->b_fname != NULL
1682 && (path_with_url(buf->b_fname)
1683#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001684 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685#endif
1686 )
1687 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1688 break;
1689 }
1690 }
1691 return buf;
1692}
1693
1694/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001695 * "bufadd(expr)" function
1696 */
1697 static void
1698f_bufadd(typval_T *argvars, typval_T *rettv)
1699{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001700 char_u *name = tv_get_string(&argvars[0]);
1701
1702 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001703}
1704
1705/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001706 * "bufexists(expr)" function
1707 */
1708 static void
1709f_bufexists(typval_T *argvars, typval_T *rettv)
1710{
1711 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1712}
1713
1714/*
1715 * "buflisted(expr)" function
1716 */
1717 static void
1718f_buflisted(typval_T *argvars, typval_T *rettv)
1719{
1720 buf_T *buf;
1721
1722 buf = find_buffer(&argvars[0]);
1723 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1724}
1725
1726/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001727 * "bufload(expr)" function
1728 */
1729 static void
1730f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1731{
1732 buf_T *buf = get_buf_arg(&argvars[0]);
1733
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001734 if (buf != NULL)
1735 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001736}
1737
1738/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001739 * "bufloaded(expr)" function
1740 */
1741 static void
1742f_bufloaded(typval_T *argvars, typval_T *rettv)
1743{
1744 buf_T *buf;
1745
1746 buf = find_buffer(&argvars[0]);
1747 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1748}
1749
1750 buf_T *
1751buflist_find_by_name(char_u *name, int curtab_only)
1752{
1753 int save_magic;
1754 char_u *save_cpo;
1755 buf_T *buf;
1756
1757 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1758 save_magic = p_magic;
1759 p_magic = TRUE;
1760 save_cpo = p_cpo;
1761 p_cpo = (char_u *)"";
1762
1763 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1764 TRUE, FALSE, curtab_only));
1765
1766 p_magic = save_magic;
1767 p_cpo = save_cpo;
1768 return buf;
1769}
1770
1771/*
1772 * Get buffer by number or pattern.
1773 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001774 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001775tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001776{
1777 char_u *name = tv->vval.v_string;
1778 buf_T *buf;
1779
1780 if (tv->v_type == VAR_NUMBER)
1781 return buflist_findnr((int)tv->vval.v_number);
1782 if (tv->v_type != VAR_STRING)
1783 return NULL;
1784 if (name == NULL || *name == NUL)
1785 return curbuf;
1786 if (name[0] == '$' && name[1] == NUL)
1787 return lastbuf;
1788
1789 buf = buflist_find_by_name(name, curtab_only);
1790
1791 /* If not found, try expanding the name, like done for bufexists(). */
1792 if (buf == NULL)
1793 buf = find_buffer(tv);
1794
1795 return buf;
1796}
1797
1798/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001799 * Get the buffer from "arg" and give an error and return NULL if it is not
1800 * valid.
1801 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001802 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001803get_buf_arg(typval_T *arg)
1804{
1805 buf_T *buf;
1806
1807 ++emsg_off;
1808 buf = tv_get_buf(arg, FALSE);
1809 --emsg_off;
1810 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001811 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001812 return buf;
1813}
1814
1815/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001816 * "bufname(expr)" function
1817 */
1818 static void
1819f_bufname(typval_T *argvars, typval_T *rettv)
1820{
1821 buf_T *buf;
1822
Bram Moolenaara8eee212019-08-24 22:14:58 +02001823 if (argvars[0].v_type == VAR_UNKNOWN)
1824 buf = curbuf;
1825 else
1826 {
1827 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1828 ++emsg_off;
1829 buf = tv_get_buf(&argvars[0], FALSE);
1830 --emsg_off;
1831 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 rettv->v_type = VAR_STRING;
1833 if (buf != NULL && buf->b_fname != NULL)
1834 rettv->vval.v_string = vim_strsave(buf->b_fname);
1835 else
1836 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001837}
1838
1839/*
1840 * "bufnr(expr)" function
1841 */
1842 static void
1843f_bufnr(typval_T *argvars, typval_T *rettv)
1844{
1845 buf_T *buf;
1846 int error = FALSE;
1847 char_u *name;
1848
Bram Moolenaara8eee212019-08-24 22:14:58 +02001849 if (argvars[0].v_type == VAR_UNKNOWN)
1850 buf = curbuf;
1851 else
1852 {
1853 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1854 ++emsg_off;
1855 buf = tv_get_buf(&argvars[0], FALSE);
1856 --emsg_off;
1857 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001858
Bram Moolenaara8eee212019-08-24 22:14:58 +02001859 // If the buffer isn't found and the second argument is not zero create a
1860 // new buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001861 if (buf == NULL
1862 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001863 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001864 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001865 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001866 && !error)
1867 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1868
1869 if (buf != NULL)
1870 rettv->vval.v_number = buf->b_fnum;
1871 else
1872 rettv->vval.v_number = -1;
1873}
1874
1875 static void
1876buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1877{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001878 win_T *wp;
1879 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001880 buf_T *buf;
1881
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001882 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001883 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001884 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001885 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001886 {
1887 ++winnr;
1888 if (wp->w_buffer == buf)
1889 break;
1890 }
1891 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001892 --emsg_off;
1893}
1894
1895/*
1896 * "bufwinid(nr)" function
1897 */
1898 static void
1899f_bufwinid(typval_T *argvars, typval_T *rettv)
1900{
1901 buf_win_common(argvars, rettv, FALSE);
1902}
1903
1904/*
1905 * "bufwinnr(nr)" function
1906 */
1907 static void
1908f_bufwinnr(typval_T *argvars, typval_T *rettv)
1909{
1910 buf_win_common(argvars, rettv, TRUE);
1911}
1912
1913/*
1914 * "byte2line(byte)" function
1915 */
1916 static void
1917f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1918{
1919#ifndef FEAT_BYTEOFF
1920 rettv->vval.v_number = -1;
1921#else
1922 long boff = 0;
1923
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001924 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001925 if (boff < 0)
1926 rettv->vval.v_number = -1;
1927 else
1928 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1929 (linenr_T)0, &boff);
1930#endif
1931}
1932
1933 static void
1934byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1935{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001936 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001937 char_u *str;
1938 varnumber_T idx;
1939
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001940 str = tv_get_string_chk(&argvars[0]);
1941 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942 rettv->vval.v_number = -1;
1943 if (str == NULL || idx < 0)
1944 return;
1945
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001946 t = str;
1947 for ( ; idx > 0; idx--)
1948 {
1949 if (*t == NUL) /* EOL reached */
1950 return;
1951 if (enc_utf8 && comp)
1952 t += utf_ptr2len(t);
1953 else
1954 t += (*mb_ptr2len)(t);
1955 }
1956 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957}
1958
1959/*
1960 * "byteidx()" function
1961 */
1962 static void
1963f_byteidx(typval_T *argvars, typval_T *rettv)
1964{
1965 byteidx(argvars, rettv, FALSE);
1966}
1967
1968/*
1969 * "byteidxcomp()" function
1970 */
1971 static void
1972f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1973{
1974 byteidx(argvars, rettv, TRUE);
1975}
1976
1977/*
1978 * "call(func, arglist [, dict])" function
1979 */
1980 static void
1981f_call(typval_T *argvars, typval_T *rettv)
1982{
1983 char_u *func;
1984 partial_T *partial = NULL;
1985 dict_T *selfdict = NULL;
1986
1987 if (argvars[1].v_type != VAR_LIST)
1988 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001989 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001990 return;
1991 }
1992 if (argvars[1].vval.v_list == NULL)
1993 return;
1994
1995 if (argvars[0].v_type == VAR_FUNC)
1996 func = argvars[0].vval.v_string;
1997 else if (argvars[0].v_type == VAR_PARTIAL)
1998 {
1999 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002000 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002001 }
2002 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002003 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004 if (*func == NUL)
2005 return; /* type error or empty name */
2006
2007 if (argvars[2].v_type != VAR_UNKNOWN)
2008 {
2009 if (argvars[2].v_type != VAR_DICT)
2010 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002011 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 return;
2013 }
2014 selfdict = argvars[2].vval.v_dict;
2015 }
2016
2017 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2018}
2019
2020#ifdef FEAT_FLOAT
2021/*
2022 * "ceil({float})" function
2023 */
2024 static void
2025f_ceil(typval_T *argvars, typval_T *rettv)
2026{
2027 float_T f = 0.0;
2028
2029 rettv->v_type = VAR_FLOAT;
2030 if (get_float_arg(argvars, &f) == OK)
2031 rettv->vval.v_float = ceil(f);
2032 else
2033 rettv->vval.v_float = 0.0;
2034}
2035#endif
2036
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002037/*
2038 * "changenr()" function
2039 */
2040 static void
2041f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2042{
2043 rettv->vval.v_number = curbuf->b_u_seq_cur;
2044}
2045
2046/*
2047 * "char2nr(string)" function
2048 */
2049 static void
2050f_char2nr(typval_T *argvars, typval_T *rettv)
2051{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052 if (has_mbyte)
2053 {
2054 int utf8 = 0;
2055
2056 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002057 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058
2059 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002060 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002062 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 }
2064 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002065 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002066}
2067
2068/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002069 * "chdir(dir)" function
2070 */
2071 static void
2072f_chdir(typval_T *argvars, typval_T *rettv)
2073{
2074 char_u *cwd;
2075 cdscope_T scope = CDSCOPE_GLOBAL;
2076
2077 rettv->v_type = VAR_STRING;
2078 rettv->vval.v_string = NULL;
2079
2080 if (argvars[0].v_type != VAR_STRING)
2081 return;
2082
2083 // Return the current directory
2084 cwd = alloc(MAXPATHL);
2085 if (cwd != NULL)
2086 {
2087 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2088 {
2089#ifdef BACKSLASH_IN_FILENAME
2090 slash_adjust(cwd);
2091#endif
2092 rettv->vval.v_string = vim_strsave(cwd);
2093 }
2094 vim_free(cwd);
2095 }
2096
2097 if (curwin->w_localdir != NULL)
2098 scope = CDSCOPE_WINDOW;
2099 else if (curtab->tp_localdir != NULL)
2100 scope = CDSCOPE_TABPAGE;
2101
2102 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2103 // Directory change failed
2104 VIM_CLEAR(rettv->vval.v_string);
2105}
2106
2107/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002108 * "cindent(lnum)" function
2109 */
2110 static void
2111f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2112{
2113#ifdef FEAT_CINDENT
2114 pos_T pos;
2115 linenr_T lnum;
2116
2117 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002118 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002119 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2120 {
2121 curwin->w_cursor.lnum = lnum;
2122 rettv->vval.v_number = get_c_indent();
2123 curwin->w_cursor = pos;
2124 }
2125 else
2126#endif
2127 rettv->vval.v_number = -1;
2128}
2129
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002130 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002131get_optional_window(typval_T *argvars, int idx)
2132{
2133 win_T *win = curwin;
2134
2135 if (argvars[idx].v_type != VAR_UNKNOWN)
2136 {
2137 win = find_win_by_nr_or_id(&argvars[idx]);
2138 if (win == NULL)
2139 {
2140 emsg(_(e_invalwindow));
2141 return NULL;
2142 }
2143 }
2144 return win;
2145}
2146
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002148 * "col(string)" function
2149 */
2150 static void
2151f_col(typval_T *argvars, typval_T *rettv)
2152{
2153 colnr_T col = 0;
2154 pos_T *fp;
2155 int fnum = curbuf->b_fnum;
2156
2157 fp = var2fpos(&argvars[0], FALSE, &fnum);
2158 if (fp != NULL && fnum == curbuf->b_fnum)
2159 {
2160 if (fp->col == MAXCOL)
2161 {
2162 /* '> can be MAXCOL, get the length of the line then */
2163 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2164 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2165 else
2166 col = MAXCOL;
2167 }
2168 else
2169 {
2170 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171 /* col(".") when the cursor is on the NUL at the end of the line
2172 * because of "coladd" can be seen as an extra column. */
2173 if (virtual_active() && fp == &curwin->w_cursor)
2174 {
2175 char_u *p = ml_get_cursor();
2176
2177 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2178 curwin->w_virtcol - curwin->w_cursor.coladd))
2179 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180 int l;
2181
2182 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2183 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002184 }
2185 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002186 }
2187 }
2188 rettv->vval.v_number = col;
2189}
2190
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002191/*
2192 * "confirm(message, buttons[, default [, type]])" function
2193 */
2194 static void
2195f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2196{
2197#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2198 char_u *message;
2199 char_u *buttons = NULL;
2200 char_u buf[NUMBUFLEN];
2201 char_u buf2[NUMBUFLEN];
2202 int def = 1;
2203 int type = VIM_GENERIC;
2204 char_u *typestr;
2205 int error = FALSE;
2206
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002207 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002208 if (message == NULL)
2209 error = TRUE;
2210 if (argvars[1].v_type != VAR_UNKNOWN)
2211 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002212 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002213 if (buttons == NULL)
2214 error = TRUE;
2215 if (argvars[2].v_type != VAR_UNKNOWN)
2216 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002217 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002218 if (argvars[3].v_type != VAR_UNKNOWN)
2219 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002220 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002221 if (typestr == NULL)
2222 error = TRUE;
2223 else
2224 {
2225 switch (TOUPPER_ASC(*typestr))
2226 {
2227 case 'E': type = VIM_ERROR; break;
2228 case 'Q': type = VIM_QUESTION; break;
2229 case 'I': type = VIM_INFO; break;
2230 case 'W': type = VIM_WARNING; break;
2231 case 'G': type = VIM_GENERIC; break;
2232 }
2233 }
2234 }
2235 }
2236 }
2237
2238 if (buttons == NULL || *buttons == NUL)
2239 buttons = (char_u *)_("&Ok");
2240
2241 if (!error)
2242 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2243 def, NULL, FALSE);
2244#endif
2245}
2246
2247/*
2248 * "copy()" function
2249 */
2250 static void
2251f_copy(typval_T *argvars, typval_T *rettv)
2252{
2253 item_copy(&argvars[0], rettv, FALSE, 0);
2254}
2255
2256#ifdef FEAT_FLOAT
2257/*
2258 * "cos()" function
2259 */
2260 static void
2261f_cos(typval_T *argvars, typval_T *rettv)
2262{
2263 float_T f = 0.0;
2264
2265 rettv->v_type = VAR_FLOAT;
2266 if (get_float_arg(argvars, &f) == OK)
2267 rettv->vval.v_float = cos(f);
2268 else
2269 rettv->vval.v_float = 0.0;
2270}
2271
2272/*
2273 * "cosh()" function
2274 */
2275 static void
2276f_cosh(typval_T *argvars, typval_T *rettv)
2277{
2278 float_T f = 0.0;
2279
2280 rettv->v_type = VAR_FLOAT;
2281 if (get_float_arg(argvars, &f) == OK)
2282 rettv->vval.v_float = cosh(f);
2283 else
2284 rettv->vval.v_float = 0.0;
2285}
2286#endif
2287
2288/*
2289 * "count()" function
2290 */
2291 static void
2292f_count(typval_T *argvars, typval_T *rettv)
2293{
2294 long n = 0;
2295 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002296 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297
Bram Moolenaar9966b212017-07-28 16:46:57 +02002298 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002299 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002300
2301 if (argvars[0].v_type == VAR_STRING)
2302 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002303 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002304 char_u *p = argvars[0].vval.v_string;
2305 char_u *next;
2306
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002307 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002308 {
2309 if (ic)
2310 {
2311 size_t len = STRLEN(expr);
2312
2313 while (*p != NUL)
2314 {
2315 if (MB_STRNICMP(p, expr, len) == 0)
2316 {
2317 ++n;
2318 p += len;
2319 }
2320 else
2321 MB_PTR_ADV(p);
2322 }
2323 }
2324 else
2325 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2326 != NULL)
2327 {
2328 ++n;
2329 p = next + STRLEN(expr);
2330 }
2331 }
2332
2333 }
2334 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002335 {
2336 listitem_T *li;
2337 list_T *l;
2338 long idx;
2339
2340 if ((l = argvars[0].vval.v_list) != NULL)
2341 {
2342 li = l->lv_first;
2343 if (argvars[2].v_type != VAR_UNKNOWN)
2344 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 if (argvars[3].v_type != VAR_UNKNOWN)
2346 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002347 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002348 if (!error)
2349 {
2350 li = list_find(l, idx);
2351 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002352 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353 }
2354 }
2355 if (error)
2356 li = NULL;
2357 }
2358
2359 for ( ; li != NULL; li = li->li_next)
2360 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2361 ++n;
2362 }
2363 }
2364 else if (argvars[0].v_type == VAR_DICT)
2365 {
2366 int todo;
2367 dict_T *d;
2368 hashitem_T *hi;
2369
2370 if ((d = argvars[0].vval.v_dict) != NULL)
2371 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002372 if (argvars[2].v_type != VAR_UNKNOWN)
2373 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002374 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002375 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002376 }
2377
2378 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2379 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2380 {
2381 if (!HASHITEM_EMPTY(hi))
2382 {
2383 --todo;
2384 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2385 ++n;
2386 }
2387 }
2388 }
2389 }
2390 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002391 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002392 rettv->vval.v_number = n;
2393}
2394
2395/*
2396 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2397 *
2398 * Checks the existence of a cscope connection.
2399 */
2400 static void
2401f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2402{
2403#ifdef FEAT_CSCOPE
2404 int num = 0;
2405 char_u *dbpath = NULL;
2406 char_u *prepend = NULL;
2407 char_u buf[NUMBUFLEN];
2408
2409 if (argvars[0].v_type != VAR_UNKNOWN
2410 && argvars[1].v_type != VAR_UNKNOWN)
2411 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002412 num = (int)tv_get_number(&argvars[0]);
2413 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002415 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002416 }
2417
2418 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2419#endif
2420}
2421
2422/*
2423 * "cursor(lnum, col)" function, or
2424 * "cursor(list)"
2425 *
2426 * Moves the cursor to the specified line and column.
2427 * Returns 0 when the position could be set, -1 otherwise.
2428 */
2429 static void
2430f_cursor(typval_T *argvars, typval_T *rettv)
2431{
2432 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002433 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 int set_curswant = TRUE;
2435
2436 rettv->vval.v_number = -1;
2437 if (argvars[1].v_type == VAR_UNKNOWN)
2438 {
2439 pos_T pos;
2440 colnr_T curswant = -1;
2441
2442 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2443 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002444 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002445 return;
2446 }
2447 line = pos.lnum;
2448 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002449 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 if (curswant >= 0)
2451 {
2452 curwin->w_curswant = curswant - 1;
2453 set_curswant = FALSE;
2454 }
2455 }
2456 else
2457 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002458 line = tv_get_lnum(argvars);
2459 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002461 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002462 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002463 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002464 return; /* type error; errmsg already given */
2465 if (line > 0)
2466 curwin->w_cursor.lnum = line;
2467 if (col > 0)
2468 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470
2471 /* Make sure the cursor is in a valid position. */
2472 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002473 /* Correct cursor for multi-byte character. */
2474 if (has_mbyte)
2475 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476
2477 curwin->w_set_curswant = set_curswant;
2478 rettv->vval.v_number = 0;
2479}
2480
Bram Moolenaar4f974752019-02-17 17:44:42 +01002481#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002482/*
2483 * "debugbreak()" function
2484 */
2485 static void
2486f_debugbreak(typval_T *argvars, typval_T *rettv)
2487{
2488 int pid;
2489
2490 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002491 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002492 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002493 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002494 else
2495 {
2496 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2497
2498 if (hProcess != NULL)
2499 {
2500 DebugBreakProcess(hProcess);
2501 CloseHandle(hProcess);
2502 rettv->vval.v_number = OK;
2503 }
2504 }
2505}
2506#endif
2507
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002508/*
2509 * "deepcopy()" function
2510 */
2511 static void
2512f_deepcopy(typval_T *argvars, typval_T *rettv)
2513{
2514 int noref = 0;
2515 int copyID;
2516
2517 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002518 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002519 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002520 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002521 else
2522 {
2523 copyID = get_copyID();
2524 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2525 }
2526}
2527
2528/*
2529 * "delete()" function
2530 */
2531 static void
2532f_delete(typval_T *argvars, typval_T *rettv)
2533{
2534 char_u nbuf[NUMBUFLEN];
2535 char_u *name;
2536 char_u *flags;
2537
2538 rettv->vval.v_number = -1;
2539 if (check_restricted() || check_secure())
2540 return;
2541
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002542 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 if (name == NULL || *name == NUL)
2544 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002545 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002546 return;
2547 }
2548
2549 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002550 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002551 else
2552 flags = (char_u *)"";
2553
2554 if (*flags == NUL)
2555 /* delete a file */
2556 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2557 else if (STRCMP(flags, "d") == 0)
2558 /* delete an empty directory */
2559 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2560 else if (STRCMP(flags, "rf") == 0)
2561 /* delete a directory recursively */
2562 rettv->vval.v_number = delete_recursive(name);
2563 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002564 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002565}
2566
2567/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002568 * "deletebufline()" function
2569 */
2570 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002571f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002572{
2573 buf_T *buf;
2574 linenr_T first, last;
2575 linenr_T lnum;
2576 long count;
2577 int is_curbuf;
2578 buf_T *curbuf_save = NULL;
2579 win_T *curwin_save = NULL;
2580 tabpage_T *tp;
2581 win_T *wp;
2582
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002583 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002584 if (buf == NULL)
2585 {
2586 rettv->vval.v_number = 1; /* FAIL */
2587 return;
2588 }
2589 is_curbuf = buf == curbuf;
2590
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002591 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002592 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002593 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002594 else
2595 last = first;
2596
2597 if (buf->b_ml.ml_mfp == NULL || first < 1
2598 || first > buf->b_ml.ml_line_count || last < first)
2599 {
2600 rettv->vval.v_number = 1; /* FAIL */
2601 return;
2602 }
2603
2604 if (!is_curbuf)
2605 {
2606 curbuf_save = curbuf;
2607 curwin_save = curwin;
2608 curbuf = buf;
2609 find_win_for_curbuf();
2610 }
2611 if (last > curbuf->b_ml.ml_line_count)
2612 last = curbuf->b_ml.ml_line_count;
2613 count = last - first + 1;
2614
2615 // When coming here from Insert mode, sync undo, so that this can be
2616 // undone separately from what was previously inserted.
2617 if (u_sync_once == 2)
2618 {
2619 u_sync_once = 1; // notify that u_sync() was called
2620 u_sync(TRUE);
2621 }
2622
2623 if (u_save(first - 1, last + 1) == FAIL)
2624 {
2625 rettv->vval.v_number = 1; /* FAIL */
2626 return;
2627 }
2628
2629 for (lnum = first; lnum <= last; ++lnum)
2630 ml_delete(first, TRUE);
2631
2632 FOR_ALL_TAB_WINDOWS(tp, wp)
2633 if (wp->w_buffer == buf)
2634 {
2635 if (wp->w_cursor.lnum > last)
2636 wp->w_cursor.lnum -= count;
2637 else if (wp->w_cursor.lnum> first)
2638 wp->w_cursor.lnum = first;
2639 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2640 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2641 }
2642 check_cursor_col();
2643 deleted_lines_mark(first, count);
2644
2645 if (!is_curbuf)
2646 {
2647 curbuf = curbuf_save;
2648 curwin = curwin_save;
2649 }
2650}
2651
2652/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 * "did_filetype()" function
2654 */
2655 static void
2656f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2657{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002658 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002659}
2660
2661/*
2662 * "diff_filler()" function
2663 */
2664 static void
2665f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2666{
2667#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002668 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002669#endif
2670}
2671
2672/*
2673 * "diff_hlID()" function
2674 */
2675 static void
2676f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2677{
2678#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002679 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002680 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002681 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 static int fnum = 0;
2683 static int change_start = 0;
2684 static int change_end = 0;
2685 static hlf_T hlID = (hlf_T)0;
2686 int filler_lines;
2687 int col;
2688
2689 if (lnum < 0) /* ignore type error in {lnum} arg */
2690 lnum = 0;
2691 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002692 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 || fnum != curbuf->b_fnum)
2694 {
2695 /* New line, buffer, change: need to get the values. */
2696 filler_lines = diff_check(curwin, lnum);
2697 if (filler_lines < 0)
2698 {
2699 if (filler_lines == -1)
2700 {
2701 change_start = MAXCOL;
2702 change_end = -1;
2703 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2704 hlID = HLF_ADD; /* added line */
2705 else
2706 hlID = HLF_CHD; /* changed line */
2707 }
2708 else
2709 hlID = HLF_ADD; /* added line */
2710 }
2711 else
2712 hlID = (hlf_T)0;
2713 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002714 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002715 fnum = curbuf->b_fnum;
2716 }
2717
2718 if (hlID == HLF_CHD || hlID == HLF_TXD)
2719 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002720 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002721 if (col >= change_start && col <= change_end)
2722 hlID = HLF_TXD; /* changed text */
2723 else
2724 hlID = HLF_CHD; /* changed line */
2725 }
2726 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2727#endif
2728}
2729
2730/*
2731 * "empty({expr})" function
2732 */
2733 static void
2734f_empty(typval_T *argvars, typval_T *rettv)
2735{
2736 int n = FALSE;
2737
2738 switch (argvars[0].v_type)
2739 {
2740 case VAR_STRING:
2741 case VAR_FUNC:
2742 n = argvars[0].vval.v_string == NULL
2743 || *argvars[0].vval.v_string == NUL;
2744 break;
2745 case VAR_PARTIAL:
2746 n = FALSE;
2747 break;
2748 case VAR_NUMBER:
2749 n = argvars[0].vval.v_number == 0;
2750 break;
2751 case VAR_FLOAT:
2752#ifdef FEAT_FLOAT
2753 n = argvars[0].vval.v_float == 0.0;
2754 break;
2755#endif
2756 case VAR_LIST:
2757 n = argvars[0].vval.v_list == NULL
2758 || argvars[0].vval.v_list->lv_first == NULL;
2759 break;
2760 case VAR_DICT:
2761 n = argvars[0].vval.v_dict == NULL
2762 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2763 break;
2764 case VAR_SPECIAL:
2765 n = argvars[0].vval.v_number != VVAL_TRUE;
2766 break;
2767
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002768 case VAR_BLOB:
2769 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002770 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2771 break;
2772
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002773 case VAR_JOB:
2774#ifdef FEAT_JOB_CHANNEL
2775 n = argvars[0].vval.v_job == NULL
2776 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2777 break;
2778#endif
2779 case VAR_CHANNEL:
2780#ifdef FEAT_JOB_CHANNEL
2781 n = argvars[0].vval.v_channel == NULL
2782 || !channel_is_open(argvars[0].vval.v_channel);
2783 break;
2784#endif
2785 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002786 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 n = TRUE;
2788 break;
2789 }
2790
2791 rettv->vval.v_number = n;
2792}
2793
2794/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002795 * "environ()" function
2796 */
2797 static void
2798f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2799{
2800#if !defined(AMIGA)
2801 int i = 0;
2802 char_u *entry, *value;
2803# ifdef MSWIN
2804 extern wchar_t **_wenviron;
2805# else
2806 extern char **environ;
2807# endif
2808
2809 if (rettv_dict_alloc(rettv) != OK)
2810 return;
2811
2812# ifdef MSWIN
2813 if (*_wenviron == NULL)
2814 return;
2815# else
2816 if (*environ == NULL)
2817 return;
2818# endif
2819
2820 for (i = 0; ; ++i)
2821 {
2822# ifdef MSWIN
2823 short_u *p;
2824
2825 if ((p = (short_u *)_wenviron[i]) == NULL)
2826 return;
2827 entry = utf16_to_enc(p, NULL);
2828# else
2829 if ((entry = (char_u *)environ[i]) == NULL)
2830 return;
2831 entry = vim_strsave(entry);
2832# endif
2833 if (entry == NULL) // out of memory
2834 return;
2835 if ((value = vim_strchr(entry, '=')) == NULL)
2836 {
2837 vim_free(entry);
2838 continue;
2839 }
2840 *value++ = NUL;
2841 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2842 vim_free(entry);
2843 }
2844#endif
2845}
2846
2847/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848 * "escape({string}, {chars})" function
2849 */
2850 static void
2851f_escape(typval_T *argvars, typval_T *rettv)
2852{
2853 char_u buf[NUMBUFLEN];
2854
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002855 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2856 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002857 rettv->v_type = VAR_STRING;
2858}
2859
2860/*
2861 * "eval()" function
2862 */
2863 static void
2864f_eval(typval_T *argvars, typval_T *rettv)
2865{
2866 char_u *s, *p;
2867
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002868 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869 if (s != NULL)
2870 s = skipwhite(s);
2871
2872 p = s;
2873 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2874 {
2875 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002876 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002877 need_clr_eos = FALSE;
2878 rettv->v_type = VAR_NUMBER;
2879 rettv->vval.v_number = 0;
2880 }
2881 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002882 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002883}
2884
2885/*
2886 * "eventhandler()" function
2887 */
2888 static void
2889f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2890{
2891 rettv->vval.v_number = vgetc_busy;
2892}
2893
2894/*
2895 * "executable()" function
2896 */
2897 static void
2898f_executable(typval_T *argvars, typval_T *rettv)
2899{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002900 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002901
2902 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02002903 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002904}
2905
2906static garray_T redir_execute_ga;
2907
2908/*
2909 * Append "value[value_len]" to the execute() output.
2910 */
2911 void
2912execute_redir_str(char_u *value, int value_len)
2913{
2914 int len;
2915
2916 if (value_len == -1)
2917 len = (int)STRLEN(value); /* Append the entire string */
2918 else
2919 len = value_len; /* Append only "value_len" characters */
2920 if (ga_grow(&redir_execute_ga, len) == OK)
2921 {
2922 mch_memmove((char *)redir_execute_ga.ga_data
2923 + redir_execute_ga.ga_len, value, len);
2924 redir_execute_ga.ga_len += len;
2925 }
2926}
2927
2928/*
2929 * Get next line from a list.
2930 * Called by do_cmdline() to get the next line.
2931 * Returns allocated string, or NULL for end of function.
2932 */
2933
2934 static char_u *
2935get_list_line(
2936 int c UNUSED,
2937 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002938 int indent UNUSED,
2939 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940{
2941 listitem_T **p = (listitem_T **)cookie;
2942 listitem_T *item = *p;
2943 char_u buf[NUMBUFLEN];
2944 char_u *s;
2945
2946 if (item == NULL)
2947 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002948 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002949 *p = item->li_next;
2950 return s == NULL ? NULL : vim_strsave(s);
2951}
2952
2953/*
2954 * "execute()" function
2955 */
2956 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002957execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002958{
2959 char_u *cmd = NULL;
2960 list_T *list = NULL;
2961 int save_msg_silent = msg_silent;
2962 int save_emsg_silent = emsg_silent;
2963 int save_emsg_noredir = emsg_noredir;
2964 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002965 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002966 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002967 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002968 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002969
2970 rettv->vval.v_string = NULL;
2971 rettv->v_type = VAR_STRING;
2972
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002973 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002974 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002975 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002976 if (list == NULL || list->lv_first == NULL)
2977 /* empty list, no commands, empty output */
2978 return;
2979 ++list->lv_refcount;
2980 }
2981 else
2982 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002983 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002984 if (cmd == NULL)
2985 return;
2986 }
2987
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002988 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 {
2990 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002991 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002992
2993 if (s == NULL)
2994 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002995 if (*s == NUL)
2996 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002997 if (STRNCMP(s, "silent", 6) == 0)
2998 ++msg_silent;
2999 if (STRCMP(s, "silent!") == 0)
3000 {
3001 emsg_silent = TRUE;
3002 emsg_noredir = TRUE;
3003 }
3004 }
3005 else
3006 ++msg_silent;
3007
3008 if (redir_execute)
3009 save_ga = redir_execute_ga;
3010 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3011 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003012 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003013 if (!echo_output)
3014 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003015
3016 if (cmd != NULL)
3017 do_cmdline_cmd(cmd);
3018 else
3019 {
3020 listitem_T *item = list->lv_first;
3021
3022 do_cmdline(NULL, get_list_line, (void *)&item,
3023 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3024 --list->lv_refcount;
3025 }
3026
Bram Moolenaard297f352017-01-29 20:31:21 +01003027 /* Need to append a NUL to the result. */
3028 if (ga_grow(&redir_execute_ga, 1) == OK)
3029 {
3030 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3031 rettv->vval.v_string = redir_execute_ga.ga_data;
3032 }
3033 else
3034 {
3035 ga_clear(&redir_execute_ga);
3036 rettv->vval.v_string = NULL;
3037 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038 msg_silent = save_msg_silent;
3039 emsg_silent = save_emsg_silent;
3040 emsg_noredir = save_emsg_noredir;
3041
3042 redir_execute = save_redir_execute;
3043 if (redir_execute)
3044 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003045 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003046
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003047 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003048 if (echo_output)
3049 // When not working silently: put it in column zero. A following
3050 // "echon" will overwrite the message, unavoidably.
3051 msg_col = 0;
3052 else
3053 // When working silently: Put it back where it was, since nothing
3054 // should have been written.
3055 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003056}
3057
3058/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003059 * "execute()" function
3060 */
3061 static void
3062f_execute(typval_T *argvars, typval_T *rettv)
3063{
3064 execute_common(argvars, rettv, 0);
3065}
3066
3067/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003068 * "exepath()" function
3069 */
3070 static void
3071f_exepath(typval_T *argvars, typval_T *rettv)
3072{
3073 char_u *p = NULL;
3074
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003075 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 rettv->v_type = VAR_STRING;
3077 rettv->vval.v_string = p;
3078}
3079
3080/*
3081 * "exists()" function
3082 */
3083 static void
3084f_exists(typval_T *argvars, typval_T *rettv)
3085{
3086 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003087 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003088
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003089 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003090 if (*p == '$') /* environment variable */
3091 {
3092 /* first try "normal" environment variables (fast) */
3093 if (mch_getenv(p + 1) != NULL)
3094 n = TRUE;
3095 else
3096 {
3097 /* try expanding things like $VIM and ${HOME} */
3098 p = expand_env_save(p);
3099 if (p != NULL && *p != '$')
3100 n = TRUE;
3101 vim_free(p);
3102 }
3103 }
3104 else if (*p == '&' || *p == '+') /* option */
3105 {
3106 n = (get_option_tv(&p, NULL, TRUE) == OK);
3107 if (*skipwhite(p) != NUL)
3108 n = FALSE; /* trailing garbage */
3109 }
3110 else if (*p == '*') /* internal or user defined function */
3111 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003112 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003113 }
3114 else if (*p == ':')
3115 {
3116 n = cmd_exists(p + 1);
3117 }
3118 else if (*p == '#')
3119 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003120 if (p[1] == '#')
3121 n = autocmd_supported(p + 2);
3122 else
3123 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003124 }
3125 else /* internal variable */
3126 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003127 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003128 }
3129
3130 rettv->vval.v_number = n;
3131}
3132
3133#ifdef FEAT_FLOAT
3134/*
3135 * "exp()" function
3136 */
3137 static void
3138f_exp(typval_T *argvars, typval_T *rettv)
3139{
3140 float_T f = 0.0;
3141
3142 rettv->v_type = VAR_FLOAT;
3143 if (get_float_arg(argvars, &f) == OK)
3144 rettv->vval.v_float = exp(f);
3145 else
3146 rettv->vval.v_float = 0.0;
3147}
3148#endif
3149
3150/*
3151 * "expand()" function
3152 */
3153 static void
3154f_expand(typval_T *argvars, typval_T *rettv)
3155{
3156 char_u *s;
3157 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003158 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003159 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3160 expand_T xpc;
3161 int error = FALSE;
3162 char_u *result;
3163
3164 rettv->v_type = VAR_STRING;
3165 if (argvars[1].v_type != VAR_UNKNOWN
3166 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003167 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003168 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003169 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003170
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003171 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003172 if (*s == '%' || *s == '#' || *s == '<')
3173 {
3174 ++emsg_off;
3175 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3176 --emsg_off;
3177 if (rettv->v_type == VAR_LIST)
3178 {
3179 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3180 list_append_string(rettv->vval.v_list, result, -1);
3181 else
3182 vim_free(result);
3183 }
3184 else
3185 rettv->vval.v_string = result;
3186 }
3187 else
3188 {
3189 /* When the optional second argument is non-zero, don't remove matches
3190 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3191 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003192 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003193 options |= WILD_KEEP_ALL;
3194 if (!error)
3195 {
3196 ExpandInit(&xpc);
3197 xpc.xp_context = EXPAND_FILES;
3198 if (p_wic)
3199 options += WILD_ICASE;
3200 if (rettv->v_type == VAR_STRING)
3201 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3202 options, WILD_ALL);
3203 else if (rettv_list_alloc(rettv) != FAIL)
3204 {
3205 int i;
3206
3207 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3208 for (i = 0; i < xpc.xp_numfiles; i++)
3209 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3210 ExpandCleanup(&xpc);
3211 }
3212 }
3213 else
3214 rettv->vval.v_string = NULL;
3215 }
3216}
3217
3218/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003219 * "expandcmd()" function
3220 * Expand all the special characters in a command string.
3221 */
3222 static void
3223f_expandcmd(typval_T *argvars, typval_T *rettv)
3224{
3225 exarg_T eap;
3226 char_u *cmdstr;
3227 char *errormsg = NULL;
3228
3229 rettv->v_type = VAR_STRING;
3230 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3231
3232 memset(&eap, 0, sizeof(eap));
3233 eap.cmd = cmdstr;
3234 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003235 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003236 eap.usefilter = FALSE;
3237 eap.nextcmd = NULL;
3238 eap.cmdidx = CMD_USER;
3239
3240 expand_filename(&eap, &cmdstr, &errormsg);
3241 if (errormsg != NULL && *errormsg != NUL)
3242 emsg(errormsg);
3243
3244 rettv->vval.v_string = cmdstr;
3245}
3246
3247/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003248 * "extend(list, list [, idx])" function
3249 * "extend(dict, dict [, action])" function
3250 */
3251 static void
3252f_extend(typval_T *argvars, typval_T *rettv)
3253{
3254 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3255
3256 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3257 {
3258 list_T *l1, *l2;
3259 listitem_T *item;
3260 long before;
3261 int error = FALSE;
3262
3263 l1 = argvars[0].vval.v_list;
3264 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003265 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003266 && l2 != NULL)
3267 {
3268 if (argvars[2].v_type != VAR_UNKNOWN)
3269 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003270 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003271 if (error)
3272 return; /* type error; errmsg already given */
3273
3274 if (before == l1->lv_len)
3275 item = NULL;
3276 else
3277 {
3278 item = list_find(l1, before);
3279 if (item == NULL)
3280 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003281 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003282 return;
3283 }
3284 }
3285 }
3286 else
3287 item = NULL;
3288 list_extend(l1, l2, item);
3289
3290 copy_tv(&argvars[0], rettv);
3291 }
3292 }
3293 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3294 {
3295 dict_T *d1, *d2;
3296 char_u *action;
3297 int i;
3298
3299 d1 = argvars[0].vval.v_dict;
3300 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003301 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003302 && d2 != NULL)
3303 {
3304 /* Check the third argument. */
3305 if (argvars[2].v_type != VAR_UNKNOWN)
3306 {
3307 static char *(av[]) = {"keep", "force", "error"};
3308
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003309 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003310 if (action == NULL)
3311 return; /* type error; errmsg already given */
3312 for (i = 0; i < 3; ++i)
3313 if (STRCMP(action, av[i]) == 0)
3314 break;
3315 if (i == 3)
3316 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003317 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003318 return;
3319 }
3320 }
3321 else
3322 action = (char_u *)"force";
3323
3324 dict_extend(d1, d2, action);
3325
3326 copy_tv(&argvars[0], rettv);
3327 }
3328 }
3329 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003330 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003331}
3332
3333/*
3334 * "feedkeys()" function
3335 */
3336 static void
3337f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3338{
3339 int remap = TRUE;
3340 int insert = FALSE;
3341 char_u *keys, *flags;
3342 char_u nbuf[NUMBUFLEN];
3343 int typed = FALSE;
3344 int execute = FALSE;
3345 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003346 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003347 char_u *keys_esc;
3348
3349 /* This is not allowed in the sandbox. If the commands would still be
3350 * executed in the sandbox it would be OK, but it probably happens later,
3351 * when "sandbox" is no longer set. */
3352 if (check_secure())
3353 return;
3354
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003355 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003356
3357 if (argvars[1].v_type != VAR_UNKNOWN)
3358 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003359 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360 for ( ; *flags != NUL; ++flags)
3361 {
3362 switch (*flags)
3363 {
3364 case 'n': remap = FALSE; break;
3365 case 'm': remap = TRUE; break;
3366 case 't': typed = TRUE; break;
3367 case 'i': insert = TRUE; break;
3368 case 'x': execute = TRUE; break;
3369 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003370 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003371 }
3372 }
3373 }
3374
3375 if (*keys != NUL || execute)
3376 {
3377 /* Need to escape K_SPECIAL and CSI before putting the string in the
3378 * typeahead buffer. */
3379 keys_esc = vim_strsave_escape_csi(keys);
3380 if (keys_esc != NULL)
3381 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003382 if (lowlevel)
3383 {
3384#ifdef USE_INPUT_BUF
3385 add_to_input_buf(keys, (int)STRLEN(keys));
3386#else
3387 emsg(_("E980: lowlevel input not supported"));
3388#endif
3389 }
3390 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003391 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003392 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003393 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003394 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003395#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003396 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003397#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003398 )
3399 typebuf_was_filled = TRUE;
3400 }
3401 vim_free(keys_esc);
3402
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403 if (execute)
3404 {
3405 int save_msg_scroll = msg_scroll;
3406
3407 /* Avoid a 1 second delay when the keys start Insert mode. */
3408 msg_scroll = FALSE;
3409
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003410 if (!dangerous)
3411 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003412 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003413 if (!dangerous)
3414 --ex_normal_busy;
3415
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003416 msg_scroll |= save_msg_scroll;
3417 }
3418 }
3419 }
3420}
3421
3422/*
3423 * "filereadable()" function
3424 */
3425 static void
3426f_filereadable(typval_T *argvars, typval_T *rettv)
3427{
3428 int fd;
3429 char_u *p;
3430 int n;
3431
3432#ifndef O_NONBLOCK
3433# define O_NONBLOCK 0
3434#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003435 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3437 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3438 {
3439 n = TRUE;
3440 close(fd);
3441 }
3442 else
3443 n = FALSE;
3444
3445 rettv->vval.v_number = n;
3446}
3447
3448/*
3449 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3450 * rights to write into.
3451 */
3452 static void
3453f_filewritable(typval_T *argvars, typval_T *rettv)
3454{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003455 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003456}
3457
3458 static void
3459findfilendir(
3460 typval_T *argvars UNUSED,
3461 typval_T *rettv,
3462 int find_what UNUSED)
3463{
3464#ifdef FEAT_SEARCHPATH
3465 char_u *fname;
3466 char_u *fresult = NULL;
3467 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3468 char_u *p;
3469 char_u pathbuf[NUMBUFLEN];
3470 int count = 1;
3471 int first = TRUE;
3472 int error = FALSE;
3473#endif
3474
3475 rettv->vval.v_string = NULL;
3476 rettv->v_type = VAR_STRING;
3477
3478#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003479 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003480
3481 if (argvars[1].v_type != VAR_UNKNOWN)
3482 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003483 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003484 if (p == NULL)
3485 error = TRUE;
3486 else
3487 {
3488 if (*p != NUL)
3489 path = p;
3490
3491 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003492 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003493 }
3494 }
3495
3496 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3497 error = TRUE;
3498
3499 if (*fname != NUL && !error)
3500 {
3501 do
3502 {
3503 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3504 vim_free(fresult);
3505 fresult = find_file_in_path_option(first ? fname : NULL,
3506 first ? (int)STRLEN(fname) : 0,
3507 0, first, path,
3508 find_what,
3509 curbuf->b_ffname,
3510 find_what == FINDFILE_DIR
3511 ? (char_u *)"" : curbuf->b_p_sua);
3512 first = FALSE;
3513
3514 if (fresult != NULL && rettv->v_type == VAR_LIST)
3515 list_append_string(rettv->vval.v_list, fresult, -1);
3516
3517 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3518 }
3519
3520 if (rettv->v_type == VAR_STRING)
3521 rettv->vval.v_string = fresult;
3522#endif
3523}
3524
3525/*
3526 * "filter()" function
3527 */
3528 static void
3529f_filter(typval_T *argvars, typval_T *rettv)
3530{
3531 filter_map(argvars, rettv, FALSE);
3532}
3533
3534/*
3535 * "finddir({fname}[, {path}[, {count}]])" function
3536 */
3537 static void
3538f_finddir(typval_T *argvars, typval_T *rettv)
3539{
3540 findfilendir(argvars, rettv, FINDFILE_DIR);
3541}
3542
3543/*
3544 * "findfile({fname}[, {path}[, {count}]])" function
3545 */
3546 static void
3547f_findfile(typval_T *argvars, typval_T *rettv)
3548{
3549 findfilendir(argvars, rettv, FINDFILE_FILE);
3550}
3551
3552#ifdef FEAT_FLOAT
3553/*
3554 * "float2nr({float})" function
3555 */
3556 static void
3557f_float2nr(typval_T *argvars, typval_T *rettv)
3558{
3559 float_T f = 0.0;
3560
3561 if (get_float_arg(argvars, &f) == OK)
3562 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003563 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003564 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003565 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003566 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003567 else
3568 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569 }
3570}
3571
3572/*
3573 * "floor({float})" function
3574 */
3575 static void
3576f_floor(typval_T *argvars, typval_T *rettv)
3577{
3578 float_T f = 0.0;
3579
3580 rettv->v_type = VAR_FLOAT;
3581 if (get_float_arg(argvars, &f) == OK)
3582 rettv->vval.v_float = floor(f);
3583 else
3584 rettv->vval.v_float = 0.0;
3585}
3586
3587/*
3588 * "fmod()" function
3589 */
3590 static void
3591f_fmod(typval_T *argvars, typval_T *rettv)
3592{
3593 float_T fx = 0.0, fy = 0.0;
3594
3595 rettv->v_type = VAR_FLOAT;
3596 if (get_float_arg(argvars, &fx) == OK
3597 && get_float_arg(&argvars[1], &fy) == OK)
3598 rettv->vval.v_float = fmod(fx, fy);
3599 else
3600 rettv->vval.v_float = 0.0;
3601}
3602#endif
3603
3604/*
3605 * "fnameescape({string})" function
3606 */
3607 static void
3608f_fnameescape(typval_T *argvars, typval_T *rettv)
3609{
3610 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003611 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003612 rettv->v_type = VAR_STRING;
3613}
3614
3615/*
3616 * "fnamemodify({fname}, {mods})" function
3617 */
3618 static void
3619f_fnamemodify(typval_T *argvars, typval_T *rettv)
3620{
3621 char_u *fname;
3622 char_u *mods;
3623 int usedlen = 0;
3624 int len;
3625 char_u *fbuf = NULL;
3626 char_u buf[NUMBUFLEN];
3627
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003628 fname = tv_get_string_chk(&argvars[0]);
3629 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003630 if (fname == NULL || mods == NULL)
3631 fname = NULL;
3632 else
3633 {
3634 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003635 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636 }
3637
3638 rettv->v_type = VAR_STRING;
3639 if (fname == NULL)
3640 rettv->vval.v_string = NULL;
3641 else
3642 rettv->vval.v_string = vim_strnsave(fname, len);
3643 vim_free(fbuf);
3644}
3645
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003646/*
3647 * "foldclosed()" function
3648 */
3649 static void
3650foldclosed_both(
3651 typval_T *argvars UNUSED,
3652 typval_T *rettv,
3653 int end UNUSED)
3654{
3655#ifdef FEAT_FOLDING
3656 linenr_T lnum;
3657 linenr_T first, last;
3658
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003659 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003660 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3661 {
3662 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3663 {
3664 if (end)
3665 rettv->vval.v_number = (varnumber_T)last;
3666 else
3667 rettv->vval.v_number = (varnumber_T)first;
3668 return;
3669 }
3670 }
3671#endif
3672 rettv->vval.v_number = -1;
3673}
3674
3675/*
3676 * "foldclosed()" function
3677 */
3678 static void
3679f_foldclosed(typval_T *argvars, typval_T *rettv)
3680{
3681 foldclosed_both(argvars, rettv, FALSE);
3682}
3683
3684/*
3685 * "foldclosedend()" function
3686 */
3687 static void
3688f_foldclosedend(typval_T *argvars, typval_T *rettv)
3689{
3690 foldclosed_both(argvars, rettv, TRUE);
3691}
3692
3693/*
3694 * "foldlevel()" function
3695 */
3696 static void
3697f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3698{
3699#ifdef FEAT_FOLDING
3700 linenr_T lnum;
3701
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003702 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003703 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3704 rettv->vval.v_number = foldLevel(lnum);
3705#endif
3706}
3707
3708/*
3709 * "foldtext()" function
3710 */
3711 static void
3712f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3713{
3714#ifdef FEAT_FOLDING
3715 linenr_T foldstart;
3716 linenr_T foldend;
3717 char_u *dashes;
3718 linenr_T lnum;
3719 char_u *s;
3720 char_u *r;
3721 int len;
3722 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003723 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003724#endif
3725
3726 rettv->v_type = VAR_STRING;
3727 rettv->vval.v_string = NULL;
3728#ifdef FEAT_FOLDING
3729 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3730 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3731 dashes = get_vim_var_str(VV_FOLDDASHES);
3732 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3733 && dashes != NULL)
3734 {
3735 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003736 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003737 if (!linewhite(lnum))
3738 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003739
3740 /* Find interesting text in this line. */
3741 s = skipwhite(ml_get(lnum));
3742 /* skip C comment-start */
3743 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3744 {
3745 s = skipwhite(s + 2);
3746 if (*skipwhite(s) == NUL
3747 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3748 {
3749 s = skipwhite(ml_get(lnum + 1));
3750 if (*s == '*')
3751 s = skipwhite(s + 1);
3752 }
3753 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003754 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003755 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003756 r = alloc(STRLEN(txt)
3757 + STRLEN(dashes) // for %s
3758 + 20 // for %3ld
3759 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003760 if (r != NULL)
3761 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003762 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003763 len = (int)STRLEN(r);
3764 STRCAT(r, s);
3765 /* remove 'foldmarker' and 'commentstring' */
3766 foldtext_cleanup(r + len);
3767 rettv->vval.v_string = r;
3768 }
3769 }
3770#endif
3771}
3772
3773/*
3774 * "foldtextresult(lnum)" function
3775 */
3776 static void
3777f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3778{
3779#ifdef FEAT_FOLDING
3780 linenr_T lnum;
3781 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003782 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003783 foldinfo_T foldinfo;
3784 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003785 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003786#endif
3787
3788 rettv->v_type = VAR_STRING;
3789 rettv->vval.v_string = NULL;
3790#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003791 if (entered)
3792 return; /* reject recursive use */
3793 entered = TRUE;
3794
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003795 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003796 /* treat illegal types and illegal string values for {lnum} the same */
3797 if (lnum < 0)
3798 lnum = 0;
3799 fold_count = foldedCount(curwin, lnum, &foldinfo);
3800 if (fold_count > 0)
3801 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003802 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3803 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003804 if (text == buf)
3805 text = vim_strsave(text);
3806 rettv->vval.v_string = text;
3807 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003808
3809 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003810#endif
3811}
3812
3813/*
3814 * "foreground()" function
3815 */
3816 static void
3817f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3818{
3819#ifdef FEAT_GUI
3820 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003821 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003822 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003823 return;
3824 }
3825#endif
3826#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003827 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003828#endif
3829}
3830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003832common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003833{
3834 char_u *s;
3835 char_u *name;
3836 int use_string = FALSE;
3837 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003838 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003839
3840 if (argvars[0].v_type == VAR_FUNC)
3841 {
3842 /* function(MyFunc, [arg], dict) */
3843 s = argvars[0].vval.v_string;
3844 }
3845 else if (argvars[0].v_type == VAR_PARTIAL
3846 && argvars[0].vval.v_partial != NULL)
3847 {
3848 /* function(dict.MyFunc, [arg]) */
3849 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003850 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003851 }
3852 else
3853 {
3854 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003855 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003856 use_string = TRUE;
3857 }
3858
Bram Moolenaar843b8842016-08-21 14:36:15 +02003859 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003860 {
3861 name = s;
3862 trans_name = trans_function_name(&name, FALSE,
3863 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3864 if (*name != NUL)
3865 s = NULL;
3866 }
3867
Bram Moolenaar843b8842016-08-21 14:36:15 +02003868 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3869 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003870 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003872 else if (trans_name != NULL && (is_funcref
3873 ? find_func(trans_name) == NULL
3874 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003875 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003876 else
3877 {
3878 int dict_idx = 0;
3879 int arg_idx = 0;
3880 list_T *list = NULL;
3881
3882 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3883 {
3884 char sid_buf[25];
3885 int off = *s == 's' ? 2 : 5;
3886
3887 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3888 * also be called from another script. Using trans_function_name()
3889 * would also work, but some plugins depend on the name being
3890 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003891 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003892 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003893 if (name != NULL)
3894 {
3895 STRCPY(name, sid_buf);
3896 STRCAT(name, s + off);
3897 }
3898 }
3899 else
3900 name = vim_strsave(s);
3901
3902 if (argvars[1].v_type != VAR_UNKNOWN)
3903 {
3904 if (argvars[2].v_type != VAR_UNKNOWN)
3905 {
3906 /* function(name, [args], dict) */
3907 arg_idx = 1;
3908 dict_idx = 2;
3909 }
3910 else if (argvars[1].v_type == VAR_DICT)
3911 /* function(name, dict) */
3912 dict_idx = 1;
3913 else
3914 /* function(name, [args]) */
3915 arg_idx = 1;
3916 if (dict_idx > 0)
3917 {
3918 if (argvars[dict_idx].v_type != VAR_DICT)
3919 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003920 emsg(_("E922: expected 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 if (argvars[dict_idx].vval.v_dict == NULL)
3925 dict_idx = 0;
3926 }
3927 if (arg_idx > 0)
3928 {
3929 if (argvars[arg_idx].v_type != VAR_LIST)
3930 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003931 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003933 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934 }
3935 list = argvars[arg_idx].vval.v_list;
3936 if (list == NULL || list->lv_len == 0)
3937 arg_idx = 0;
3938 }
3939 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003940 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003942 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003943
3944 /* result is a VAR_PARTIAL */
3945 if (pt == NULL)
3946 vim_free(name);
3947 else
3948 {
3949 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3950 {
3951 listitem_T *li;
3952 int i = 0;
3953 int arg_len = 0;
3954 int lv_len = 0;
3955
3956 if (arg_pt != NULL)
3957 arg_len = arg_pt->pt_argc;
3958 if (list != NULL)
3959 lv_len = list->lv_len;
3960 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003961 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003962 if (pt->pt_argv == NULL)
3963 {
3964 vim_free(pt);
3965 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003966 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003967 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003968 for (i = 0; i < arg_len; i++)
3969 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3970 if (lv_len > 0)
3971 for (li = list->lv_first; li != NULL;
3972 li = li->li_next)
3973 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003974 }
3975
3976 /* For "function(dict.func, [], dict)" and "func" is a partial
3977 * use "dict". That is backwards compatible. */
3978 if (dict_idx > 0)
3979 {
3980 /* The dict is bound explicitly, pt_auto is FALSE. */
3981 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3982 ++pt->pt_dict->dv_refcount;
3983 }
3984 else if (arg_pt != NULL)
3985 {
3986 /* If the dict was bound automatically the result is also
3987 * bound automatically. */
3988 pt->pt_dict = arg_pt->pt_dict;
3989 pt->pt_auto = arg_pt->pt_auto;
3990 if (pt->pt_dict != NULL)
3991 ++pt->pt_dict->dv_refcount;
3992 }
3993
3994 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003995 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3996 {
3997 pt->pt_func = arg_pt->pt_func;
3998 func_ptr_ref(pt->pt_func);
3999 vim_free(name);
4000 }
4001 else if (is_funcref)
4002 {
4003 pt->pt_func = find_func(trans_name);
4004 func_ptr_ref(pt->pt_func);
4005 vim_free(name);
4006 }
4007 else
4008 {
4009 pt->pt_name = name;
4010 func_ref(name);
4011 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012 }
4013 rettv->v_type = VAR_PARTIAL;
4014 rettv->vval.v_partial = pt;
4015 }
4016 else
4017 {
4018 /* result is a VAR_FUNC */
4019 rettv->v_type = VAR_FUNC;
4020 rettv->vval.v_string = name;
4021 func_ref(name);
4022 }
4023 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004024theend:
4025 vim_free(trans_name);
4026}
4027
4028/*
4029 * "funcref()" function
4030 */
4031 static void
4032f_funcref(typval_T *argvars, typval_T *rettv)
4033{
4034 common_function(argvars, rettv, TRUE);
4035}
4036
4037/*
4038 * "function()" function
4039 */
4040 static void
4041f_function(typval_T *argvars, typval_T *rettv)
4042{
4043 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044}
4045
4046/*
4047 * "garbagecollect()" function
4048 */
4049 static void
4050f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4051{
4052 /* This is postponed until we are back at the toplevel, because we may be
4053 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4054 want_garbage_collect = TRUE;
4055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004056 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057 garbage_collect_at_exit = TRUE;
4058}
4059
4060/*
4061 * "get()" function
4062 */
4063 static void
4064f_get(typval_T *argvars, typval_T *rettv)
4065{
4066 listitem_T *li;
4067 list_T *l;
4068 dictitem_T *di;
4069 dict_T *d;
4070 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004071 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004073 if (argvars[0].v_type == VAR_BLOB)
4074 {
4075 int error = FALSE;
4076 int idx = tv_get_number_chk(&argvars[1], &error);
4077
4078 if (!error)
4079 {
4080 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004081 if (idx < 0)
4082 idx = blob_len(argvars[0].vval.v_blob) + idx;
4083 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4084 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004085 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004086 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004087 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004088 tv = rettv;
4089 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004090 }
4091 }
4092 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004093 {
4094 if ((l = argvars[0].vval.v_list) != NULL)
4095 {
4096 int error = FALSE;
4097
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004098 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099 if (!error && li != NULL)
4100 tv = &li->li_tv;
4101 }
4102 }
4103 else if (argvars[0].v_type == VAR_DICT)
4104 {
4105 if ((d = argvars[0].vval.v_dict) != NULL)
4106 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004107 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004108 if (di != NULL)
4109 tv = &di->di_tv;
4110 }
4111 }
4112 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4113 {
4114 partial_T *pt;
4115 partial_T fref_pt;
4116
4117 if (argvars[0].v_type == VAR_PARTIAL)
4118 pt = argvars[0].vval.v_partial;
4119 else
4120 {
4121 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4122 fref_pt.pt_name = argvars[0].vval.v_string;
4123 pt = &fref_pt;
4124 }
4125
4126 if (pt != NULL)
4127 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004128 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004129 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004130
4131 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4132 {
4133 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004134 n = partial_name(pt);
4135 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004136 rettv->vval.v_string = NULL;
4137 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004138 {
4139 rettv->vval.v_string = vim_strsave(n);
4140 if (rettv->v_type == VAR_FUNC)
4141 func_ref(rettv->vval.v_string);
4142 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004143 }
4144 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004145 {
4146 what_is_dict = TRUE;
4147 if (pt->pt_dict != NULL)
4148 rettv_dict_set(rettv, pt->pt_dict);
4149 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004150 else if (STRCMP(what, "args") == 0)
4151 {
4152 rettv->v_type = VAR_LIST;
4153 if (rettv_list_alloc(rettv) == OK)
4154 {
4155 int i;
4156
4157 for (i = 0; i < pt->pt_argc; ++i)
4158 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4159 }
4160 }
4161 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004162 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004163
4164 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4165 // third argument
4166 if (!what_is_dict)
4167 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004168 }
4169 }
4170 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004171 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004172
4173 if (tv == NULL)
4174 {
4175 if (argvars[2].v_type != VAR_UNKNOWN)
4176 copy_tv(&argvars[2], rettv);
4177 }
4178 else
4179 copy_tv(tv, rettv);
4180}
4181
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004182/*
4183 * Returns buffer options, variables and other attributes in a dictionary.
4184 */
4185 static dict_T *
4186get_buffer_info(buf_T *buf)
4187{
4188 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004189 tabpage_T *tp;
4190 win_T *wp;
4191 list_T *windows;
4192
4193 dict = dict_alloc();
4194 if (dict == NULL)
4195 return NULL;
4196
Bram Moolenaare0be1672018-07-08 16:50:37 +02004197 dict_add_number(dict, "bufnr", buf->b_fnum);
4198 dict_add_string(dict, "name", buf->b_ffname);
4199 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4200 : buflist_findlnum(buf));
4201 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4202 dict_add_number(dict, "listed", buf->b_p_bl);
4203 dict_add_number(dict, "changed", bufIsChanged(buf));
4204 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4205 dict_add_number(dict, "hidden",
4206 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004207
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004208 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004209 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004210
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004211 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004212 windows = list_alloc();
4213 if (windows != NULL)
4214 {
4215 FOR_ALL_TAB_WINDOWS(tp, wp)
4216 if (wp->w_buffer == buf)
4217 list_append_number(windows, (varnumber_T)wp->w_id);
4218 dict_add_list(dict, "windows", windows);
4219 }
4220
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004221#ifdef FEAT_TEXT_PROP
4222 // List of popup windows displaying this buffer
4223 windows = list_alloc();
4224 if (windows != NULL)
4225 {
4226 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4227 if (wp->w_buffer == buf)
4228 list_append_number(windows, (varnumber_T)wp->w_id);
4229 FOR_ALL_TABPAGES(tp)
4230 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4231 if (wp->w_buffer == buf)
4232 list_append_number(windows, (varnumber_T)wp->w_id);
4233
4234 dict_add_list(dict, "popups", windows);
4235 }
4236#endif
4237
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004238#ifdef FEAT_SIGNS
4239 if (buf->b_signlist != NULL)
4240 {
4241 /* List of signs placed in this buffer */
4242 list_T *signs = list_alloc();
4243 if (signs != NULL)
4244 {
4245 get_buffer_signs(buf, signs);
4246 dict_add_list(dict, "signs", signs);
4247 }
4248 }
4249#endif
4250
4251 return dict;
4252}
4253
4254/*
4255 * "getbufinfo()" function
4256 */
4257 static void
4258f_getbufinfo(typval_T *argvars, typval_T *rettv)
4259{
4260 buf_T *buf = NULL;
4261 buf_T *argbuf = NULL;
4262 dict_T *d;
4263 int filtered = FALSE;
4264 int sel_buflisted = FALSE;
4265 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004266 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004267
4268 if (rettv_list_alloc(rettv) != OK)
4269 return;
4270
4271 /* List of all the buffers or selected buffers */
4272 if (argvars[0].v_type == VAR_DICT)
4273 {
4274 dict_T *sel_d = argvars[0].vval.v_dict;
4275
4276 if (sel_d != NULL)
4277 {
4278 dictitem_T *di;
4279
4280 filtered = TRUE;
4281
4282 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004283 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004284 sel_buflisted = TRUE;
4285
4286 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004287 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004288 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004289
4290 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004291 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004292 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004293 }
4294 }
4295 else if (argvars[0].v_type != VAR_UNKNOWN)
4296 {
4297 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004298 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004299 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004300 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004301 --emsg_off;
4302 if (argbuf == NULL)
4303 return;
4304 }
4305
4306 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004307 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004308 {
4309 if (argbuf != NULL && argbuf != buf)
4310 continue;
4311 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004312 || (sel_buflisted && !buf->b_p_bl)
4313 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004314 continue;
4315
4316 d = get_buffer_info(buf);
4317 if (d != NULL)
4318 list_append_dict(rettv->vval.v_list, d);
4319 if (argbuf != NULL)
4320 return;
4321 }
4322}
4323
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004324/*
4325 * Get line or list of lines from buffer "buf" into "rettv".
4326 * Return a range (from start to end) of lines in rettv from the specified
4327 * buffer.
4328 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4329 */
4330 static void
4331get_buffer_lines(
4332 buf_T *buf,
4333 linenr_T start,
4334 linenr_T end,
4335 int retlist,
4336 typval_T *rettv)
4337{
4338 char_u *p;
4339
4340 rettv->v_type = VAR_STRING;
4341 rettv->vval.v_string = NULL;
4342 if (retlist && rettv_list_alloc(rettv) == FAIL)
4343 return;
4344
4345 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4346 return;
4347
4348 if (!retlist)
4349 {
4350 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4351 p = ml_get_buf(buf, start, FALSE);
4352 else
4353 p = (char_u *)"";
4354 rettv->vval.v_string = vim_strsave(p);
4355 }
4356 else
4357 {
4358 if (end < start)
4359 return;
4360
4361 if (start < 1)
4362 start = 1;
4363 if (end > buf->b_ml.ml_line_count)
4364 end = buf->b_ml.ml_line_count;
4365 while (start <= end)
4366 if (list_append_string(rettv->vval.v_list,
4367 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4368 break;
4369 }
4370}
4371
4372/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004373 * "getbufline()" function
4374 */
4375 static void
4376f_getbufline(typval_T *argvars, typval_T *rettv)
4377{
4378 linenr_T lnum;
4379 linenr_T end;
4380 buf_T *buf;
4381
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004382 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004383 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004384 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004385 --emsg_off;
4386
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004387 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004388 if (argvars[2].v_type == VAR_UNKNOWN)
4389 end = lnum;
4390 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004391 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004392
4393 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4394}
4395
4396/*
4397 * "getbufvar()" function
4398 */
4399 static void
4400f_getbufvar(typval_T *argvars, typval_T *rettv)
4401{
4402 buf_T *buf;
4403 buf_T *save_curbuf;
4404 char_u *varname;
4405 dictitem_T *v;
4406 int done = FALSE;
4407
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004408 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4409 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004410 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004411 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004412
4413 rettv->v_type = VAR_STRING;
4414 rettv->vval.v_string = NULL;
4415
4416 if (buf != NULL && varname != NULL)
4417 {
4418 /* set curbuf to be our buf, temporarily */
4419 save_curbuf = curbuf;
4420 curbuf = buf;
4421
Bram Moolenaar30567352016-08-27 21:25:44 +02004422 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004423 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004424 if (varname[1] == NUL)
4425 {
4426 /* get all buffer-local options in a dict */
4427 dict_T *opts = get_winbuf_options(TRUE);
4428
4429 if (opts != NULL)
4430 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004431 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004432 done = TRUE;
4433 }
4434 }
4435 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4436 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004437 done = TRUE;
4438 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004439 else
4440 {
4441 /* Look up the variable. */
4442 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4443 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4444 'b', varname, FALSE);
4445 if (v != NULL)
4446 {
4447 copy_tv(&v->di_tv, rettv);
4448 done = TRUE;
4449 }
4450 }
4451
4452 /* restore previous notion of curbuf */
4453 curbuf = save_curbuf;
4454 }
4455
4456 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4457 /* use the default value */
4458 copy_tv(&argvars[2], rettv);
4459
4460 --emsg_off;
4461}
4462
4463/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004464 * "getchangelist()" function
4465 */
4466 static void
4467f_getchangelist(typval_T *argvars, typval_T *rettv)
4468{
4469#ifdef FEAT_JUMPLIST
4470 buf_T *buf;
4471 int i;
4472 list_T *l;
4473 dict_T *d;
4474#endif
4475
4476 if (rettv_list_alloc(rettv) != OK)
4477 return;
4478
4479#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004480 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004481 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004482 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004483 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004484 if (buf == NULL)
4485 return;
4486
4487 l = list_alloc();
4488 if (l == NULL)
4489 return;
4490
4491 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4492 return;
4493 /*
4494 * The current window change list index tracks only the position in the
4495 * current buffer change list. For other buffers, use the change list
4496 * length as the current index.
4497 */
4498 list_append_number(rettv->vval.v_list,
4499 (varnumber_T)((buf == curwin->w_buffer)
4500 ? curwin->w_changelistidx : buf->b_changelistlen));
4501
4502 for (i = 0; i < buf->b_changelistlen; ++i)
4503 {
4504 if (buf->b_changelist[i].lnum == 0)
4505 continue;
4506 if ((d = dict_alloc()) == NULL)
4507 return;
4508 if (list_append_dict(l, d) == FAIL)
4509 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004510 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4511 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004512 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004513 }
4514#endif
4515}
4516/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517 * "getchar()" function
4518 */
4519 static void
4520f_getchar(typval_T *argvars, typval_T *rettv)
4521{
4522 varnumber_T n;
4523 int error = FALSE;
4524
Bram Moolenaar84d93902018-09-11 20:10:20 +02004525#ifdef MESSAGE_QUEUE
4526 // vpeekc() used to check for messages, but that caused problems, invoking
4527 // a callback where it was not expected. Some plugins use getchar(1) in a
4528 // loop to await a message, therefore make sure we check for messages here.
4529 parse_queued_messages();
4530#endif
4531
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004532 /* Position the cursor. Needed after a message that ends in a space. */
4533 windgoto(msg_row, msg_col);
4534
4535 ++no_mapping;
4536 ++allow_keys;
4537 for (;;)
4538 {
4539 if (argvars[0].v_type == VAR_UNKNOWN)
4540 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004541 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004542 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004543 /* getchar(1): only check if char avail */
4544 n = vpeekc_any();
4545 else if (error || vpeekc_any() == NUL)
4546 /* illegal argument or getchar(0) and no char avail: return zero */
4547 n = 0;
4548 else
4549 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004550 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004551
4552 if (n == K_IGNORE)
4553 continue;
4554 break;
4555 }
4556 --no_mapping;
4557 --allow_keys;
4558
4559 set_vim_var_nr(VV_MOUSE_WIN, 0);
4560 set_vim_var_nr(VV_MOUSE_WINID, 0);
4561 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4562 set_vim_var_nr(VV_MOUSE_COL, 0);
4563
4564 rettv->vval.v_number = n;
4565 if (IS_SPECIAL(n) || mod_mask != 0)
4566 {
4567 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4568 int i = 0;
4569
4570 /* Turn a special key into three bytes, plus modifier. */
4571 if (mod_mask != 0)
4572 {
4573 temp[i++] = K_SPECIAL;
4574 temp[i++] = KS_MODIFIER;
4575 temp[i++] = mod_mask;
4576 }
4577 if (IS_SPECIAL(n))
4578 {
4579 temp[i++] = K_SPECIAL;
4580 temp[i++] = K_SECOND(n);
4581 temp[i++] = K_THIRD(n);
4582 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004583 else if (has_mbyte)
4584 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004585 else
4586 temp[i++] = n;
4587 temp[i++] = NUL;
4588 rettv->v_type = VAR_STRING;
4589 rettv->vval.v_string = vim_strsave(temp);
4590
4591#ifdef FEAT_MOUSE
4592 if (is_mouse_key(n))
4593 {
4594 int row = mouse_row;
4595 int col = mouse_col;
4596 win_T *win;
4597 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004598 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004599 int winnr = 1;
4600
4601 if (row >= 0 && col >= 0)
4602 {
4603 /* Find the window at the mouse coordinates and compute the
4604 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004605 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004606 if (win == NULL)
4607 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004608 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004609# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004610 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004611 winnr = 0;
4612 else
4613# endif
4614 for (wp = firstwin; wp != win && wp != NULL;
4615 wp = wp->w_next)
4616 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004617 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4618 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4619 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4620 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4621 }
4622 }
4623#endif
4624 }
4625}
4626
4627/*
4628 * "getcharmod()" function
4629 */
4630 static void
4631f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4632{
4633 rettv->vval.v_number = mod_mask;
4634}
4635
4636/*
4637 * "getcharsearch()" function
4638 */
4639 static void
4640f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4641{
4642 if (rettv_dict_alloc(rettv) != FAIL)
4643 {
4644 dict_T *dict = rettv->vval.v_dict;
4645
Bram Moolenaare0be1672018-07-08 16:50:37 +02004646 dict_add_string(dict, "char", last_csearch());
4647 dict_add_number(dict, "forward", last_csearch_forward());
4648 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004649 }
4650}
4651
4652/*
4653 * "getcmdline()" function
4654 */
4655 static void
4656f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4657{
4658 rettv->v_type = VAR_STRING;
4659 rettv->vval.v_string = get_cmdline_str();
4660}
4661
4662/*
4663 * "getcmdpos()" function
4664 */
4665 static void
4666f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4667{
4668 rettv->vval.v_number = get_cmdline_pos() + 1;
4669}
4670
4671/*
4672 * "getcmdtype()" function
4673 */
4674 static void
4675f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4676{
4677 rettv->v_type = VAR_STRING;
4678 rettv->vval.v_string = alloc(2);
4679 if (rettv->vval.v_string != NULL)
4680 {
4681 rettv->vval.v_string[0] = get_cmdline_type();
4682 rettv->vval.v_string[1] = NUL;
4683 }
4684}
4685
4686/*
4687 * "getcmdwintype()" function
4688 */
4689 static void
4690f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4691{
4692 rettv->v_type = VAR_STRING;
4693 rettv->vval.v_string = NULL;
4694#ifdef FEAT_CMDWIN
4695 rettv->vval.v_string = alloc(2);
4696 if (rettv->vval.v_string != NULL)
4697 {
4698 rettv->vval.v_string[0] = cmdwin_type;
4699 rettv->vval.v_string[1] = NUL;
4700 }
4701#endif
4702}
4703
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004704/*
4705 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004706 *
4707 * Return the current working directory of a window in a tab page.
4708 * First optional argument 'winnr' is the window number or -1 and the second
4709 * optional argument 'tabnr' is the tab page number.
4710 *
4711 * If no arguments are supplied, then return the directory of the current
4712 * window.
4713 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4714 * the specified window.
4715 * If 'winnr' is 0 then return the directory of the current window.
4716 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4717 * directory of the specified tab page. Otherwise return the directory of the
4718 * specified window in the specified tab page.
4719 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004720 */
4721 static void
4722f_getcwd(typval_T *argvars, typval_T *rettv)
4723{
4724 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004725 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004726 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004727 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004728
4729 rettv->v_type = VAR_STRING;
4730 rettv->vval.v_string = NULL;
4731
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004732 if (argvars[0].v_type == VAR_NUMBER
4733 && argvars[0].vval.v_number == -1
4734 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004735 global = TRUE;
4736 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004737 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004738
4739 if (wp != NULL && wp->w_localdir != NULL)
4740 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004741 else if (tp != NULL && tp->tp_localdir != NULL)
4742 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4743 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004744 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004745 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 rettv->vval.v_string = vim_strsave(globaldir);
4747 else
4748 {
4749 cwd = alloc(MAXPATHL);
4750 if (cwd != NULL)
4751 {
4752 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4753 rettv->vval.v_string = vim_strsave(cwd);
4754 vim_free(cwd);
4755 }
4756 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004757 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004758#ifdef BACKSLASH_IN_FILENAME
4759 if (rettv->vval.v_string != NULL)
4760 slash_adjust(rettv->vval.v_string);
4761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004762}
4763
4764/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004765 * "getenv()" function
4766 */
4767 static void
4768f_getenv(typval_T *argvars, typval_T *rettv)
4769{
4770 int mustfree = FALSE;
4771 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4772
4773 if (p == NULL)
4774 {
4775 rettv->v_type = VAR_SPECIAL;
4776 rettv->vval.v_number = VVAL_NULL;
4777 return;
4778 }
4779 if (!mustfree)
4780 p = vim_strsave(p);
4781 rettv->vval.v_string = p;
4782 rettv->v_type = VAR_STRING;
4783}
4784
4785/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004786 * "getfontname()" function
4787 */
4788 static void
4789f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4790{
4791 rettv->v_type = VAR_STRING;
4792 rettv->vval.v_string = NULL;
4793#ifdef FEAT_GUI
4794 if (gui.in_use)
4795 {
4796 GuiFont font;
4797 char_u *name = NULL;
4798
4799 if (argvars[0].v_type == VAR_UNKNOWN)
4800 {
4801 /* Get the "Normal" font. Either the name saved by
4802 * hl_set_font_name() or from the font ID. */
4803 font = gui.norm_font;
4804 name = hl_get_font_name();
4805 }
4806 else
4807 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004808 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004809 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4810 return;
4811 font = gui_mch_get_font(name, FALSE);
4812 if (font == NOFONT)
4813 return; /* Invalid font name, return empty string. */
4814 }
4815 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4816 if (argvars[0].v_type != VAR_UNKNOWN)
4817 gui_mch_free_font(font);
4818 }
4819#endif
4820}
4821
4822/*
4823 * "getfperm({fname})" function
4824 */
4825 static void
4826f_getfperm(typval_T *argvars, typval_T *rettv)
4827{
4828 char_u *fname;
4829 stat_T st;
4830 char_u *perm = NULL;
4831 char_u flags[] = "rwx";
4832 int i;
4833
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004834 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004835
4836 rettv->v_type = VAR_STRING;
4837 if (mch_stat((char *)fname, &st) >= 0)
4838 {
4839 perm = vim_strsave((char_u *)"---------");
4840 if (perm != NULL)
4841 {
4842 for (i = 0; i < 9; i++)
4843 {
4844 if (st.st_mode & (1 << (8 - i)))
4845 perm[i] = flags[i % 3];
4846 }
4847 }
4848 }
4849 rettv->vval.v_string = perm;
4850}
4851
4852/*
4853 * "getfsize({fname})" function
4854 */
4855 static void
4856f_getfsize(typval_T *argvars, typval_T *rettv)
4857{
4858 char_u *fname;
4859 stat_T st;
4860
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004861 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004862
4863 rettv->v_type = VAR_NUMBER;
4864
4865 if (mch_stat((char *)fname, &st) >= 0)
4866 {
4867 if (mch_isdir(fname))
4868 rettv->vval.v_number = 0;
4869 else
4870 {
4871 rettv->vval.v_number = (varnumber_T)st.st_size;
4872
4873 /* non-perfect check for overflow */
4874 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4875 rettv->vval.v_number = -2;
4876 }
4877 }
4878 else
4879 rettv->vval.v_number = -1;
4880}
4881
4882/*
4883 * "getftime({fname})" function
4884 */
4885 static void
4886f_getftime(typval_T *argvars, typval_T *rettv)
4887{
4888 char_u *fname;
4889 stat_T st;
4890
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004891 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004892
4893 if (mch_stat((char *)fname, &st) >= 0)
4894 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4895 else
4896 rettv->vval.v_number = -1;
4897}
4898
4899/*
4900 * "getftype({fname})" function
4901 */
4902 static void
4903f_getftype(typval_T *argvars, typval_T *rettv)
4904{
4905 char_u *fname;
4906 stat_T st;
4907 char_u *type = NULL;
4908 char *t;
4909
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004910 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911
4912 rettv->v_type = VAR_STRING;
4913 if (mch_lstat((char *)fname, &st) >= 0)
4914 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915 if (S_ISREG(st.st_mode))
4916 t = "file";
4917 else if (S_ISDIR(st.st_mode))
4918 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004919 else if (S_ISLNK(st.st_mode))
4920 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921 else if (S_ISBLK(st.st_mode))
4922 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004923 else if (S_ISCHR(st.st_mode))
4924 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004925 else if (S_ISFIFO(st.st_mode))
4926 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004927 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02004928 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004929 else
4930 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931 type = vim_strsave((char_u *)t);
4932 }
4933 rettv->vval.v_string = type;
4934}
4935
4936/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004937 * "getjumplist()" function
4938 */
4939 static void
4940f_getjumplist(typval_T *argvars, typval_T *rettv)
4941{
4942#ifdef FEAT_JUMPLIST
4943 win_T *wp;
4944 int i;
4945 list_T *l;
4946 dict_T *d;
4947#endif
4948
4949 if (rettv_list_alloc(rettv) != OK)
4950 return;
4951
4952#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004953 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004954 if (wp == NULL)
4955 return;
4956
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01004957 cleanup_jumplist(wp, TRUE);
4958
Bram Moolenaar4f505882018-02-10 21:06:32 +01004959 l = list_alloc();
4960 if (l == NULL)
4961 return;
4962
4963 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4964 return;
4965 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4966
4967 for (i = 0; i < wp->w_jumplistlen; ++i)
4968 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004969 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4970 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004971 if ((d = dict_alloc()) == NULL)
4972 return;
4973 if (list_append_dict(l, d) == FAIL)
4974 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004975 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4976 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004977 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004978 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004979 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02004980 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004981 }
4982#endif
4983}
4984
4985/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004986 * "getline(lnum, [end])" function
4987 */
4988 static void
4989f_getline(typval_T *argvars, typval_T *rettv)
4990{
4991 linenr_T lnum;
4992 linenr_T end;
4993 int retlist;
4994
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004995 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004996 if (argvars[1].v_type == VAR_UNKNOWN)
4997 {
4998 end = 0;
4999 retlist = FALSE;
5000 }
5001 else
5002 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005003 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005004 retlist = TRUE;
5005 }
5006
5007 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5008}
5009
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005010#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005011 static void
5012get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5013{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005014 if (what_arg->v_type == VAR_UNKNOWN)
5015 {
5016 if (rettv_list_alloc(rettv) == OK)
5017 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005018 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005019 }
5020 else
5021 {
5022 if (rettv_dict_alloc(rettv) == OK)
5023 if (is_qf || (wp != NULL))
5024 {
5025 if (what_arg->v_type == VAR_DICT)
5026 {
5027 dict_T *d = what_arg->vval.v_dict;
5028
5029 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005030 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005031 }
5032 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005033 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005034 }
5035 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005036}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005037#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005038
5039/*
5040 * "getloclist()" function
5041 */
5042 static void
5043f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5044{
5045#ifdef FEAT_QUICKFIX
5046 win_T *wp;
5047
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005048 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005049 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5050#endif
5051}
5052
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005054 * "getpid()" function
5055 */
5056 static void
5057f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5058{
5059 rettv->vval.v_number = mch_get_pid();
5060}
5061
5062 static void
5063getpos_both(
5064 typval_T *argvars,
5065 typval_T *rettv,
5066 int getcurpos)
5067{
5068 pos_T *fp;
5069 list_T *l;
5070 int fnum = -1;
5071
5072 if (rettv_list_alloc(rettv) == OK)
5073 {
5074 l = rettv->vval.v_list;
5075 if (getcurpos)
5076 fp = &curwin->w_cursor;
5077 else
5078 fp = var2fpos(&argvars[0], TRUE, &fnum);
5079 if (fnum != -1)
5080 list_append_number(l, (varnumber_T)fnum);
5081 else
5082 list_append_number(l, (varnumber_T)0);
5083 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5084 : (varnumber_T)0);
5085 list_append_number(l, (fp != NULL)
5086 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5087 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005088 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005089 (varnumber_T)0);
5090 if (getcurpos)
5091 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005092 int save_set_curswant = curwin->w_set_curswant;
5093 colnr_T save_curswant = curwin->w_curswant;
5094 colnr_T save_virtcol = curwin->w_virtcol;
5095
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096 update_curswant();
5097 list_append_number(l, curwin->w_curswant == MAXCOL ?
5098 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005099
5100 // Do not change "curswant", as it is unexpected that a get
5101 // function has a side effect.
5102 if (save_set_curswant)
5103 {
5104 curwin->w_set_curswant = save_set_curswant;
5105 curwin->w_curswant = save_curswant;
5106 curwin->w_virtcol = save_virtcol;
5107 curwin->w_valid &= ~VALID_VIRTCOL;
5108 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 }
5110 }
5111 else
5112 rettv->vval.v_number = FALSE;
5113}
5114
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115/*
5116 * "getcurpos()" function
5117 */
5118 static void
5119f_getcurpos(typval_T *argvars, typval_T *rettv)
5120{
5121 getpos_both(argvars, rettv, TRUE);
5122}
5123
5124/*
5125 * "getpos(string)" function
5126 */
5127 static void
5128f_getpos(typval_T *argvars, typval_T *rettv)
5129{
5130 getpos_both(argvars, rettv, FALSE);
5131}
5132
5133/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005134 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135 */
5136 static void
5137f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5138{
5139#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005140 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005141#endif
5142}
5143
5144/*
5145 * "getreg()" function
5146 */
5147 static void
5148f_getreg(typval_T *argvars, typval_T *rettv)
5149{
5150 char_u *strregname;
5151 int regname;
5152 int arg2 = FALSE;
5153 int return_list = FALSE;
5154 int error = FALSE;
5155
5156 if (argvars[0].v_type != VAR_UNKNOWN)
5157 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005158 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005159 error = strregname == NULL;
5160 if (argvars[1].v_type != VAR_UNKNOWN)
5161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005162 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005163 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005164 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005165 }
5166 }
5167 else
5168 strregname = get_vim_var_str(VV_REG);
5169
5170 if (error)
5171 return;
5172
5173 regname = (strregname == NULL ? '"' : *strregname);
5174 if (regname == 0)
5175 regname = '"';
5176
5177 if (return_list)
5178 {
5179 rettv->v_type = VAR_LIST;
5180 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5181 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5182 if (rettv->vval.v_list == NULL)
5183 (void)rettv_list_alloc(rettv);
5184 else
5185 ++rettv->vval.v_list->lv_refcount;
5186 }
5187 else
5188 {
5189 rettv->v_type = VAR_STRING;
5190 rettv->vval.v_string = get_reg_contents(regname,
5191 arg2 ? GREG_EXPR_SRC : 0);
5192 }
5193}
5194
5195/*
5196 * "getregtype()" function
5197 */
5198 static void
5199f_getregtype(typval_T *argvars, typval_T *rettv)
5200{
5201 char_u *strregname;
5202 int regname;
5203 char_u buf[NUMBUFLEN + 2];
5204 long reglen = 0;
5205
5206 if (argvars[0].v_type != VAR_UNKNOWN)
5207 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005208 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 if (strregname == NULL) /* type error; errmsg already given */
5210 {
5211 rettv->v_type = VAR_STRING;
5212 rettv->vval.v_string = NULL;
5213 return;
5214 }
5215 }
5216 else
5217 /* Default to v:register */
5218 strregname = get_vim_var_str(VV_REG);
5219
5220 regname = (strregname == NULL ? '"' : *strregname);
5221 if (regname == 0)
5222 regname = '"';
5223
5224 buf[0] = NUL;
5225 buf[1] = NUL;
5226 switch (get_reg_type(regname, &reglen))
5227 {
5228 case MLINE: buf[0] = 'V'; break;
5229 case MCHAR: buf[0] = 'v'; break;
5230 case MBLOCK:
5231 buf[0] = Ctrl_V;
5232 sprintf((char *)buf + 1, "%ld", reglen + 1);
5233 break;
5234 }
5235 rettv->v_type = VAR_STRING;
5236 rettv->vval.v_string = vim_strsave(buf);
5237}
5238
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005239/*
5240 * Returns information (variables, options, etc.) about a tab page
5241 * as a dictionary.
5242 */
5243 static dict_T *
5244get_tabpage_info(tabpage_T *tp, int tp_idx)
5245{
5246 win_T *wp;
5247 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005248 list_T *l;
5249
5250 dict = dict_alloc();
5251 if (dict == NULL)
5252 return NULL;
5253
Bram Moolenaare0be1672018-07-08 16:50:37 +02005254 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005255
5256 l = list_alloc();
5257 if (l != NULL)
5258 {
5259 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005260 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005261 list_append_number(l, (varnumber_T)wp->w_id);
5262 dict_add_list(dict, "windows", l);
5263 }
5264
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005265 /* Make a reference to tabpage variables */
5266 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005267
5268 return dict;
5269}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005270
5271/*
5272 * "gettabinfo()" function
5273 */
5274 static void
5275f_gettabinfo(typval_T *argvars, typval_T *rettv)
5276{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005277 tabpage_T *tp, *tparg = NULL;
5278 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005279 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005280
5281 if (rettv_list_alloc(rettv) != OK)
5282 return;
5283
5284 if (argvars[0].v_type != VAR_UNKNOWN)
5285 {
5286 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005287 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005288 if (tparg == NULL)
5289 return;
5290 }
5291
5292 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005293 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005294 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005295 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005296 if (tparg != NULL && tp != tparg)
5297 continue;
5298 d = get_tabpage_info(tp, tpnr);
5299 if (d != NULL)
5300 list_append_dict(rettv->vval.v_list, d);
5301 if (tparg != NULL)
5302 return;
5303 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005304}
5305
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306/*
5307 * "gettabvar()" function
5308 */
5309 static void
5310f_gettabvar(typval_T *argvars, typval_T *rettv)
5311{
5312 win_T *oldcurwin;
5313 tabpage_T *tp, *oldtabpage;
5314 dictitem_T *v;
5315 char_u *varname;
5316 int done = FALSE;
5317
5318 rettv->v_type = VAR_STRING;
5319 rettv->vval.v_string = NULL;
5320
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005321 varname = tv_get_string_chk(&argvars[1]);
5322 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005323 if (tp != NULL && varname != NULL)
5324 {
5325 /* Set tp to be our tabpage, temporarily. Also set the window to the
5326 * first window in the tabpage, otherwise the window is not valid. */
5327 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005328 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5329 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005330 {
5331 /* look up the variable */
5332 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5333 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5334 if (v != NULL)
5335 {
5336 copy_tv(&v->di_tv, rettv);
5337 done = TRUE;
5338 }
5339 }
5340
5341 /* restore previous notion of curwin */
5342 restore_win(oldcurwin, oldtabpage, TRUE);
5343 }
5344
5345 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5346 copy_tv(&argvars[2], rettv);
5347}
5348
5349/*
5350 * "gettabwinvar()" function
5351 */
5352 static void
5353f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5354{
5355 getwinvar(argvars, rettv, 1);
5356}
5357
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005358/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005359 * "gettagstack()" function
5360 */
5361 static void
5362f_gettagstack(typval_T *argvars, typval_T *rettv)
5363{
5364 win_T *wp = curwin; // default is current window
5365
5366 if (rettv_dict_alloc(rettv) != OK)
5367 return;
5368
5369 if (argvars[0].v_type != VAR_UNKNOWN)
5370 {
5371 wp = find_win_by_nr_or_id(&argvars[0]);
5372 if (wp == NULL)
5373 return;
5374 }
5375
5376 get_tagstack(wp, rettv->vval.v_dict);
5377}
5378
5379/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005380 * Returns information about a window as a dictionary.
5381 */
5382 static dict_T *
5383get_win_info(win_T *wp, short tpnr, short winnr)
5384{
5385 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005386
5387 dict = dict_alloc();
5388 if (dict == NULL)
5389 return NULL;
5390
Bram Moolenaare0be1672018-07-08 16:50:37 +02005391 dict_add_number(dict, "tabnr", tpnr);
5392 dict_add_number(dict, "winnr", winnr);
5393 dict_add_number(dict, "winid", wp->w_id);
5394 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005395 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005396 dict_add_number(dict, "topline", wp->w_topline);
5397 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005398#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005399 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005400#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005401 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005402 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005403 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005404
Bram Moolenaar69905d12017-08-13 18:14:47 +02005405#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005406 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005407#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005408#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005409 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5410 dict_add_number(dict, "loclist",
5411 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005412#endif
5413
Bram Moolenaar30567352016-08-27 21:25:44 +02005414 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005415 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005416
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005417 return dict;
5418}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005419
5420/*
5421 * "getwininfo()" function
5422 */
5423 static void
5424f_getwininfo(typval_T *argvars, typval_T *rettv)
5425{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005426 tabpage_T *tp;
5427 win_T *wp = NULL, *wparg = NULL;
5428 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005429 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005430
5431 if (rettv_list_alloc(rettv) != OK)
5432 return;
5433
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005434 if (argvars[0].v_type != VAR_UNKNOWN)
5435 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005436 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005437 if (wparg == NULL)
5438 return;
5439 }
5440
5441 /* Collect information about either all the windows across all the tab
5442 * pages or one particular window.
5443 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005444 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005445 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005446 tabnr++;
5447 winnr = 0;
5448 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005449 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005450 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005451 if (wparg != NULL && wp != wparg)
5452 continue;
5453 d = get_win_info(wp, tabnr, winnr);
5454 if (d != NULL)
5455 list_append_dict(rettv->vval.v_list, d);
5456 if (wparg != NULL)
5457 /* found information about a specific window */
5458 return;
5459 }
5460 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005461}
5462
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005463/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005464 * "win_execute()" function
5465 */
5466 static void
5467f_win_execute(typval_T *argvars, typval_T *rettv)
5468{
5469 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005470 tabpage_T *tp;
5471 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005472 win_T *save_curwin;
5473 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005474
Bram Moolenaar820680b2019-08-09 14:56:22 +02005475 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005476 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005477 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005478 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005479 check_cursor();
5480 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005481 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005482 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005483 }
5484}
5485
5486/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005487 * "win_findbuf()" function
5488 */
5489 static void
5490f_win_findbuf(typval_T *argvars, typval_T *rettv)
5491{
5492 if (rettv_list_alloc(rettv) != FAIL)
5493 win_findbuf(argvars, rettv->vval.v_list);
5494}
5495
5496/*
5497 * "win_getid()" function
5498 */
5499 static void
5500f_win_getid(typval_T *argvars, typval_T *rettv)
5501{
5502 rettv->vval.v_number = win_getid(argvars);
5503}
5504
5505/*
5506 * "win_gotoid()" function
5507 */
5508 static void
5509f_win_gotoid(typval_T *argvars, typval_T *rettv)
5510{
5511 rettv->vval.v_number = win_gotoid(argvars);
5512}
5513
5514/*
5515 * "win_id2tabwin()" function
5516 */
5517 static void
5518f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5519{
5520 if (rettv_list_alloc(rettv) != FAIL)
5521 win_id2tabwin(argvars, rettv->vval.v_list);
5522}
5523
5524/*
5525 * "win_id2win()" function
5526 */
5527 static void
5528f_win_id2win(typval_T *argvars, typval_T *rettv)
5529{
5530 rettv->vval.v_number = win_id2win(argvars);
5531}
5532
5533/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005534 * "win_screenpos()" function
5535 */
5536 static void
5537f_win_screenpos(typval_T *argvars, typval_T *rettv)
5538{
5539 win_T *wp;
5540
5541 if (rettv_list_alloc(rettv) == FAIL)
5542 return;
5543
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005544 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005545 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5546 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5547}
5548
5549/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005550 * "getwinpos({timeout})" function
5551 */
5552 static void
5553f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5554{
5555 int x = -1;
5556 int y = -1;
5557
5558 if (rettv_list_alloc(rettv) == FAIL)
5559 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005560#if defined(FEAT_GUI) \
5561 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5562 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005563 {
5564 varnumber_T timeout = 100;
5565
5566 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005567 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005568
5569 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005570 }
5571#endif
5572 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5573 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5574}
5575
5576
5577/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005578 * "getwinposx()" function
5579 */
5580 static void
5581f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5582{
5583 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005584#if defined(FEAT_GUI) \
5585 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5586 || defined(MSWIN)
5587
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005588 {
5589 int x, y;
5590
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005591 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005592 rettv->vval.v_number = x;
5593 }
5594#endif
5595}
5596
5597/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005598 * "getwinposy()" function
5599 */
5600 static void
5601f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5602{
5603 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005604#if defined(FEAT_GUI) \
5605 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5606 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005607 {
5608 int x, y;
5609
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005610 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005611 rettv->vval.v_number = y;
5612 }
5613#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005614}
5615
5616/*
5617 * "getwinvar()" function
5618 */
5619 static void
5620f_getwinvar(typval_T *argvars, typval_T *rettv)
5621{
5622 getwinvar(argvars, rettv, 0);
5623}
5624
5625/*
5626 * "glob()" function
5627 */
5628 static void
5629f_glob(typval_T *argvars, typval_T *rettv)
5630{
5631 int options = WILD_SILENT|WILD_USE_NL;
5632 expand_T xpc;
5633 int error = FALSE;
5634
5635 /* When the optional second argument is non-zero, don't remove matches
5636 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5637 rettv->v_type = VAR_STRING;
5638 if (argvars[1].v_type != VAR_UNKNOWN)
5639 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005640 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005641 options |= WILD_KEEP_ALL;
5642 if (argvars[2].v_type != VAR_UNKNOWN)
5643 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005644 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005645 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005646 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005647 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648 options |= WILD_ALLLINKS;
5649 }
5650 }
5651 if (!error)
5652 {
5653 ExpandInit(&xpc);
5654 xpc.xp_context = EXPAND_FILES;
5655 if (p_wic)
5656 options += WILD_ICASE;
5657 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005658 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 NULL, options, WILD_ALL);
5660 else if (rettv_list_alloc(rettv) != FAIL)
5661 {
5662 int i;
5663
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005664 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005665 NULL, options, WILD_ALL_KEEP);
5666 for (i = 0; i < xpc.xp_numfiles; i++)
5667 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5668
5669 ExpandCleanup(&xpc);
5670 }
5671 }
5672 else
5673 rettv->vval.v_string = NULL;
5674}
5675
5676/*
5677 * "globpath()" function
5678 */
5679 static void
5680f_globpath(typval_T *argvars, typval_T *rettv)
5681{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005682 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005683 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005684 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685 int error = FALSE;
5686 garray_T ga;
5687 int i;
5688
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005689 // When the optional second argument is non-zero, don't remove matches
5690 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691 rettv->v_type = VAR_STRING;
5692 if (argvars[2].v_type != VAR_UNKNOWN)
5693 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005694 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005695 flags |= WILD_KEEP_ALL;
5696 if (argvars[3].v_type != VAR_UNKNOWN)
5697 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005698 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005699 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005700 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005701 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005702 flags |= WILD_ALLLINKS;
5703 }
5704 }
5705 if (file != NULL && !error)
5706 {
5707 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005708 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005709 if (rettv->v_type == VAR_STRING)
5710 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5711 else if (rettv_list_alloc(rettv) != FAIL)
5712 for (i = 0; i < ga.ga_len; ++i)
5713 list_append_string(rettv->vval.v_list,
5714 ((char_u **)(ga.ga_data))[i], -1);
5715 ga_clear_strings(&ga);
5716 }
5717 else
5718 rettv->vval.v_string = NULL;
5719}
5720
5721/*
5722 * "glob2regpat()" function
5723 */
5724 static void
5725f_glob2regpat(typval_T *argvars, typval_T *rettv)
5726{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005727 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005728
5729 rettv->v_type = VAR_STRING;
5730 rettv->vval.v_string = (pat == NULL)
5731 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5732}
5733
5734/* for VIM_VERSION_ defines */
5735#include "version.h"
5736
5737/*
5738 * "has()" function
5739 */
5740 static void
5741f_has(typval_T *argvars, typval_T *rettv)
5742{
5743 int i;
5744 char_u *name;
5745 int n = FALSE;
5746 static char *(has_list[]) =
5747 {
5748#ifdef AMIGA
5749 "amiga",
5750# ifdef FEAT_ARP
5751 "arp",
5752# endif
5753#endif
5754#ifdef __BEOS__
5755 "beos",
5756#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005757#if defined(BSD) && !defined(MACOS_X)
5758 "bsd",
5759#endif
5760#ifdef hpux
5761 "hpux",
5762#endif
5763#ifdef __linux__
5764 "linux",
5765#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005766#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005767 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5768 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005769# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005770 "macunix", /* Mac OS X, with the darwin feature */
5771 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005772# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005773#endif
5774#ifdef __QNX__
5775 "qnx",
5776#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005777#ifdef SUN_SYSTEM
5778 "sun",
5779#else
5780 "moon",
5781#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782#ifdef UNIX
5783 "unix",
5784#endif
5785#ifdef VMS
5786 "vms",
5787#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005788#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005789 "win32",
5790#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005791#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 "win32unix",
5793#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005794#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005795 "win64",
5796#endif
5797#ifdef EBCDIC
5798 "ebcdic",
5799#endif
5800#ifndef CASE_INSENSITIVE_FILENAME
5801 "fname_case",
5802#endif
5803#ifdef HAVE_ACL
5804 "acl",
5805#endif
5806#ifdef FEAT_ARABIC
5807 "arabic",
5808#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005809 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005810#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005811 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005812#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005813#ifdef FEAT_AUTOSERVERNAME
5814 "autoservername",
5815#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005816#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005817 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01005818# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005819 "balloon_multiline",
5820# endif
5821#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005822#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005823 "balloon_eval_term",
5824#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005825#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5826 "builtin_terms",
5827# ifdef ALL_BUILTIN_TCAPS
5828 "all_builtin_terms",
5829# endif
5830#endif
5831#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01005832 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005833 || defined(FEAT_GUI_MOTIF))
5834 "browsefilter",
5835#endif
5836#ifdef FEAT_BYTEOFF
5837 "byte_offset",
5838#endif
5839#ifdef FEAT_JOB_CHANNEL
5840 "channel",
5841#endif
5842#ifdef FEAT_CINDENT
5843 "cindent",
5844#endif
5845#ifdef FEAT_CLIENTSERVER
5846 "clientserver",
5847#endif
5848#ifdef FEAT_CLIPBOARD
5849 "clipboard",
5850#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005851 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005852 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005853#ifdef FEAT_COMMENTS
5854 "comments",
5855#endif
5856#ifdef FEAT_CONCEAL
5857 "conceal",
5858#endif
5859#ifdef FEAT_CRYPT
5860 "cryptv",
5861 "crypt-blowfish",
5862 "crypt-blowfish2",
5863#endif
5864#ifdef FEAT_CSCOPE
5865 "cscope",
5866#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005867 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868#ifdef CURSOR_SHAPE
5869 "cursorshape",
5870#endif
5871#ifdef DEBUG
5872 "debug",
5873#endif
5874#ifdef FEAT_CON_DIALOG
5875 "dialog_con",
5876#endif
5877#ifdef FEAT_GUI_DIALOG
5878 "dialog_gui",
5879#endif
5880#ifdef FEAT_DIFF
5881 "diff",
5882#endif
5883#ifdef FEAT_DIGRAPHS
5884 "digraphs",
5885#endif
5886#ifdef FEAT_DIRECTX
5887 "directx",
5888#endif
5889#ifdef FEAT_DND
5890 "dnd",
5891#endif
5892#ifdef FEAT_EMACS_TAGS
5893 "emacs_tags",
5894#endif
5895 "eval", /* always present, of course! */
5896 "ex_extra", /* graduated feature */
5897#ifdef FEAT_SEARCH_EXTRA
5898 "extra_search",
5899#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900#ifdef FEAT_SEARCHPATH
5901 "file_in_path",
5902#endif
5903#ifdef FEAT_FILTERPIPE
5904 "filterpipe",
5905#endif
5906#ifdef FEAT_FIND_ID
5907 "find_in_path",
5908#endif
5909#ifdef FEAT_FLOAT
5910 "float",
5911#endif
5912#ifdef FEAT_FOLDING
5913 "folding",
5914#endif
5915#ifdef FEAT_FOOTER
5916 "footer",
5917#endif
5918#if !defined(USE_SYSTEM) && defined(UNIX)
5919 "fork",
5920#endif
5921#ifdef FEAT_GETTEXT
5922 "gettext",
5923#endif
5924#ifdef FEAT_GUI
5925 "gui",
5926#endif
5927#ifdef FEAT_GUI_ATHENA
5928# ifdef FEAT_GUI_NEXTAW
5929 "gui_neXtaw",
5930# else
5931 "gui_athena",
5932# endif
5933#endif
5934#ifdef FEAT_GUI_GTK
5935 "gui_gtk",
5936# ifdef USE_GTK3
5937 "gui_gtk3",
5938# else
5939 "gui_gtk2",
5940# endif
5941#endif
5942#ifdef FEAT_GUI_GNOME
5943 "gui_gnome",
5944#endif
5945#ifdef FEAT_GUI_MAC
5946 "gui_mac",
5947#endif
5948#ifdef FEAT_GUI_MOTIF
5949 "gui_motif",
5950#endif
5951#ifdef FEAT_GUI_PHOTON
5952 "gui_photon",
5953#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005954#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005955 "gui_win32",
5956#endif
5957#ifdef FEAT_HANGULIN
5958 "hangul_input",
5959#endif
5960#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5961 "iconv",
5962#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005963 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005964#ifdef FEAT_JOB_CHANNEL
5965 "job",
5966#endif
5967#ifdef FEAT_JUMPLIST
5968 "jumplist",
5969#endif
5970#ifdef FEAT_KEYMAP
5971 "keymap",
5972#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005973 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005974#ifdef FEAT_LANGMAP
5975 "langmap",
5976#endif
5977#ifdef FEAT_LIBCALL
5978 "libcall",
5979#endif
5980#ifdef FEAT_LINEBREAK
5981 "linebreak",
5982#endif
5983#ifdef FEAT_LISP
5984 "lispindent",
5985#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005986 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005987 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005988#ifdef FEAT_LUA
5989# ifndef DYNAMIC_LUA
5990 "lua",
5991# endif
5992#endif
5993#ifdef FEAT_MENU
5994 "menu",
5995#endif
5996#ifdef FEAT_SESSION
5997 "mksession",
5998#endif
5999#ifdef FEAT_MODIFY_FNAME
6000 "modify_fname",
6001#endif
6002#ifdef FEAT_MOUSE
6003 "mouse",
6004#endif
6005#ifdef FEAT_MOUSESHAPE
6006 "mouseshape",
6007#endif
6008#if defined(UNIX) || defined(VMS)
6009# ifdef FEAT_MOUSE_DEC
6010 "mouse_dec",
6011# endif
6012# ifdef FEAT_MOUSE_GPM
6013 "mouse_gpm",
6014# endif
6015# ifdef FEAT_MOUSE_JSB
6016 "mouse_jsbterm",
6017# endif
6018# ifdef FEAT_MOUSE_NET
6019 "mouse_netterm",
6020# endif
6021# ifdef FEAT_MOUSE_PTERM
6022 "mouse_pterm",
6023# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006024# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006025 "mouse_sgr",
6026# endif
6027# ifdef FEAT_SYSMOUSE
6028 "mouse_sysmouse",
6029# endif
6030# ifdef FEAT_MOUSE_URXVT
6031 "mouse_urxvt",
6032# endif
6033# ifdef FEAT_MOUSE_XTERM
6034 "mouse_xterm",
6035# endif
6036#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006037 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006038#ifdef FEAT_MBYTE_IME
6039 "multi_byte_ime",
6040#endif
6041#ifdef FEAT_MULTI_LANG
6042 "multi_lang",
6043#endif
6044#ifdef FEAT_MZSCHEME
6045#ifndef DYNAMIC_MZSCHEME
6046 "mzscheme",
6047#endif
6048#endif
6049#ifdef FEAT_NUM64
6050 "num64",
6051#endif
6052#ifdef FEAT_OLE
6053 "ole",
6054#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006055#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006056 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006057#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006058#ifdef FEAT_PATH_EXTRA
6059 "path_extra",
6060#endif
6061#ifdef FEAT_PERL
6062#ifndef DYNAMIC_PERL
6063 "perl",
6064#endif
6065#endif
6066#ifdef FEAT_PERSISTENT_UNDO
6067 "persistent_undo",
6068#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006069#if defined(FEAT_PYTHON)
6070 "python_compiled",
6071# if defined(DYNAMIC_PYTHON)
6072 "python_dynamic",
6073# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006074 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006075 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006076# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006077#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006078#if defined(FEAT_PYTHON3)
6079 "python3_compiled",
6080# if defined(DYNAMIC_PYTHON3)
6081 "python3_dynamic",
6082# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006084 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006085# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006086#endif
6087#ifdef FEAT_POSTSCRIPT
6088 "postscript",
6089#endif
6090#ifdef FEAT_PRINTER
6091 "printer",
6092#endif
6093#ifdef FEAT_PROFILE
6094 "profile",
6095#endif
6096#ifdef FEAT_RELTIME
6097 "reltime",
6098#endif
6099#ifdef FEAT_QUICKFIX
6100 "quickfix",
6101#endif
6102#ifdef FEAT_RIGHTLEFT
6103 "rightleft",
6104#endif
6105#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6106 "ruby",
6107#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006108 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006109#ifdef FEAT_CMDL_INFO
6110 "showcmd",
6111 "cmdline_info",
6112#endif
6113#ifdef FEAT_SIGNS
6114 "signs",
6115#endif
6116#ifdef FEAT_SMARTINDENT
6117 "smartindent",
6118#endif
6119#ifdef STARTUPTIME
6120 "startuptime",
6121#endif
6122#ifdef FEAT_STL_OPT
6123 "statusline",
6124#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006125#ifdef FEAT_NETBEANS_INTG
6126 "netbeans_intg",
6127#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006128#ifdef FEAT_SOUND
6129 "sound",
6130#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006131#ifdef FEAT_SPELL
6132 "spell",
6133#endif
6134#ifdef FEAT_SYN_HL
6135 "syntax",
6136#endif
6137#if defined(USE_SYSTEM) || !defined(UNIX)
6138 "system",
6139#endif
6140#ifdef FEAT_TAG_BINS
6141 "tag_binary",
6142#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143#ifdef FEAT_TCL
6144# ifndef DYNAMIC_TCL
6145 "tcl",
6146# endif
6147#endif
6148#ifdef FEAT_TERMGUICOLORS
6149 "termguicolors",
6150#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006151#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006152 "terminal",
6153#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006154#ifdef TERMINFO
6155 "terminfo",
6156#endif
6157#ifdef FEAT_TERMRESPONSE
6158 "termresponse",
6159#endif
6160#ifdef FEAT_TEXTOBJ
6161 "textobjects",
6162#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006163#ifdef FEAT_TEXT_PROP
6164 "textprop",
6165#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166#ifdef HAVE_TGETENT
6167 "tgetent",
6168#endif
6169#ifdef FEAT_TIMERS
6170 "timers",
6171#endif
6172#ifdef FEAT_TITLE
6173 "title",
6174#endif
6175#ifdef FEAT_TOOLBAR
6176 "toolbar",
6177#endif
6178#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6179 "unnamedplus",
6180#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006181 "user-commands", /* was accidentally included in 5.4 */
6182 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006183#ifdef FEAT_VARTABS
6184 "vartabs",
6185#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006186 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006187#ifdef FEAT_VIMINFO
6188 "viminfo",
6189#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006190 "vimscript-1",
6191 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006192 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006193 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006197#ifdef FEAT_VTP
6198 "vtp",
6199#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006200#ifdef FEAT_WILDIGN
6201 "wildignore",
6202#endif
6203#ifdef FEAT_WILDMENU
6204 "wildmenu",
6205#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006206 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006207#ifdef FEAT_WAK
6208 "winaltkeys",
6209#endif
6210#ifdef FEAT_WRITEBACKUP
6211 "writebackup",
6212#endif
6213#ifdef FEAT_XIM
6214 "xim",
6215#endif
6216#ifdef FEAT_XFONTSET
6217 "xfontset",
6218#endif
6219#ifdef FEAT_XPM_W32
6220 "xpm",
6221 "xpm_w32", /* for backward compatibility */
6222#else
6223# if defined(HAVE_XPM)
6224 "xpm",
6225# endif
6226#endif
6227#ifdef USE_XSMP
6228 "xsmp",
6229#endif
6230#ifdef USE_XSMP_INTERACT
6231 "xsmp_interact",
6232#endif
6233#ifdef FEAT_XCLIPBOARD
6234 "xterm_clipboard",
6235#endif
6236#ifdef FEAT_XTERM_SAVE
6237 "xterm_save",
6238#endif
6239#if defined(UNIX) && defined(FEAT_X11)
6240 "X11",
6241#endif
6242 NULL
6243 };
6244
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006245 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006246 for (i = 0; has_list[i] != NULL; ++i)
6247 if (STRICMP(name, has_list[i]) == 0)
6248 {
6249 n = TRUE;
6250 break;
6251 }
6252
6253 if (n == FALSE)
6254 {
6255 if (STRNICMP(name, "patch", 5) == 0)
6256 {
6257 if (name[5] == '-'
6258 && STRLEN(name) >= 11
6259 && vim_isdigit(name[6])
6260 && vim_isdigit(name[8])
6261 && vim_isdigit(name[10]))
6262 {
6263 int major = atoi((char *)name + 6);
6264 int minor = atoi((char *)name + 8);
6265
6266 /* Expect "patch-9.9.01234". */
6267 n = (major < VIM_VERSION_MAJOR
6268 || (major == VIM_VERSION_MAJOR
6269 && (minor < VIM_VERSION_MINOR
6270 || (minor == VIM_VERSION_MINOR
6271 && has_patch(atoi((char *)name + 10))))));
6272 }
6273 else
6274 n = has_patch(atoi((char *)name + 5));
6275 }
6276 else if (STRICMP(name, "vim_starting") == 0)
6277 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006278 else if (STRICMP(name, "ttyin") == 0)
6279 n = mch_input_isatty();
6280 else if (STRICMP(name, "ttyout") == 0)
6281 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006282 else if (STRICMP(name, "multi_byte_encoding") == 0)
6283 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006284#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 else if (STRICMP(name, "balloon_multiline") == 0)
6286 n = multiline_balloon_available();
6287#endif
6288#ifdef DYNAMIC_TCL
6289 else if (STRICMP(name, "tcl") == 0)
6290 n = tcl_enabled(FALSE);
6291#endif
6292#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6293 else if (STRICMP(name, "iconv") == 0)
6294 n = iconv_enabled(FALSE);
6295#endif
6296#ifdef DYNAMIC_LUA
6297 else if (STRICMP(name, "lua") == 0)
6298 n = lua_enabled(FALSE);
6299#endif
6300#ifdef DYNAMIC_MZSCHEME
6301 else if (STRICMP(name, "mzscheme") == 0)
6302 n = mzscheme_enabled(FALSE);
6303#endif
6304#ifdef DYNAMIC_RUBY
6305 else if (STRICMP(name, "ruby") == 0)
6306 n = ruby_enabled(FALSE);
6307#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006308#ifdef DYNAMIC_PYTHON
6309 else if (STRICMP(name, "python") == 0)
6310 n = python_enabled(FALSE);
6311#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006312#ifdef DYNAMIC_PYTHON3
6313 else if (STRICMP(name, "python3") == 0)
6314 n = python3_enabled(FALSE);
6315#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006316#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6317 else if (STRICMP(name, "pythonx") == 0)
6318 {
6319# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6320 if (p_pyx == 0)
6321 n = python3_enabled(FALSE) || python_enabled(FALSE);
6322 else if (p_pyx == 3)
6323 n = python3_enabled(FALSE);
6324 else if (p_pyx == 2)
6325 n = python_enabled(FALSE);
6326# elif defined(DYNAMIC_PYTHON)
6327 n = python_enabled(FALSE);
6328# elif defined(DYNAMIC_PYTHON3)
6329 n = python3_enabled(FALSE);
6330# endif
6331 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006332#endif
6333#ifdef DYNAMIC_PERL
6334 else if (STRICMP(name, "perl") == 0)
6335 n = perl_enabled(FALSE);
6336#endif
6337#ifdef FEAT_GUI
6338 else if (STRICMP(name, "gui_running") == 0)
6339 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006340# ifdef FEAT_BROWSE
6341 else if (STRICMP(name, "browse") == 0)
6342 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6343# endif
6344#endif
6345#ifdef FEAT_SYN_HL
6346 else if (STRICMP(name, "syntax_items") == 0)
6347 n = syntax_present(curwin);
6348#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006349#ifdef FEAT_VTP
6350 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006351 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006352#endif
6353#ifdef FEAT_NETBEANS_INTG
6354 else if (STRICMP(name, "netbeans_enabled") == 0)
6355 n = netbeans_active();
6356#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006357#ifdef FEAT_MOUSE_GPM
6358 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6359 n = gpm_enabled();
6360#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006361#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006362 else if (STRICMP(name, "terminal") == 0)
6363 n = terminal_enabled();
6364#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006365#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006366 else if (STRICMP(name, "conpty") == 0)
6367 n = use_conpty();
6368#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006369#ifdef FEAT_CLIPBOARD
6370 else if (STRICMP(name, "clipboard_working") == 0)
6371 n = clip_star.available;
6372#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373 }
6374
6375 rettv->vval.v_number = n;
6376}
6377
6378/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006379 * "haslocaldir()" function
6380 */
6381 static void
6382f_haslocaldir(typval_T *argvars, typval_T *rettv)
6383{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006384 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385 win_T *wp = NULL;
6386
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006387 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6388
6389 // Check for window-local and tab-local directories
6390 if (wp != NULL && wp->w_localdir != NULL)
6391 rettv->vval.v_number = 1;
6392 else if (tp != NULL && tp->tp_localdir != NULL)
6393 rettv->vval.v_number = 2;
6394 else
6395 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396}
6397
6398/*
6399 * "hasmapto()" function
6400 */
6401 static void
6402f_hasmapto(typval_T *argvars, typval_T *rettv)
6403{
6404 char_u *name;
6405 char_u *mode;
6406 char_u buf[NUMBUFLEN];
6407 int abbr = FALSE;
6408
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006409 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006410 if (argvars[1].v_type == VAR_UNKNOWN)
6411 mode = (char_u *)"nvo";
6412 else
6413 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006414 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006416 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417 }
6418
6419 if (map_to_exists(name, mode, abbr))
6420 rettv->vval.v_number = TRUE;
6421 else
6422 rettv->vval.v_number = FALSE;
6423}
6424
6425/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 * "highlightID(name)" function
6427 */
6428 static void
6429f_hlID(typval_T *argvars, typval_T *rettv)
6430{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006431 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006432}
6433
6434/*
6435 * "highlight_exists()" function
6436 */
6437 static void
6438f_hlexists(typval_T *argvars, typval_T *rettv)
6439{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006440 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006441}
6442
6443/*
6444 * "hostname()" function
6445 */
6446 static void
6447f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6448{
6449 char_u hostname[256];
6450
6451 mch_get_host_name(hostname, 256);
6452 rettv->v_type = VAR_STRING;
6453 rettv->vval.v_string = vim_strsave(hostname);
6454}
6455
6456/*
6457 * iconv() function
6458 */
6459 static void
6460f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6461{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 char_u buf1[NUMBUFLEN];
6463 char_u buf2[NUMBUFLEN];
6464 char_u *from, *to, *str;
6465 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466
6467 rettv->v_type = VAR_STRING;
6468 rettv->vval.v_string = NULL;
6469
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006470 str = tv_get_string(&argvars[0]);
6471 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6472 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473 vimconv.vc_type = CONV_NONE;
6474 convert_setup(&vimconv, from, to);
6475
6476 /* If the encodings are equal, no conversion needed. */
6477 if (vimconv.vc_type == CONV_NONE)
6478 rettv->vval.v_string = vim_strsave(str);
6479 else
6480 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6481
6482 convert_setup(&vimconv, NULL, NULL);
6483 vim_free(from);
6484 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485}
6486
6487/*
6488 * "indent()" function
6489 */
6490 static void
6491f_indent(typval_T *argvars, typval_T *rettv)
6492{
6493 linenr_T lnum;
6494
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006495 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6497 rettv->vval.v_number = get_indent_lnum(lnum);
6498 else
6499 rettv->vval.v_number = -1;
6500}
6501
6502/*
6503 * "index()" function
6504 */
6505 static void
6506f_index(typval_T *argvars, typval_T *rettv)
6507{
6508 list_T *l;
6509 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006510 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006511 long idx = 0;
6512 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006513 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514
6515 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006516 if (argvars[0].v_type == VAR_BLOB)
6517 {
6518 typval_T tv;
6519 int start = 0;
6520
6521 if (argvars[2].v_type != VAR_UNKNOWN)
6522 {
6523 start = tv_get_number_chk(&argvars[2], &error);
6524 if (error)
6525 return;
6526 }
6527 b = argvars[0].vval.v_blob;
6528 if (b == NULL)
6529 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006530 if (start < 0)
6531 {
6532 start = blob_len(b) + start;
6533 if (start < 0)
6534 start = 0;
6535 }
6536
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006537 for (idx = start; idx < blob_len(b); ++idx)
6538 {
6539 tv.v_type = VAR_NUMBER;
6540 tv.vval.v_number = blob_get(b, idx);
6541 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6542 {
6543 rettv->vval.v_number = idx;
6544 return;
6545 }
6546 }
6547 return;
6548 }
6549 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006551 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006552 return;
6553 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006554
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555 l = argvars[0].vval.v_list;
6556 if (l != NULL)
6557 {
6558 item = l->lv_first;
6559 if (argvars[2].v_type != VAR_UNKNOWN)
6560 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006561 /* Start at specified item. Use the cached index that list_find()
6562 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006563 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006564 idx = l->lv_idx;
6565 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006566 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006567 if (error)
6568 item = NULL;
6569 }
6570
6571 for ( ; item != NULL; item = item->li_next, ++idx)
6572 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6573 {
6574 rettv->vval.v_number = idx;
6575 break;
6576 }
6577 }
6578}
6579
6580static int inputsecret_flag = 0;
6581
6582/*
6583 * "input()" function
6584 * Also handles inputsecret() when inputsecret is set.
6585 */
6586 static void
6587f_input(typval_T *argvars, typval_T *rettv)
6588{
6589 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6590}
6591
6592/*
6593 * "inputdialog()" function
6594 */
6595 static void
6596f_inputdialog(typval_T *argvars, typval_T *rettv)
6597{
6598#if defined(FEAT_GUI_TEXTDIALOG)
6599 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6600 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6601 {
6602 char_u *message;
6603 char_u buf[NUMBUFLEN];
6604 char_u *defstr = (char_u *)"";
6605
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006606 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006607 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006608 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006609 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6610 else
6611 IObuff[0] = NUL;
6612 if (message != NULL && defstr != NULL
6613 && do_dialog(VIM_QUESTION, NULL, message,
6614 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6615 rettv->vval.v_string = vim_strsave(IObuff);
6616 else
6617 {
6618 if (message != NULL && defstr != NULL
6619 && argvars[1].v_type != VAR_UNKNOWN
6620 && argvars[2].v_type != VAR_UNKNOWN)
6621 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006622 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006623 else
6624 rettv->vval.v_string = NULL;
6625 }
6626 rettv->v_type = VAR_STRING;
6627 }
6628 else
6629#endif
6630 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6631}
6632
6633/*
6634 * "inputlist()" function
6635 */
6636 static void
6637f_inputlist(typval_T *argvars, typval_T *rettv)
6638{
6639 listitem_T *li;
6640 int selected;
6641 int mouse_used;
6642
6643#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006644 /* While starting up, there is no place to enter text. When running tests
6645 * with --not-a-term we assume feedkeys() will be used. */
6646 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006647 return;
6648#endif
6649 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6650 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006651 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652 return;
6653 }
6654
6655 msg_start();
6656 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6657 lines_left = Rows; /* avoid more prompt */
6658 msg_scroll = TRUE;
6659 msg_clr_eos();
6660
6661 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6662 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006663 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006664 msg_putchar('\n');
6665 }
6666
6667 /* Ask for choice. */
6668 selected = prompt_for_number(&mouse_used);
6669 if (mouse_used)
6670 selected -= lines_left;
6671
6672 rettv->vval.v_number = selected;
6673}
6674
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6676
6677/*
6678 * "inputrestore()" function
6679 */
6680 static void
6681f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6682{
6683 if (ga_userinput.ga_len > 0)
6684 {
6685 --ga_userinput.ga_len;
6686 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6687 + ga_userinput.ga_len);
6688 /* default return is zero == OK */
6689 }
6690 else if (p_verbose > 1)
6691 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006692 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693 rettv->vval.v_number = 1; /* Failed */
6694 }
6695}
6696
6697/*
6698 * "inputsave()" function
6699 */
6700 static void
6701f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6702{
6703 /* Add an entry to the stack of typeahead storage. */
6704 if (ga_grow(&ga_userinput, 1) == OK)
6705 {
6706 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6707 + ga_userinput.ga_len);
6708 ++ga_userinput.ga_len;
6709 /* default return is zero == OK */
6710 }
6711 else
6712 rettv->vval.v_number = 1; /* Failed */
6713}
6714
6715/*
6716 * "inputsecret()" function
6717 */
6718 static void
6719f_inputsecret(typval_T *argvars, typval_T *rettv)
6720{
6721 ++cmdline_star;
6722 ++inputsecret_flag;
6723 f_input(argvars, rettv);
6724 --cmdline_star;
6725 --inputsecret_flag;
6726}
6727
6728/*
6729 * "insert()" function
6730 */
6731 static void
6732f_insert(typval_T *argvars, typval_T *rettv)
6733{
6734 long before = 0;
6735 listitem_T *item;
6736 list_T *l;
6737 int error = FALSE;
6738
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006739 if (argvars[0].v_type == VAR_BLOB)
6740 {
6741 int val, len;
6742 char_u *p;
6743
6744 len = blob_len(argvars[0].vval.v_blob);
6745 if (argvars[2].v_type != VAR_UNKNOWN)
6746 {
6747 before = (long)tv_get_number_chk(&argvars[2], &error);
6748 if (error)
6749 return; // type error; errmsg already given
6750 if (before < 0 || before > len)
6751 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006752 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006753 return;
6754 }
6755 }
6756 val = tv_get_number_chk(&argvars[1], &error);
6757 if (error)
6758 return;
6759 if (val < 0 || val > 255)
6760 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006761 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006762 return;
6763 }
6764
6765 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6766 return;
6767 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6768 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6769 *(p + before) = val;
6770 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6771
6772 copy_tv(&argvars[0], rettv);
6773 }
6774 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006775 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006776 else if ((l = argvars[0].vval.v_list) != NULL
6777 && !var_check_lock(l->lv_lock,
6778 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 {
6780 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006781 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782 if (error)
6783 return; /* type error; errmsg already given */
6784
6785 if (before == l->lv_len)
6786 item = NULL;
6787 else
6788 {
6789 item = list_find(l, before);
6790 if (item == NULL)
6791 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006792 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006793 l = NULL;
6794 }
6795 }
6796 if (l != NULL)
6797 {
6798 list_insert_tv(l, &argvars[1], item);
6799 copy_tv(&argvars[0], rettv);
6800 }
6801 }
6802}
6803
6804/*
6805 * "invert(expr)" function
6806 */
6807 static void
6808f_invert(typval_T *argvars, typval_T *rettv)
6809{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006810 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006811}
6812
6813/*
6814 * "isdirectory()" function
6815 */
6816 static void
6817f_isdirectory(typval_T *argvars, typval_T *rettv)
6818{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006819 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006820}
6821
6822/*
6823 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6824 * or it refers to a List or Dictionary that is locked.
6825 */
6826 static int
6827tv_islocked(typval_T *tv)
6828{
6829 return (tv->v_lock & VAR_LOCKED)
6830 || (tv->v_type == VAR_LIST
6831 && tv->vval.v_list != NULL
6832 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6833 || (tv->v_type == VAR_DICT
6834 && tv->vval.v_dict != NULL
6835 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6836}
6837
6838/*
6839 * "islocked()" function
6840 */
6841 static void
6842f_islocked(typval_T *argvars, typval_T *rettv)
6843{
6844 lval_T lv;
6845 char_u *end;
6846 dictitem_T *di;
6847
6848 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006849 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006850 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 if (end != NULL && lv.ll_name != NULL)
6852 {
6853 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006854 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006855 else
6856 {
6857 if (lv.ll_tv == NULL)
6858 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006859 di = find_var(lv.ll_name, NULL, TRUE);
6860 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006861 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006862 /* Consider a variable locked when:
6863 * 1. the variable itself is locked
6864 * 2. the value of the variable is locked.
6865 * 3. the List or Dict value is locked.
6866 */
6867 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6868 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869 }
6870 }
6871 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006872 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006873 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006874 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006875 else if (lv.ll_list != NULL)
6876 /* List item. */
6877 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6878 else
6879 /* Dictionary item. */
6880 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6881 }
6882 }
6883
6884 clear_lval(&lv);
6885}
6886
6887#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6888/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006889 * "isinf()" function
6890 */
6891 static void
6892f_isinf(typval_T *argvars, typval_T *rettv)
6893{
6894 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6895 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6896}
6897
6898/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006899 * "isnan()" function
6900 */
6901 static void
6902f_isnan(typval_T *argvars, typval_T *rettv)
6903{
6904 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6905 && isnan(argvars[0].vval.v_float);
6906}
6907#endif
6908
6909/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006910 * "last_buffer_nr()" function.
6911 */
6912 static void
6913f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6914{
6915 int n = 0;
6916 buf_T *buf;
6917
Bram Moolenaar29323592016-07-24 22:04:11 +02006918 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006919 if (n < buf->b_fnum)
6920 n = buf->b_fnum;
6921
6922 rettv->vval.v_number = n;
6923}
6924
6925/*
6926 * "len()" function
6927 */
6928 static void
6929f_len(typval_T *argvars, typval_T *rettv)
6930{
6931 switch (argvars[0].v_type)
6932 {
6933 case VAR_STRING:
6934 case VAR_NUMBER:
6935 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006936 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006937 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006938 case VAR_BLOB:
6939 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6940 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006941 case VAR_LIST:
6942 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6943 break;
6944 case VAR_DICT:
6945 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6946 break;
6947 case VAR_UNKNOWN:
6948 case VAR_SPECIAL:
6949 case VAR_FLOAT:
6950 case VAR_FUNC:
6951 case VAR_PARTIAL:
6952 case VAR_JOB:
6953 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006954 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006955 break;
6956 }
6957}
6958
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006960libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961{
6962#ifdef FEAT_LIBCALL
6963 char_u *string_in;
6964 char_u **string_result;
6965 int nr_result;
6966#endif
6967
6968 rettv->v_type = type;
6969 if (type != VAR_NUMBER)
6970 rettv->vval.v_string = NULL;
6971
6972 if (check_restricted() || check_secure())
6973 return;
6974
6975#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006976 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006977 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6978 {
6979 string_in = NULL;
6980 if (argvars[2].v_type == VAR_STRING)
6981 string_in = argvars[2].vval.v_string;
6982 if (type == VAR_NUMBER)
6983 string_result = NULL;
6984 else
6985 string_result = &rettv->vval.v_string;
6986 if (mch_libcall(argvars[0].vval.v_string,
6987 argvars[1].vval.v_string,
6988 string_in,
6989 argvars[2].vval.v_number,
6990 string_result,
6991 &nr_result) == OK
6992 && type == VAR_NUMBER)
6993 rettv->vval.v_number = nr_result;
6994 }
6995#endif
6996}
6997
6998/*
6999 * "libcall()" function
7000 */
7001 static void
7002f_libcall(typval_T *argvars, typval_T *rettv)
7003{
7004 libcall_common(argvars, rettv, VAR_STRING);
7005}
7006
7007/*
7008 * "libcallnr()" function
7009 */
7010 static void
7011f_libcallnr(typval_T *argvars, typval_T *rettv)
7012{
7013 libcall_common(argvars, rettv, VAR_NUMBER);
7014}
7015
7016/*
7017 * "line(string)" function
7018 */
7019 static void
7020f_line(typval_T *argvars, typval_T *rettv)
7021{
7022 linenr_T lnum = 0;
7023 pos_T *fp;
7024 int fnum;
7025
7026 fp = var2fpos(&argvars[0], TRUE, &fnum);
7027 if (fp != NULL)
7028 lnum = fp->lnum;
7029 rettv->vval.v_number = lnum;
7030}
7031
7032/*
7033 * "line2byte(lnum)" function
7034 */
7035 static void
7036f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7037{
7038#ifndef FEAT_BYTEOFF
7039 rettv->vval.v_number = -1;
7040#else
7041 linenr_T lnum;
7042
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007043 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007044 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7045 rettv->vval.v_number = -1;
7046 else
7047 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7048 if (rettv->vval.v_number >= 0)
7049 ++rettv->vval.v_number;
7050#endif
7051}
7052
7053/*
7054 * "lispindent(lnum)" function
7055 */
7056 static void
7057f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7058{
7059#ifdef FEAT_LISP
7060 pos_T pos;
7061 linenr_T lnum;
7062
7063 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007064 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007065 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7066 {
7067 curwin->w_cursor.lnum = lnum;
7068 rettv->vval.v_number = get_lisp_indent();
7069 curwin->w_cursor = pos;
7070 }
7071 else
7072#endif
7073 rettv->vval.v_number = -1;
7074}
7075
7076/*
7077 * "localtime()" function
7078 */
7079 static void
7080f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7081{
7082 rettv->vval.v_number = (varnumber_T)time(NULL);
7083}
7084
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007085#ifdef FEAT_FLOAT
7086/*
7087 * "log()" function
7088 */
7089 static void
7090f_log(typval_T *argvars, typval_T *rettv)
7091{
7092 float_T f = 0.0;
7093
7094 rettv->v_type = VAR_FLOAT;
7095 if (get_float_arg(argvars, &f) == OK)
7096 rettv->vval.v_float = log(f);
7097 else
7098 rettv->vval.v_float = 0.0;
7099}
7100
7101/*
7102 * "log10()" function
7103 */
7104 static void
7105f_log10(typval_T *argvars, typval_T *rettv)
7106{
7107 float_T f = 0.0;
7108
7109 rettv->v_type = VAR_FLOAT;
7110 if (get_float_arg(argvars, &f) == OK)
7111 rettv->vval.v_float = log10(f);
7112 else
7113 rettv->vval.v_float = 0.0;
7114}
7115#endif
7116
7117#ifdef FEAT_LUA
7118/*
7119 * "luaeval()" function
7120 */
7121 static void
7122f_luaeval(typval_T *argvars, typval_T *rettv)
7123{
7124 char_u *str;
7125 char_u buf[NUMBUFLEN];
7126
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007127 if (check_restricted() || check_secure())
7128 return;
7129
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007130 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 do_luaeval(str, argvars + 1, rettv);
7132}
7133#endif
7134
7135/*
7136 * "map()" function
7137 */
7138 static void
7139f_map(typval_T *argvars, typval_T *rettv)
7140{
7141 filter_map(argvars, rettv, TRUE);
7142}
7143
7144/*
7145 * "maparg()" function
7146 */
7147 static void
7148f_maparg(typval_T *argvars, typval_T *rettv)
7149{
7150 get_maparg(argvars, rettv, TRUE);
7151}
7152
7153/*
7154 * "mapcheck()" function
7155 */
7156 static void
7157f_mapcheck(typval_T *argvars, typval_T *rettv)
7158{
7159 get_maparg(argvars, rettv, FALSE);
7160}
7161
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007162typedef enum
7163{
7164 MATCH_END, /* matchend() */
7165 MATCH_MATCH, /* match() */
7166 MATCH_STR, /* matchstr() */
7167 MATCH_LIST, /* matchlist() */
7168 MATCH_POS /* matchstrpos() */
7169} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007170
7171 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007172find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007173{
7174 char_u *str = NULL;
7175 long len = 0;
7176 char_u *expr = NULL;
7177 char_u *pat;
7178 regmatch_T regmatch;
7179 char_u patbuf[NUMBUFLEN];
7180 char_u strbuf[NUMBUFLEN];
7181 char_u *save_cpo;
7182 long start = 0;
7183 long nth = 1;
7184 colnr_T startcol = 0;
7185 int match = 0;
7186 list_T *l = NULL;
7187 listitem_T *li = NULL;
7188 long idx = 0;
7189 char_u *tofree = NULL;
7190
7191 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7192 save_cpo = p_cpo;
7193 p_cpo = (char_u *)"";
7194
7195 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007196 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007198 /* type MATCH_LIST: return empty list when there are no matches.
7199 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007200 if (rettv_list_alloc(rettv) == FAIL)
7201 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007202 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007203 && (list_append_string(rettv->vval.v_list,
7204 (char_u *)"", 0) == FAIL
7205 || list_append_number(rettv->vval.v_list,
7206 (varnumber_T)-1) == FAIL
7207 || list_append_number(rettv->vval.v_list,
7208 (varnumber_T)-1) == FAIL
7209 || list_append_number(rettv->vval.v_list,
7210 (varnumber_T)-1) == FAIL))
7211 {
7212 list_free(rettv->vval.v_list);
7213 rettv->vval.v_list = NULL;
7214 goto theend;
7215 }
7216 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007217 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218 {
7219 rettv->v_type = VAR_STRING;
7220 rettv->vval.v_string = NULL;
7221 }
7222
7223 if (argvars[0].v_type == VAR_LIST)
7224 {
7225 if ((l = argvars[0].vval.v_list) == NULL)
7226 goto theend;
7227 li = l->lv_first;
7228 }
7229 else
7230 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007231 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007232 len = (long)STRLEN(str);
7233 }
7234
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007235 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 if (pat == NULL)
7237 goto theend;
7238
7239 if (argvars[2].v_type != VAR_UNKNOWN)
7240 {
7241 int error = FALSE;
7242
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007243 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007244 if (error)
7245 goto theend;
7246 if (l != NULL)
7247 {
7248 li = list_find(l, start);
7249 if (li == NULL)
7250 goto theend;
7251 idx = l->lv_idx; /* use the cached index */
7252 }
7253 else
7254 {
7255 if (start < 0)
7256 start = 0;
7257 if (start > len)
7258 goto theend;
7259 /* When "count" argument is there ignore matches before "start",
7260 * otherwise skip part of the string. Differs when pattern is "^"
7261 * or "\<". */
7262 if (argvars[3].v_type != VAR_UNKNOWN)
7263 startcol = start;
7264 else
7265 {
7266 str += start;
7267 len -= start;
7268 }
7269 }
7270
7271 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007272 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007273 if (error)
7274 goto theend;
7275 }
7276
7277 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7278 if (regmatch.regprog != NULL)
7279 {
7280 regmatch.rm_ic = p_ic;
7281
7282 for (;;)
7283 {
7284 if (l != NULL)
7285 {
7286 if (li == NULL)
7287 {
7288 match = FALSE;
7289 break;
7290 }
7291 vim_free(tofree);
7292 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7293 if (str == NULL)
7294 break;
7295 }
7296
7297 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7298
7299 if (match && --nth <= 0)
7300 break;
7301 if (l == NULL && !match)
7302 break;
7303
7304 /* Advance to just after the match. */
7305 if (l != NULL)
7306 {
7307 li = li->li_next;
7308 ++idx;
7309 }
7310 else
7311 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007312 startcol = (colnr_T)(regmatch.startp[0]
7313 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007314 if (startcol > (colnr_T)len
7315 || str + startcol <= regmatch.startp[0])
7316 {
7317 match = FALSE;
7318 break;
7319 }
7320 }
7321 }
7322
7323 if (match)
7324 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007325 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007326 {
7327 listitem_T *li1 = rettv->vval.v_list->lv_first;
7328 listitem_T *li2 = li1->li_next;
7329 listitem_T *li3 = li2->li_next;
7330 listitem_T *li4 = li3->li_next;
7331
7332 vim_free(li1->li_tv.vval.v_string);
7333 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7334 (int)(regmatch.endp[0] - regmatch.startp[0]));
7335 li3->li_tv.vval.v_number =
7336 (varnumber_T)(regmatch.startp[0] - expr);
7337 li4->li_tv.vval.v_number =
7338 (varnumber_T)(regmatch.endp[0] - expr);
7339 if (l != NULL)
7340 li2->li_tv.vval.v_number = (varnumber_T)idx;
7341 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007342 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007343 {
7344 int i;
7345
7346 /* return list with matched string and submatches */
7347 for (i = 0; i < NSUBEXP; ++i)
7348 {
7349 if (regmatch.endp[i] == NULL)
7350 {
7351 if (list_append_string(rettv->vval.v_list,
7352 (char_u *)"", 0) == FAIL)
7353 break;
7354 }
7355 else if (list_append_string(rettv->vval.v_list,
7356 regmatch.startp[i],
7357 (int)(regmatch.endp[i] - regmatch.startp[i]))
7358 == FAIL)
7359 break;
7360 }
7361 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007362 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007363 {
7364 /* return matched string */
7365 if (l != NULL)
7366 copy_tv(&li->li_tv, rettv);
7367 else
7368 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7369 (int)(regmatch.endp[0] - regmatch.startp[0]));
7370 }
7371 else if (l != NULL)
7372 rettv->vval.v_number = idx;
7373 else
7374 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007375 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007376 rettv->vval.v_number =
7377 (varnumber_T)(regmatch.startp[0] - str);
7378 else
7379 rettv->vval.v_number =
7380 (varnumber_T)(regmatch.endp[0] - str);
7381 rettv->vval.v_number += (varnumber_T)(str - expr);
7382 }
7383 }
7384 vim_regfree(regmatch.regprog);
7385 }
7386
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007387theend:
7388 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389 /* matchstrpos() without a list: drop the second item. */
7390 listitem_remove(rettv->vval.v_list,
7391 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 vim_free(tofree);
7393 p_cpo = save_cpo;
7394}
7395
7396/*
7397 * "match()" function
7398 */
7399 static void
7400f_match(typval_T *argvars, typval_T *rettv)
7401{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007402 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403}
7404
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405/*
7406 * "matchend()" function
7407 */
7408 static void
7409f_matchend(typval_T *argvars, typval_T *rettv)
7410{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007411 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412}
7413
7414/*
7415 * "matchlist()" function
7416 */
7417 static void
7418f_matchlist(typval_T *argvars, typval_T *rettv)
7419{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007420 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007421}
7422
7423/*
7424 * "matchstr()" function
7425 */
7426 static void
7427f_matchstr(typval_T *argvars, typval_T *rettv)
7428{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007429 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007430}
7431
7432/*
7433 * "matchstrpos()" function
7434 */
7435 static void
7436f_matchstrpos(typval_T *argvars, typval_T *rettv)
7437{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007438 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439}
7440
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 static void
7442max_min(typval_T *argvars, typval_T *rettv, int domax)
7443{
7444 varnumber_T n = 0;
7445 varnumber_T i;
7446 int error = FALSE;
7447
7448 if (argvars[0].v_type == VAR_LIST)
7449 {
7450 list_T *l;
7451 listitem_T *li;
7452
7453 l = argvars[0].vval.v_list;
7454 if (l != NULL)
7455 {
7456 li = l->lv_first;
7457 if (li != NULL)
7458 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007459 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007460 for (;;)
7461 {
7462 li = li->li_next;
7463 if (li == NULL)
7464 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007465 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007466 if (domax ? i > n : i < n)
7467 n = i;
7468 }
7469 }
7470 }
7471 }
7472 else if (argvars[0].v_type == VAR_DICT)
7473 {
7474 dict_T *d;
7475 int first = TRUE;
7476 hashitem_T *hi;
7477 int todo;
7478
7479 d = argvars[0].vval.v_dict;
7480 if (d != NULL)
7481 {
7482 todo = (int)d->dv_hashtab.ht_used;
7483 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7484 {
7485 if (!HASHITEM_EMPTY(hi))
7486 {
7487 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007488 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007489 if (first)
7490 {
7491 n = i;
7492 first = FALSE;
7493 }
7494 else if (domax ? i > n : i < n)
7495 n = i;
7496 }
7497 }
7498 }
7499 }
7500 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007501 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502 rettv->vval.v_number = error ? 0 : n;
7503}
7504
7505/*
7506 * "max()" function
7507 */
7508 static void
7509f_max(typval_T *argvars, typval_T *rettv)
7510{
7511 max_min(argvars, rettv, TRUE);
7512}
7513
7514/*
7515 * "min()" function
7516 */
7517 static void
7518f_min(typval_T *argvars, typval_T *rettv)
7519{
7520 max_min(argvars, rettv, FALSE);
7521}
7522
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007523/*
7524 * Create the directory in which "dir" is located, and higher levels when
7525 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007526 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527 */
7528 static int
7529mkdir_recurse(char_u *dir, int prot)
7530{
7531 char_u *p;
7532 char_u *updir;
7533 int r = FAIL;
7534
7535 /* Get end of directory name in "dir".
7536 * We're done when it's "/" or "c:/". */
7537 p = gettail_sep(dir);
7538 if (p <= get_past_head(dir))
7539 return OK;
7540
7541 /* If the directory exists we're done. Otherwise: create it.*/
7542 updir = vim_strnsave(dir, (int)(p - dir));
7543 if (updir == NULL)
7544 return FAIL;
7545 if (mch_isdir(updir))
7546 r = OK;
7547 else if (mkdir_recurse(updir, prot) == OK)
7548 r = vim_mkdir_emsg(updir, prot);
7549 vim_free(updir);
7550 return r;
7551}
7552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007553/*
7554 * "mkdir()" function
7555 */
7556 static void
7557f_mkdir(typval_T *argvars, typval_T *rettv)
7558{
7559 char_u *dir;
7560 char_u buf[NUMBUFLEN];
7561 int prot = 0755;
7562
7563 rettv->vval.v_number = FAIL;
7564 if (check_restricted() || check_secure())
7565 return;
7566
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007567 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007568 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007569 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007571 if (*gettail(dir) == NUL)
7572 /* remove trailing slashes */
7573 *gettail_sep(dir) = NUL;
7574
7575 if (argvars[1].v_type != VAR_UNKNOWN)
7576 {
7577 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007579 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007580 if (prot == -1)
7581 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007582 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007583 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007584 {
7585 if (mch_isdir(dir))
7586 {
7587 /* With the "p" flag it's OK if the dir already exists. */
7588 rettv->vval.v_number = OK;
7589 return;
7590 }
7591 mkdir_recurse(dir, prot);
7592 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007593 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007594 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007595}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007596
7597/*
7598 * "mode()" function
7599 */
7600 static void
7601f_mode(typval_T *argvars, typval_T *rettv)
7602{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007603 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007604
Bram Moolenaar612cc382018-07-29 15:34:26 +02007605 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007606
7607 if (time_for_testing == 93784)
7608 {
7609 /* Testing the two-character code. */
7610 buf[0] = 'x';
7611 buf[1] = '!';
7612 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007613#ifdef FEAT_TERMINAL
7614 else if (term_use_loop())
7615 buf[0] = 't';
7616#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617 else if (VIsual_active)
7618 {
7619 if (VIsual_select)
7620 buf[0] = VIsual_mode + 's' - 'v';
7621 else
7622 buf[0] = VIsual_mode;
7623 }
7624 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7625 || State == CONFIRM)
7626 {
7627 buf[0] = 'r';
7628 if (State == ASKMORE)
7629 buf[1] = 'm';
7630 else if (State == CONFIRM)
7631 buf[1] = '?';
7632 }
7633 else if (State == EXTERNCMD)
7634 buf[0] = '!';
7635 else if (State & INSERT)
7636 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007637 if (State & VREPLACE_FLAG)
7638 {
7639 buf[0] = 'R';
7640 buf[1] = 'v';
7641 }
7642 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007643 {
7644 if (State & REPLACE_FLAG)
7645 buf[0] = 'R';
7646 else
7647 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007648 if (ins_compl_active())
7649 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007650 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007651 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007652 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007654 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655 {
7656 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007657 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007658 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007659 else if (exmode_active == EXMODE_NORMAL)
7660 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007661 }
7662 else
7663 {
7664 buf[0] = 'n';
7665 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007666 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007668 // to be able to detect force-linewise/blockwise/characterwise operations
7669 buf[2] = motion_force;
7670 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007671 else if (restart_edit == 'I' || restart_edit == 'R'
7672 || restart_edit == 'V')
7673 {
7674 buf[1] = 'i';
7675 buf[2] = restart_edit;
7676 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007677 }
7678
7679 /* Clear out the minor mode when the argument is not a non-zero number or
7680 * non-empty string. */
7681 if (!non_zero_arg(&argvars[0]))
7682 buf[1] = NUL;
7683
7684 rettv->vval.v_string = vim_strsave(buf);
7685 rettv->v_type = VAR_STRING;
7686}
7687
7688#if defined(FEAT_MZSCHEME) || defined(PROTO)
7689/*
7690 * "mzeval()" function
7691 */
7692 static void
7693f_mzeval(typval_T *argvars, typval_T *rettv)
7694{
7695 char_u *str;
7696 char_u buf[NUMBUFLEN];
7697
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007698 if (check_restricted() || check_secure())
7699 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007700 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007701 do_mzeval(str, rettv);
7702}
7703
7704 void
7705mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7706{
7707 typval_T argvars[3];
7708
7709 argvars[0].v_type = VAR_STRING;
7710 argvars[0].vval.v_string = name;
7711 copy_tv(args, &argvars[1]);
7712 argvars[2].v_type = VAR_UNKNOWN;
7713 f_call(argvars, rettv);
7714 clear_tv(&argvars[1]);
7715}
7716#endif
7717
7718/*
7719 * "nextnonblank()" function
7720 */
7721 static void
7722f_nextnonblank(typval_T *argvars, typval_T *rettv)
7723{
7724 linenr_T lnum;
7725
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007726 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727 {
7728 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7729 {
7730 lnum = 0;
7731 break;
7732 }
7733 if (*skipwhite(ml_get(lnum)) != NUL)
7734 break;
7735 }
7736 rettv->vval.v_number = lnum;
7737}
7738
7739/*
7740 * "nr2char()" function
7741 */
7742 static void
7743f_nr2char(typval_T *argvars, typval_T *rettv)
7744{
7745 char_u buf[NUMBUFLEN];
7746
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747 if (has_mbyte)
7748 {
7749 int utf8 = 0;
7750
7751 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007752 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007753 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007754 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007755 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007756 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007757 }
7758 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007760 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007761 buf[1] = NUL;
7762 }
7763 rettv->v_type = VAR_STRING;
7764 rettv->vval.v_string = vim_strsave(buf);
7765}
7766
7767/*
7768 * "or(expr, expr)" function
7769 */
7770 static void
7771f_or(typval_T *argvars, typval_T *rettv)
7772{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007773 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7774 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007775}
7776
7777/*
7778 * "pathshorten()" function
7779 */
7780 static void
7781f_pathshorten(typval_T *argvars, typval_T *rettv)
7782{
7783 char_u *p;
7784
7785 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007786 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007787 if (p == NULL)
7788 rettv->vval.v_string = NULL;
7789 else
7790 {
7791 p = vim_strsave(p);
7792 rettv->vval.v_string = p;
7793 if (p != NULL)
7794 shorten_dir(p);
7795 }
7796}
7797
7798#ifdef FEAT_PERL
7799/*
7800 * "perleval()" function
7801 */
7802 static void
7803f_perleval(typval_T *argvars, typval_T *rettv)
7804{
7805 char_u *str;
7806 char_u buf[NUMBUFLEN];
7807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007808 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007809 do_perleval(str, rettv);
7810}
7811#endif
7812
7813#ifdef FEAT_FLOAT
7814/*
7815 * "pow()" function
7816 */
7817 static void
7818f_pow(typval_T *argvars, typval_T *rettv)
7819{
7820 float_T fx = 0.0, fy = 0.0;
7821
7822 rettv->v_type = VAR_FLOAT;
7823 if (get_float_arg(argvars, &fx) == OK
7824 && get_float_arg(&argvars[1], &fy) == OK)
7825 rettv->vval.v_float = pow(fx, fy);
7826 else
7827 rettv->vval.v_float = 0.0;
7828}
7829#endif
7830
7831/*
7832 * "prevnonblank()" function
7833 */
7834 static void
7835f_prevnonblank(typval_T *argvars, typval_T *rettv)
7836{
7837 linenr_T lnum;
7838
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007839 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7841 lnum = 0;
7842 else
7843 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7844 --lnum;
7845 rettv->vval.v_number = lnum;
7846}
7847
7848/* This dummy va_list is here because:
7849 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7850 * - locally in the function results in a "used before set" warning
7851 * - using va_start() to initialize it gives "function with fixed args" error */
7852static va_list ap;
7853
7854/*
7855 * "printf()" function
7856 */
7857 static void
7858f_printf(typval_T *argvars, typval_T *rettv)
7859{
7860 char_u buf[NUMBUFLEN];
7861 int len;
7862 char_u *s;
7863 int saved_did_emsg = did_emsg;
7864 char *fmt;
7865
7866 rettv->v_type = VAR_STRING;
7867 rettv->vval.v_string = NULL;
7868
7869 /* Get the required length, allocate the buffer and do it for real. */
7870 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007871 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007872 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007873 if (!did_emsg)
7874 {
7875 s = alloc(len + 1);
7876 if (s != NULL)
7877 {
7878 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007879 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7880 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007881 }
7882 }
7883 did_emsg |= saved_did_emsg;
7884}
7885
7886/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007887 * "pum_getpos()" function
7888 */
7889 static void
7890f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7891{
7892 if (rettv_dict_alloc(rettv) != OK)
7893 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007894 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007895}
7896
7897/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007898 * "pumvisible()" function
7899 */
7900 static void
7901f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7902{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007903 if (pum_visible())
7904 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007905}
7906
7907#ifdef FEAT_PYTHON3
7908/*
7909 * "py3eval()" function
7910 */
7911 static void
7912f_py3eval(typval_T *argvars, typval_T *rettv)
7913{
7914 char_u *str;
7915 char_u buf[NUMBUFLEN];
7916
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007917 if (check_restricted() || check_secure())
7918 return;
7919
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007920 if (p_pyx == 0)
7921 p_pyx = 3;
7922
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007923 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924 do_py3eval(str, rettv);
7925}
7926#endif
7927
7928#ifdef FEAT_PYTHON
7929/*
7930 * "pyeval()" function
7931 */
7932 static void
7933f_pyeval(typval_T *argvars, typval_T *rettv)
7934{
7935 char_u *str;
7936 char_u buf[NUMBUFLEN];
7937
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007938 if (check_restricted() || check_secure())
7939 return;
7940
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007941 if (p_pyx == 0)
7942 p_pyx = 2;
7943
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007944 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007945 do_pyeval(str, rettv);
7946}
7947#endif
7948
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007949#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7950/*
7951 * "pyxeval()" function
7952 */
7953 static void
7954f_pyxeval(typval_T *argvars, typval_T *rettv)
7955{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007956 if (check_restricted() || check_secure())
7957 return;
7958
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007959# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7960 init_pyxversion();
7961 if (p_pyx == 2)
7962 f_pyeval(argvars, rettv);
7963 else
7964 f_py3eval(argvars, rettv);
7965# elif defined(FEAT_PYTHON)
7966 f_pyeval(argvars, rettv);
7967# elif defined(FEAT_PYTHON3)
7968 f_py3eval(argvars, rettv);
7969# endif
7970}
7971#endif
7972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007973/*
7974 * "range()" function
7975 */
7976 static void
7977f_range(typval_T *argvars, typval_T *rettv)
7978{
7979 varnumber_T start;
7980 varnumber_T end;
7981 varnumber_T stride = 1;
7982 varnumber_T i;
7983 int error = FALSE;
7984
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007985 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007986 if (argvars[1].v_type == VAR_UNKNOWN)
7987 {
7988 end = start - 1;
7989 start = 0;
7990 }
7991 else
7992 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007993 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007994 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007995 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007996 }
7997
7998 if (error)
7999 return; /* type error; errmsg already given */
8000 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008001 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008003 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 else
8005 {
8006 if (rettv_list_alloc(rettv) == OK)
8007 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8008 if (list_append_number(rettv->vval.v_list,
8009 (varnumber_T)i) == FAIL)
8010 break;
8011 }
8012}
8013
8014/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008015 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008016 */
8017 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008018readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008019{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008020 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008021 typval_T save_val;
8022 typval_T rettv;
8023 typval_T argv[2];
8024 int retval = 0;
8025 int error = FALSE;
8026
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008027 if (expr->v_type == VAR_UNKNOWN)
8028 return 1;
8029
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008030 prepare_vimvar(VV_VAL, &save_val);
8031 set_vim_var_string(VV_VAL, name, -1);
8032 argv[0].v_type = VAR_STRING;
8033 argv[0].vval.v_string = name;
8034
8035 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8036 goto theend;
8037
8038 retval = tv_get_number_chk(&rettv, &error);
8039 if (error)
8040 retval = -1;
8041 clear_tv(&rettv);
8042
8043theend:
8044 set_vim_var_string(VV_VAL, NULL, 0);
8045 restore_vimvar(VV_VAL, &save_val);
8046 return retval;
8047}
8048
8049/*
8050 * "readdir()" function
8051 */
8052 static void
8053f_readdir(typval_T *argvars, typval_T *rettv)
8054{
8055 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008056 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008057 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008058 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008059 garray_T ga;
8060 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008061
8062 if (rettv_list_alloc(rettv) == FAIL)
8063 return;
8064 path = tv_get_string(&argvars[0]);
8065 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008066
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008067 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8068 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008069 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008070 for (i = 0; i < ga.ga_len; i++)
8071 {
8072 p = ((char_u **)ga.ga_data)[i];
8073 list_append_string(rettv->vval.v_list, p, -1);
8074 }
8075 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008076 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008077}
8078
8079/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008080 * "readfile()" function
8081 */
8082 static void
8083f_readfile(typval_T *argvars, typval_T *rettv)
8084{
8085 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008086 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087 int failed = FALSE;
8088 char_u *fname;
8089 FILE *fd;
8090 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8091 int io_size = sizeof(buf);
8092 int readlen; /* size of last fread() */
8093 char_u *prev = NULL; /* previously read bytes, if any */
8094 long prevlen = 0; /* length of data in prev */
8095 long prevsize = 0; /* size of prev buffer */
8096 long maxline = MAXLNUM;
8097 long cnt = 0;
8098 char_u *p; /* position in buf */
8099 char_u *start; /* start of current line */
8100
8101 if (argvars[1].v_type != VAR_UNKNOWN)
8102 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008103 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008104 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008105 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8106 blob = TRUE;
8107
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008108 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008109 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008110 }
8111
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008112 if (blob)
8113 {
8114 if (rettv_blob_alloc(rettv) == FAIL)
8115 return;
8116 }
8117 else
8118 {
8119 if (rettv_list_alloc(rettv) == FAIL)
8120 return;
8121 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122
8123 /* Always open the file in binary mode, library functions have a mind of
8124 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008125 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008126 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8127 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008128 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008129 return;
8130 }
8131
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008132 if (blob)
8133 {
8134 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8135 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008136 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008137 blob_free(rettv->vval.v_blob);
8138 }
8139 fclose(fd);
8140 return;
8141 }
8142
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008143 while (cnt < maxline || maxline < 0)
8144 {
8145 readlen = (int)fread(buf, 1, io_size, fd);
8146
8147 /* This for loop processes what was read, but is also entered at end
8148 * of file so that either:
8149 * - an incomplete line gets written
8150 * - a "binary" file gets an empty line at the end if it ends in a
8151 * newline. */
8152 for (p = buf, start = buf;
8153 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8154 ++p)
8155 {
8156 if (*p == '\n' || readlen <= 0)
8157 {
8158 listitem_T *li;
8159 char_u *s = NULL;
8160 long_u len = p - start;
8161
8162 /* Finished a line. Remove CRs before NL. */
8163 if (readlen > 0 && !binary)
8164 {
8165 while (len > 0 && start[len - 1] == '\r')
8166 --len;
8167 /* removal may cross back to the "prev" string */
8168 if (len == 0)
8169 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8170 --prevlen;
8171 }
8172 if (prevlen == 0)
8173 s = vim_strnsave(start, (int)len);
8174 else
8175 {
8176 /* Change "prev" buffer to be the right size. This way
8177 * the bytes are only copied once, and very long lines are
8178 * allocated only once. */
8179 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8180 {
8181 mch_memmove(s + prevlen, start, len);
8182 s[prevlen + len] = NUL;
8183 prev = NULL; /* the list will own the string */
8184 prevlen = prevsize = 0;
8185 }
8186 }
8187 if (s == NULL)
8188 {
8189 do_outofmem_msg((long_u) prevlen + len + 1);
8190 failed = TRUE;
8191 break;
8192 }
8193
8194 if ((li = listitem_alloc()) == NULL)
8195 {
8196 vim_free(s);
8197 failed = TRUE;
8198 break;
8199 }
8200 li->li_tv.v_type = VAR_STRING;
8201 li->li_tv.v_lock = 0;
8202 li->li_tv.vval.v_string = s;
8203 list_append(rettv->vval.v_list, li);
8204
8205 start = p + 1; /* step over newline */
8206 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8207 break;
8208 }
8209 else if (*p == NUL)
8210 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8212 * when finding the BF and check the previous two bytes. */
8213 else if (*p == 0xbf && enc_utf8 && !binary)
8214 {
8215 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8216 * + 1, these may be in the "prev" string. */
8217 char_u back1 = p >= buf + 1 ? p[-1]
8218 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8219 char_u back2 = p >= buf + 2 ? p[-2]
8220 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8221 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8222
8223 if (back2 == 0xef && back1 == 0xbb)
8224 {
8225 char_u *dest = p - 2;
8226
8227 /* Usually a BOM is at the beginning of a file, and so at
8228 * the beginning of a line; then we can just step over it.
8229 */
8230 if (start == dest)
8231 start = p + 1;
8232 else
8233 {
8234 /* have to shuffle buf to close gap */
8235 int adjust_prevlen = 0;
8236
8237 if (dest < buf)
8238 {
8239 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8240 dest = buf;
8241 }
8242 if (readlen > p - buf + 1)
8243 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8244 readlen -= 3 - adjust_prevlen;
8245 prevlen -= adjust_prevlen;
8246 p = dest - 1;
8247 }
8248 }
8249 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008250 } /* for */
8251
8252 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8253 break;
8254 if (start < p)
8255 {
8256 /* There's part of a line in buf, store it in "prev". */
8257 if (p - start + prevlen >= prevsize)
8258 {
8259 /* need bigger "prev" buffer */
8260 char_u *newprev;
8261
8262 /* A common use case is ordinary text files and "prev" gets a
8263 * fragment of a line, so the first allocation is made
8264 * small, to avoid repeatedly 'allocing' large and
8265 * 'reallocing' small. */
8266 if (prevsize == 0)
8267 prevsize = (long)(p - start);
8268 else
8269 {
8270 long grow50pc = (prevsize * 3) / 2;
8271 long growmin = (long)((p - start) * 2 + prevlen);
8272 prevsize = grow50pc > growmin ? grow50pc : growmin;
8273 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008274 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008275 if (newprev == NULL)
8276 {
8277 do_outofmem_msg((long_u)prevsize);
8278 failed = TRUE;
8279 break;
8280 }
8281 prev = newprev;
8282 }
8283 /* Add the line part to end of "prev". */
8284 mch_memmove(prev + prevlen, start, p - start);
8285 prevlen += (long)(p - start);
8286 }
8287 } /* while */
8288
8289 /*
8290 * For a negative line count use only the lines at the end of the file,
8291 * free the rest.
8292 */
8293 if (!failed && maxline < 0)
8294 while (cnt > -maxline)
8295 {
8296 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8297 --cnt;
8298 }
8299
8300 if (failed)
8301 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008302 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008303 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008304 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305 }
8306
8307 vim_free(prev);
8308 fclose(fd);
8309}
8310
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008311 static void
8312return_register(int regname, typval_T *rettv)
8313{
8314 char_u buf[2] = {0, 0};
8315
8316 buf[0] = (char_u)regname;
8317 rettv->v_type = VAR_STRING;
8318 rettv->vval.v_string = vim_strsave(buf);
8319}
8320
8321/*
8322 * "reg_executing()" function
8323 */
8324 static void
8325f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8326{
8327 return_register(reg_executing, rettv);
8328}
8329
8330/*
8331 * "reg_recording()" function
8332 */
8333 static void
8334f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8335{
8336 return_register(reg_recording, rettv);
8337}
8338
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008340/*
8341 * Convert a List to proftime_T.
8342 * Return FAIL when there is something wrong.
8343 */
8344 static int
8345list2proftime(typval_T *arg, proftime_T *tm)
8346{
8347 long n1, n2;
8348 int error = FALSE;
8349
8350 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8351 || arg->vval.v_list->lv_len != 2)
8352 return FAIL;
8353 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8354 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008355# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008356 tm->HighPart = n1;
8357 tm->LowPart = n2;
8358# else
8359 tm->tv_sec = n1;
8360 tm->tv_usec = n2;
8361# endif
8362 return error ? FAIL : OK;
8363}
8364#endif /* FEAT_RELTIME */
8365
8366/*
8367 * "reltime()" function
8368 */
8369 static void
8370f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8371{
8372#ifdef FEAT_RELTIME
8373 proftime_T res;
8374 proftime_T start;
8375
8376 if (argvars[0].v_type == VAR_UNKNOWN)
8377 {
8378 /* No arguments: get current time. */
8379 profile_start(&res);
8380 }
8381 else if (argvars[1].v_type == VAR_UNKNOWN)
8382 {
8383 if (list2proftime(&argvars[0], &res) == FAIL)
8384 return;
8385 profile_end(&res);
8386 }
8387 else
8388 {
8389 /* Two arguments: compute the difference. */
8390 if (list2proftime(&argvars[0], &start) == FAIL
8391 || list2proftime(&argvars[1], &res) == FAIL)
8392 return;
8393 profile_sub(&res, &start);
8394 }
8395
8396 if (rettv_list_alloc(rettv) == OK)
8397 {
8398 long n1, n2;
8399
Bram Moolenaar4f974752019-02-17 17:44:42 +01008400# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008401 n1 = res.HighPart;
8402 n2 = res.LowPart;
8403# else
8404 n1 = res.tv_sec;
8405 n2 = res.tv_usec;
8406# endif
8407 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8408 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8409 }
8410#endif
8411}
8412
8413#ifdef FEAT_FLOAT
8414/*
8415 * "reltimefloat()" function
8416 */
8417 static void
8418f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8419{
8420# ifdef FEAT_RELTIME
8421 proftime_T tm;
8422# endif
8423
8424 rettv->v_type = VAR_FLOAT;
8425 rettv->vval.v_float = 0;
8426# ifdef FEAT_RELTIME
8427 if (list2proftime(&argvars[0], &tm) == OK)
8428 rettv->vval.v_float = profile_float(&tm);
8429# endif
8430}
8431#endif
8432
8433/*
8434 * "reltimestr()" function
8435 */
8436 static void
8437f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8438{
8439#ifdef FEAT_RELTIME
8440 proftime_T tm;
8441#endif
8442
8443 rettv->v_type = VAR_STRING;
8444 rettv->vval.v_string = NULL;
8445#ifdef FEAT_RELTIME
8446 if (list2proftime(&argvars[0], &tm) == OK)
8447 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8448#endif
8449}
8450
8451#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008452 static void
8453make_connection(void)
8454{
8455 if (X_DISPLAY == NULL
8456# ifdef FEAT_GUI
8457 && !gui.in_use
8458# endif
8459 )
8460 {
8461 x_force_connect = TRUE;
8462 setup_term_clip();
8463 x_force_connect = FALSE;
8464 }
8465}
8466
8467 static int
8468check_connection(void)
8469{
8470 make_connection();
8471 if (X_DISPLAY == NULL)
8472 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008473 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008474 return FAIL;
8475 }
8476 return OK;
8477}
8478#endif
8479
8480#ifdef FEAT_CLIENTSERVER
8481 static void
8482remote_common(typval_T *argvars, typval_T *rettv, int expr)
8483{
8484 char_u *server_name;
8485 char_u *keys;
8486 char_u *r = NULL;
8487 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008488 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008489# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490 HWND w;
8491# else
8492 Window w;
8493# endif
8494
8495 if (check_restricted() || check_secure())
8496 return;
8497
8498# ifdef FEAT_X11
8499 if (check_connection() == FAIL)
8500 return;
8501# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008502 if (argvars[2].v_type != VAR_UNKNOWN
8503 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008504 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008505
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008506 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008507 if (server_name == NULL)
8508 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008509 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008510# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008511 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008512# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008513 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8514 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008515# endif
8516 {
8517 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008518 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008519 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008520 vim_free(r);
8521 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008522 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008523 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008524 return;
8525 }
8526
8527 rettv->vval.v_string = r;
8528
8529 if (argvars[2].v_type != VAR_UNKNOWN)
8530 {
8531 dictitem_T v;
8532 char_u str[30];
8533 char_u *idvar;
8534
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008535 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008536 if (idvar != NULL && *idvar != NUL)
8537 {
8538 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8539 v.di_tv.v_type = VAR_STRING;
8540 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008541 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008542 vim_free(v.di_tv.vval.v_string);
8543 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008544 }
8545}
8546#endif
8547
8548/*
8549 * "remote_expr()" function
8550 */
8551 static void
8552f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8553{
8554 rettv->v_type = VAR_STRING;
8555 rettv->vval.v_string = NULL;
8556#ifdef FEAT_CLIENTSERVER
8557 remote_common(argvars, rettv, TRUE);
8558#endif
8559}
8560
8561/*
8562 * "remote_foreground()" function
8563 */
8564 static void
8565f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8566{
8567#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008568# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008569 /* On Win32 it's done in this application. */
8570 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008571 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008572
8573 if (server_name != NULL)
8574 serverForeground(server_name);
8575 }
8576# else
8577 /* Send a foreground() expression to the server. */
8578 argvars[1].v_type = VAR_STRING;
8579 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8580 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008581 rettv->v_type = VAR_STRING;
8582 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008583 remote_common(argvars, rettv, TRUE);
8584 vim_free(argvars[1].vval.v_string);
8585# endif
8586#endif
8587}
8588
8589 static void
8590f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8591{
8592#ifdef FEAT_CLIENTSERVER
8593 dictitem_T v;
8594 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008595# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596 long_u n = 0;
8597# endif
8598 char_u *serverid;
8599
8600 if (check_restricted() || check_secure())
8601 {
8602 rettv->vval.v_number = -1;
8603 return;
8604 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008605 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008606 if (serverid == NULL)
8607 {
8608 rettv->vval.v_number = -1;
8609 return; /* type error; errmsg already given */
8610 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008611# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008612 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8613 if (n == 0)
8614 rettv->vval.v_number = -1;
8615 else
8616 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008617 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008618 rettv->vval.v_number = (s != NULL);
8619 }
8620# else
8621 if (check_connection() == FAIL)
8622 return;
8623
8624 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8625 serverStrToWin(serverid), &s);
8626# endif
8627
8628 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8629 {
8630 char_u *retvar;
8631
8632 v.di_tv.v_type = VAR_STRING;
8633 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008634 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008635 if (retvar != NULL)
8636 set_var(retvar, &v.di_tv, FALSE);
8637 vim_free(v.di_tv.vval.v_string);
8638 }
8639#else
8640 rettv->vval.v_number = -1;
8641#endif
8642}
8643
8644 static void
8645f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8646{
8647 char_u *r = NULL;
8648
8649#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008650 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008651
8652 if (serverid != NULL && !check_restricted() && !check_secure())
8653 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008654 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008655# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008656 /* The server's HWND is encoded in the 'id' parameter */
8657 long_u n = 0;
8658# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008659
8660 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008661 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008662
Bram Moolenaar4f974752019-02-17 17:44:42 +01008663# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008664 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8665 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008666 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008667 if (r == NULL)
8668# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008669 if (check_connection() == FAIL
8670 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8671 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008672# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008673 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008674 }
8675#endif
8676 rettv->v_type = VAR_STRING;
8677 rettv->vval.v_string = r;
8678}
8679
8680/*
8681 * "remote_send()" function
8682 */
8683 static void
8684f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8685{
8686 rettv->v_type = VAR_STRING;
8687 rettv->vval.v_string = NULL;
8688#ifdef FEAT_CLIENTSERVER
8689 remote_common(argvars, rettv, FALSE);
8690#endif
8691}
8692
8693/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008694 * "remote_startserver()" function
8695 */
8696 static void
8697f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8698{
8699#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008700 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008701
8702 if (server == NULL)
8703 return; /* type error; errmsg already given */
8704 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008705 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008706 else
8707 {
8708# ifdef FEAT_X11
8709 if (check_connection() == OK)
8710 serverRegisterName(X_DISPLAY, server);
8711# else
8712 serverSetName(server);
8713# endif
8714 }
8715#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008716 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008717#endif
8718}
8719
8720/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 * "remove()" function
8722 */
8723 static void
8724f_remove(typval_T *argvars, typval_T *rettv)
8725{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8727
8728 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008729 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008730 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008731 blob_remove(argvars, rettv);
8732 else if (argvars[0].v_type == VAR_LIST)
8733 list_remove(argvars, rettv, arg_errmsg);
8734 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008735 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008736}
8737
8738/*
8739 * "rename({from}, {to})" function
8740 */
8741 static void
8742f_rename(typval_T *argvars, typval_T *rettv)
8743{
8744 char_u buf[NUMBUFLEN];
8745
8746 if (check_restricted() || check_secure())
8747 rettv->vval.v_number = -1;
8748 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008749 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8750 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008751}
8752
8753/*
8754 * "repeat()" function
8755 */
8756 static void
8757f_repeat(typval_T *argvars, typval_T *rettv)
8758{
8759 char_u *p;
8760 int n;
8761 int slen;
8762 int len;
8763 char_u *r;
8764 int i;
8765
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008766 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008767 if (argvars[0].v_type == VAR_LIST)
8768 {
8769 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8770 while (n-- > 0)
8771 if (list_extend(rettv->vval.v_list,
8772 argvars[0].vval.v_list, NULL) == FAIL)
8773 break;
8774 }
8775 else
8776 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008777 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008778 rettv->v_type = VAR_STRING;
8779 rettv->vval.v_string = NULL;
8780
8781 slen = (int)STRLEN(p);
8782 len = slen * n;
8783 if (len <= 0)
8784 return;
8785
8786 r = alloc(len + 1);
8787 if (r != NULL)
8788 {
8789 for (i = 0; i < n; i++)
8790 mch_memmove(r + i * slen, p, (size_t)slen);
8791 r[len] = NUL;
8792 }
8793
8794 rettv->vval.v_string = r;
8795 }
8796}
8797
8798/*
8799 * "resolve()" function
8800 */
8801 static void
8802f_resolve(typval_T *argvars, typval_T *rettv)
8803{
8804 char_u *p;
8805#ifdef HAVE_READLINK
8806 char_u *buf = NULL;
8807#endif
8808
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008809 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008810#ifdef FEAT_SHORTCUT
8811 {
8812 char_u *v = NULL;
8813
Bram Moolenaardce1e892019-02-10 23:18:53 +01008814 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008815 if (v != NULL)
8816 rettv->vval.v_string = v;
8817 else
8818 rettv->vval.v_string = vim_strsave(p);
8819 }
8820#else
8821# ifdef HAVE_READLINK
8822 {
8823 char_u *cpy;
8824 int len;
8825 char_u *remain = NULL;
8826 char_u *q;
8827 int is_relative_to_current = FALSE;
8828 int has_trailing_pathsep = FALSE;
8829 int limit = 100;
8830
8831 p = vim_strsave(p);
8832
8833 if (p[0] == '.' && (vim_ispathsep(p[1])
8834 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8835 is_relative_to_current = TRUE;
8836
8837 len = STRLEN(p);
8838 if (len > 0 && after_pathsep(p, p + len))
8839 {
8840 has_trailing_pathsep = TRUE;
8841 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8842 }
8843
8844 q = getnextcomp(p);
8845 if (*q != NUL)
8846 {
8847 /* Separate the first path component in "p", and keep the
8848 * remainder (beginning with the path separator). */
8849 remain = vim_strsave(q - 1);
8850 q[-1] = NUL;
8851 }
8852
8853 buf = alloc(MAXPATHL + 1);
8854 if (buf == NULL)
8855 goto fail;
8856
8857 for (;;)
8858 {
8859 for (;;)
8860 {
8861 len = readlink((char *)p, (char *)buf, MAXPATHL);
8862 if (len <= 0)
8863 break;
8864 buf[len] = NUL;
8865
8866 if (limit-- == 0)
8867 {
8868 vim_free(p);
8869 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008870 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008871 rettv->vval.v_string = NULL;
8872 goto fail;
8873 }
8874
8875 /* Ensure that the result will have a trailing path separator
8876 * if the argument has one. */
8877 if (remain == NULL && has_trailing_pathsep)
8878 add_pathsep(buf);
8879
8880 /* Separate the first path component in the link value and
8881 * concatenate the remainders. */
8882 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8883 if (*q != NUL)
8884 {
8885 if (remain == NULL)
8886 remain = vim_strsave(q - 1);
8887 else
8888 {
8889 cpy = concat_str(q - 1, remain);
8890 if (cpy != NULL)
8891 {
8892 vim_free(remain);
8893 remain = cpy;
8894 }
8895 }
8896 q[-1] = NUL;
8897 }
8898
8899 q = gettail(p);
8900 if (q > p && *q == NUL)
8901 {
8902 /* Ignore trailing path separator. */
8903 q[-1] = NUL;
8904 q = gettail(p);
8905 }
8906 if (q > p && !mch_isFullName(buf))
8907 {
8908 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02008909 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008910 if (cpy != NULL)
8911 {
8912 STRCPY(cpy, p);
8913 STRCPY(gettail(cpy), buf);
8914 vim_free(p);
8915 p = cpy;
8916 }
8917 }
8918 else
8919 {
8920 vim_free(p);
8921 p = vim_strsave(buf);
8922 }
8923 }
8924
8925 if (remain == NULL)
8926 break;
8927
8928 /* Append the first path component of "remain" to "p". */
8929 q = getnextcomp(remain + 1);
8930 len = q - remain - (*q != NUL);
8931 cpy = vim_strnsave(p, STRLEN(p) + len);
8932 if (cpy != NULL)
8933 {
8934 STRNCAT(cpy, remain, len);
8935 vim_free(p);
8936 p = cpy;
8937 }
8938 /* Shorten "remain". */
8939 if (*q != NUL)
8940 STRMOVE(remain, q - 1);
8941 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01008942 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008943 }
8944
8945 /* If the result is a relative path name, make it explicitly relative to
8946 * the current directory if and only if the argument had this form. */
8947 if (!vim_ispathsep(*p))
8948 {
8949 if (is_relative_to_current
8950 && *p != NUL
8951 && !(p[0] == '.'
8952 && (p[1] == NUL
8953 || vim_ispathsep(p[1])
8954 || (p[1] == '.'
8955 && (p[2] == NUL
8956 || vim_ispathsep(p[2]))))))
8957 {
8958 /* Prepend "./". */
8959 cpy = concat_str((char_u *)"./", p);
8960 if (cpy != NULL)
8961 {
8962 vim_free(p);
8963 p = cpy;
8964 }
8965 }
8966 else if (!is_relative_to_current)
8967 {
8968 /* Strip leading "./". */
8969 q = p;
8970 while (q[0] == '.' && vim_ispathsep(q[1]))
8971 q += 2;
8972 if (q > p)
8973 STRMOVE(p, p + 2);
8974 }
8975 }
8976
8977 /* Ensure that the result will have no trailing path separator
8978 * if the argument had none. But keep "/" or "//". */
8979 if (!has_trailing_pathsep)
8980 {
8981 q = p + STRLEN(p);
8982 if (after_pathsep(p, q))
8983 *gettail_sep(p) = NUL;
8984 }
8985
8986 rettv->vval.v_string = p;
8987 }
8988# else
8989 rettv->vval.v_string = vim_strsave(p);
8990# endif
8991#endif
8992
8993 simplify_filename(rettv->vval.v_string);
8994
8995#ifdef HAVE_READLINK
8996fail:
8997 vim_free(buf);
8998#endif
8999 rettv->v_type = VAR_STRING;
9000}
9001
9002/*
9003 * "reverse({list})" function
9004 */
9005 static void
9006f_reverse(typval_T *argvars, typval_T *rettv)
9007{
9008 list_T *l;
9009 listitem_T *li, *ni;
9010
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009011 if (argvars[0].v_type == VAR_BLOB)
9012 {
9013 blob_T *b = argvars[0].vval.v_blob;
9014 int i, len = blob_len(b);
9015
9016 for (i = 0; i < len / 2; i++)
9017 {
9018 int tmp = blob_get(b, i);
9019
9020 blob_set(b, i, blob_get(b, len - i - 1));
9021 blob_set(b, len - i - 1, tmp);
9022 }
9023 rettv_blob_set(rettv, b);
9024 return;
9025 }
9026
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009027 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009028 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009029 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009030 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009031 (char_u *)N_("reverse() argument"), TRUE))
9032 {
9033 li = l->lv_last;
9034 l->lv_first = l->lv_last = NULL;
9035 l->lv_len = 0;
9036 while (li != NULL)
9037 {
9038 ni = li->li_prev;
9039 list_append(l, li);
9040 li = ni;
9041 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009042 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009043 l->lv_idx = l->lv_len - l->lv_idx - 1;
9044 }
9045}
9046
9047#define SP_NOMOVE 0x01 /* don't move cursor */
9048#define SP_REPEAT 0x02 /* repeat to find outer pair */
9049#define SP_RETCOUNT 0x04 /* return matchcount */
9050#define SP_SETPCMARK 0x08 /* set previous context mark */
9051#define SP_START 0x10 /* accept match at start position */
9052#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9053#define SP_END 0x40 /* leave cursor at end of match */
9054#define SP_COLUMN 0x80 /* start at cursor column */
9055
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009056/*
9057 * Get flags for a search function.
9058 * Possibly sets "p_ws".
9059 * Returns BACKWARD, FORWARD or zero (for an error).
9060 */
9061 static int
9062get_search_arg(typval_T *varp, int *flagsp)
9063{
9064 int dir = FORWARD;
9065 char_u *flags;
9066 char_u nbuf[NUMBUFLEN];
9067 int mask;
9068
9069 if (varp->v_type != VAR_UNKNOWN)
9070 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009071 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009072 if (flags == NULL)
9073 return 0; /* type error; errmsg already given */
9074 while (*flags != NUL)
9075 {
9076 switch (*flags)
9077 {
9078 case 'b': dir = BACKWARD; break;
9079 case 'w': p_ws = TRUE; break;
9080 case 'W': p_ws = FALSE; break;
9081 default: mask = 0;
9082 if (flagsp != NULL)
9083 switch (*flags)
9084 {
9085 case 'c': mask = SP_START; break;
9086 case 'e': mask = SP_END; break;
9087 case 'm': mask = SP_RETCOUNT; break;
9088 case 'n': mask = SP_NOMOVE; break;
9089 case 'p': mask = SP_SUBPAT; break;
9090 case 'r': mask = SP_REPEAT; break;
9091 case 's': mask = SP_SETPCMARK; break;
9092 case 'z': mask = SP_COLUMN; break;
9093 }
9094 if (mask == 0)
9095 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009096 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009097 dir = 0;
9098 }
9099 else
9100 *flagsp |= mask;
9101 }
9102 if (dir == 0)
9103 break;
9104 ++flags;
9105 }
9106 }
9107 return dir;
9108}
9109
9110/*
9111 * Shared by search() and searchpos() functions.
9112 */
9113 static int
9114search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9115{
9116 int flags;
9117 char_u *pat;
9118 pos_T pos;
9119 pos_T save_cursor;
9120 int save_p_ws = p_ws;
9121 int dir;
9122 int retval = 0; /* default: FAIL */
9123 long lnum_stop = 0;
9124 proftime_T tm;
9125#ifdef FEAT_RELTIME
9126 long time_limit = 0;
9127#endif
9128 int options = SEARCH_KEEP;
9129 int subpatnum;
9130
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009131 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009132 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9133 if (dir == 0)
9134 goto theend;
9135 flags = *flagsp;
9136 if (flags & SP_START)
9137 options |= SEARCH_START;
9138 if (flags & SP_END)
9139 options |= SEARCH_END;
9140 if (flags & SP_COLUMN)
9141 options |= SEARCH_COL;
9142
9143 /* Optional arguments: line number to stop searching and timeout. */
9144 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9145 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009146 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009147 if (lnum_stop < 0)
9148 goto theend;
9149#ifdef FEAT_RELTIME
9150 if (argvars[3].v_type != VAR_UNKNOWN)
9151 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009152 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009153 if (time_limit < 0)
9154 goto theend;
9155 }
9156#endif
9157 }
9158
9159#ifdef FEAT_RELTIME
9160 /* Set the time limit, if there is one. */
9161 profile_setlimit(time_limit, &tm);
9162#endif
9163
9164 /*
9165 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9166 * Check to make sure only those flags are set.
9167 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9168 * flags cannot be set. Check for that condition also.
9169 */
9170 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9171 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9172 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009173 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009174 goto theend;
9175 }
9176
9177 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009178 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009179 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009180 if (subpatnum != FAIL)
9181 {
9182 if (flags & SP_SUBPAT)
9183 retval = subpatnum;
9184 else
9185 retval = pos.lnum;
9186 if (flags & SP_SETPCMARK)
9187 setpcmark();
9188 curwin->w_cursor = pos;
9189 if (match_pos != NULL)
9190 {
9191 /* Store the match cursor position */
9192 match_pos->lnum = pos.lnum;
9193 match_pos->col = pos.col + 1;
9194 }
9195 /* "/$" will put the cursor after the end of the line, may need to
9196 * correct that here */
9197 check_cursor();
9198 }
9199
9200 /* If 'n' flag is used: restore cursor position. */
9201 if (flags & SP_NOMOVE)
9202 curwin->w_cursor = save_cursor;
9203 else
9204 curwin->w_set_curswant = TRUE;
9205theend:
9206 p_ws = save_p_ws;
9207
9208 return retval;
9209}
9210
9211#ifdef FEAT_FLOAT
9212
9213/*
9214 * round() is not in C90, use ceil() or floor() instead.
9215 */
9216 float_T
9217vim_round(float_T f)
9218{
9219 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9220}
9221
9222/*
9223 * "round({float})" function
9224 */
9225 static void
9226f_round(typval_T *argvars, typval_T *rettv)
9227{
9228 float_T f = 0.0;
9229
9230 rettv->v_type = VAR_FLOAT;
9231 if (get_float_arg(argvars, &f) == OK)
9232 rettv->vval.v_float = vim_round(f);
9233 else
9234 rettv->vval.v_float = 0.0;
9235}
9236#endif
9237
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009238#ifdef FEAT_RUBY
9239/*
9240 * "rubyeval()" function
9241 */
9242 static void
9243f_rubyeval(typval_T *argvars, typval_T *rettv)
9244{
9245 char_u *str;
9246 char_u buf[NUMBUFLEN];
9247
9248 str = tv_get_string_buf(&argvars[0], buf);
9249 do_rubyeval(str, rettv);
9250}
9251#endif
9252
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009253/*
9254 * "screenattr()" function
9255 */
9256 static void
9257f_screenattr(typval_T *argvars, typval_T *rettv)
9258{
9259 int row;
9260 int col;
9261 int c;
9262
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009263 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9264 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009265 if (row < 0 || row >= screen_Rows
9266 || col < 0 || col >= screen_Columns)
9267 c = -1;
9268 else
9269 c = ScreenAttrs[LineOffset[row] + col];
9270 rettv->vval.v_number = c;
9271}
9272
9273/*
9274 * "screenchar()" function
9275 */
9276 static void
9277f_screenchar(typval_T *argvars, typval_T *rettv)
9278{
9279 int row;
9280 int col;
9281 int off;
9282 int c;
9283
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009284 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9285 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009286 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009287 c = -1;
9288 else
9289 {
9290 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009291 if (enc_utf8 && ScreenLinesUC[off] != 0)
9292 c = ScreenLinesUC[off];
9293 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009294 c = ScreenLines[off];
9295 }
9296 rettv->vval.v_number = c;
9297}
9298
9299/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009300 * "screenchars()" function
9301 */
9302 static void
9303f_screenchars(typval_T *argvars, typval_T *rettv)
9304{
9305 int row;
9306 int col;
9307 int off;
9308 int c;
9309 int i;
9310
9311 if (rettv_list_alloc(rettv) == FAIL)
9312 return;
9313 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9314 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9315 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9316 return;
9317
9318 off = LineOffset[row] + col;
9319 if (enc_utf8 && ScreenLinesUC[off] != 0)
9320 c = ScreenLinesUC[off];
9321 else
9322 c = ScreenLines[off];
9323 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9324
9325 if (enc_utf8)
9326
9327 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9328 list_append_number(rettv->vval.v_list,
9329 (varnumber_T)ScreenLinesC[i][off]);
9330}
9331
9332/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333 * "screencol()" function
9334 *
9335 * First column is 1 to be consistent with virtcol().
9336 */
9337 static void
9338f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9339{
9340 rettv->vval.v_number = screen_screencol() + 1;
9341}
9342
9343/*
9344 * "screenrow()" function
9345 */
9346 static void
9347f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9348{
9349 rettv->vval.v_number = screen_screenrow() + 1;
9350}
9351
9352/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009353 * "screenstring()" function
9354 */
9355 static void
9356f_screenstring(typval_T *argvars, typval_T *rettv)
9357{
9358 int row;
9359 int col;
9360 int off;
9361 int c;
9362 int i;
9363 char_u buf[MB_MAXBYTES + 1];
9364 int buflen = 0;
9365
9366 rettv->vval.v_string = NULL;
9367 rettv->v_type = VAR_STRING;
9368
9369 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9370 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9371 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9372 return;
9373
9374 off = LineOffset[row] + col;
9375 if (enc_utf8 && ScreenLinesUC[off] != 0)
9376 c = ScreenLinesUC[off];
9377 else
9378 c = ScreenLines[off];
9379 buflen += mb_char2bytes(c, buf);
9380
9381 if (enc_utf8)
9382 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9383 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9384
9385 buf[buflen] = NUL;
9386 rettv->vval.v_string = vim_strsave(buf);
9387}
9388
9389/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009390 * "search()" function
9391 */
9392 static void
9393f_search(typval_T *argvars, typval_T *rettv)
9394{
9395 int flags = 0;
9396
9397 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9398}
9399
9400/*
9401 * "searchdecl()" function
9402 */
9403 static void
9404f_searchdecl(typval_T *argvars, typval_T *rettv)
9405{
9406 int locally = 1;
9407 int thisblock = 0;
9408 int error = FALSE;
9409 char_u *name;
9410
9411 rettv->vval.v_number = 1; /* default: FAIL */
9412
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009413 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009414 if (argvars[1].v_type != VAR_UNKNOWN)
9415 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009416 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009417 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009418 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009419 }
9420 if (!error && name != NULL)
9421 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9422 locally, thisblock, SEARCH_KEEP) == FAIL;
9423}
9424
9425/*
9426 * Used by searchpair() and searchpairpos()
9427 */
9428 static int
9429searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9430{
9431 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009432 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009433 int save_p_ws = p_ws;
9434 int dir;
9435 int flags = 0;
9436 char_u nbuf1[NUMBUFLEN];
9437 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009438 int retval = 0; /* default: FAIL */
9439 long lnum_stop = 0;
9440 long time_limit = 0;
9441
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009442 /* Get the three pattern arguments: start, middle, end. Will result in an
9443 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009444 spat = tv_get_string_chk(&argvars[0]);
9445 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9446 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009447 if (spat == NULL || mpat == NULL || epat == NULL)
9448 goto theend; /* type error */
9449
9450 /* Handle the optional fourth argument: flags */
9451 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9452 if (dir == 0)
9453 goto theend;
9454
9455 /* Don't accept SP_END or SP_SUBPAT.
9456 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9457 */
9458 if ((flags & (SP_END | SP_SUBPAT)) != 0
9459 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9460 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009461 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009462 goto theend;
9463 }
9464
9465 /* Using 'r' implies 'W', otherwise it doesn't work. */
9466 if (flags & SP_REPEAT)
9467 p_ws = FALSE;
9468
9469 /* Optional fifth argument: skip expression */
9470 if (argvars[3].v_type == VAR_UNKNOWN
9471 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009472 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009473 else
9474 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009475 skip = &argvars[4];
9476 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9477 && skip->v_type != VAR_STRING)
9478 {
9479 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009480 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009481 goto theend;
9482 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009483 if (argvars[5].v_type != VAR_UNKNOWN)
9484 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009485 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009486 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009487 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009488 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009489 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009490 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009491#ifdef FEAT_RELTIME
9492 if (argvars[6].v_type != VAR_UNKNOWN)
9493 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009494 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009495 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009496 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009497 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009498 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009499 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009500 }
9501#endif
9502 }
9503 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009504
9505 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9506 match_pos, lnum_stop, time_limit);
9507
9508theend:
9509 p_ws = save_p_ws;
9510
9511 return retval;
9512}
9513
9514/*
9515 * "searchpair()" function
9516 */
9517 static void
9518f_searchpair(typval_T *argvars, typval_T *rettv)
9519{
9520 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9521}
9522
9523/*
9524 * "searchpairpos()" function
9525 */
9526 static void
9527f_searchpairpos(typval_T *argvars, typval_T *rettv)
9528{
9529 pos_T match_pos;
9530 int lnum = 0;
9531 int col = 0;
9532
9533 if (rettv_list_alloc(rettv) == FAIL)
9534 return;
9535
9536 if (searchpair_cmn(argvars, &match_pos) > 0)
9537 {
9538 lnum = match_pos.lnum;
9539 col = match_pos.col;
9540 }
9541
9542 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9543 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9544}
9545
9546/*
9547 * Search for a start/middle/end thing.
9548 * Used by searchpair(), see its documentation for the details.
9549 * Returns 0 or -1 for no match,
9550 */
9551 long
9552do_searchpair(
9553 char_u *spat, /* start pattern */
9554 char_u *mpat, /* middle pattern */
9555 char_u *epat, /* end pattern */
9556 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009557 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009558 int flags, /* SP_SETPCMARK and other SP_ values */
9559 pos_T *match_pos,
9560 linenr_T lnum_stop, /* stop at this line if not zero */
9561 long time_limit UNUSED) /* stop after this many msec */
9562{
9563 char_u *save_cpo;
9564 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9565 long retval = 0;
9566 pos_T pos;
9567 pos_T firstpos;
9568 pos_T foundpos;
9569 pos_T save_cursor;
9570 pos_T save_pos;
9571 int n;
9572 int r;
9573 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009574 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009575 int err;
9576 int options = SEARCH_KEEP;
9577 proftime_T tm;
9578
9579 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9580 save_cpo = p_cpo;
9581 p_cpo = empty_option;
9582
9583#ifdef FEAT_RELTIME
9584 /* Set the time limit, if there is one. */
9585 profile_setlimit(time_limit, &tm);
9586#endif
9587
9588 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9589 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009590 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9591 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009592 if (pat2 == NULL || pat3 == NULL)
9593 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009594 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009595 if (*mpat == NUL)
9596 STRCPY(pat3, pat2);
9597 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009598 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009599 spat, epat, mpat);
9600 if (flags & SP_START)
9601 options |= SEARCH_START;
9602
Bram Moolenaar48570482017-10-30 21:48:41 +01009603 if (skip != NULL)
9604 {
9605 /* Empty string means to not use the skip expression. */
9606 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9607 use_skip = skip->vval.v_string != NULL
9608 && *skip->vval.v_string != NUL;
9609 }
9610
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009611 save_cursor = curwin->w_cursor;
9612 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009613 CLEAR_POS(&firstpos);
9614 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009615 pat = pat3;
9616 for (;;)
9617 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009618 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009619 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009620 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009621 /* didn't find it or found the first match again: FAIL */
9622 break;
9623
9624 if (firstpos.lnum == 0)
9625 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009626 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009627 {
9628 /* Found the same position again. Can happen with a pattern that
9629 * has "\zs" at the end and searching backwards. Advance one
9630 * character and try again. */
9631 if (dir == BACKWARD)
9632 decl(&pos);
9633 else
9634 incl(&pos);
9635 }
9636 foundpos = pos;
9637
9638 /* clear the start flag to avoid getting stuck here */
9639 options &= ~SEARCH_START;
9640
9641 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009642 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009643 {
9644 save_pos = curwin->w_cursor;
9645 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009646 err = FALSE;
9647 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009648 curwin->w_cursor = save_pos;
9649 if (err)
9650 {
9651 /* Evaluating {skip} caused an error, break here. */
9652 curwin->w_cursor = save_cursor;
9653 retval = -1;
9654 break;
9655 }
9656 if (r)
9657 continue;
9658 }
9659
9660 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9661 {
9662 /* Found end when searching backwards or start when searching
9663 * forward: nested pair. */
9664 ++nest;
9665 pat = pat2; /* nested, don't search for middle */
9666 }
9667 else
9668 {
9669 /* Found end when searching forward or start when searching
9670 * backward: end of (nested) pair; or found middle in outer pair. */
9671 if (--nest == 1)
9672 pat = pat3; /* outer level, search for middle */
9673 }
9674
9675 if (nest == 0)
9676 {
9677 /* Found the match: return matchcount or line number. */
9678 if (flags & SP_RETCOUNT)
9679 ++retval;
9680 else
9681 retval = pos.lnum;
9682 if (flags & SP_SETPCMARK)
9683 setpcmark();
9684 curwin->w_cursor = pos;
9685 if (!(flags & SP_REPEAT))
9686 break;
9687 nest = 1; /* search for next unmatched */
9688 }
9689 }
9690
9691 if (match_pos != NULL)
9692 {
9693 /* Store the match cursor position */
9694 match_pos->lnum = curwin->w_cursor.lnum;
9695 match_pos->col = curwin->w_cursor.col + 1;
9696 }
9697
9698 /* If 'n' flag is used or search failed: restore cursor position. */
9699 if ((flags & SP_NOMOVE) || retval == 0)
9700 curwin->w_cursor = save_cursor;
9701
9702theend:
9703 vim_free(pat2);
9704 vim_free(pat3);
9705 if (p_cpo == empty_option)
9706 p_cpo = save_cpo;
9707 else
9708 /* Darn, evaluating the {skip} expression changed the value. */
9709 free_string_option(save_cpo);
9710
9711 return retval;
9712}
9713
9714/*
9715 * "searchpos()" function
9716 */
9717 static void
9718f_searchpos(typval_T *argvars, typval_T *rettv)
9719{
9720 pos_T match_pos;
9721 int lnum = 0;
9722 int col = 0;
9723 int n;
9724 int flags = 0;
9725
9726 if (rettv_list_alloc(rettv) == FAIL)
9727 return;
9728
9729 n = search_cmn(argvars, &match_pos, &flags);
9730 if (n > 0)
9731 {
9732 lnum = match_pos.lnum;
9733 col = match_pos.col;
9734 }
9735
9736 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9737 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9738 if (flags & SP_SUBPAT)
9739 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9740}
9741
9742 static void
9743f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9744{
9745#ifdef FEAT_CLIENTSERVER
9746 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009747 char_u *server = tv_get_string_chk(&argvars[0]);
9748 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009749
9750 rettv->vval.v_number = -1;
9751 if (server == NULL || reply == NULL)
9752 return;
9753 if (check_restricted() || check_secure())
9754 return;
9755# ifdef FEAT_X11
9756 if (check_connection() == FAIL)
9757 return;
9758# endif
9759
9760 if (serverSendReply(server, reply) < 0)
9761 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009762 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009763 return;
9764 }
9765 rettv->vval.v_number = 0;
9766#else
9767 rettv->vval.v_number = -1;
9768#endif
9769}
9770
9771 static void
9772f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9773{
9774 char_u *r = NULL;
9775
9776#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009777# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009778 r = serverGetVimNames();
9779# else
9780 make_connection();
9781 if (X_DISPLAY != NULL)
9782 r = serverGetVimNames(X_DISPLAY);
9783# endif
9784#endif
9785 rettv->v_type = VAR_STRING;
9786 rettv->vval.v_string = r;
9787}
9788
9789/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009790 * "setbufline()" function
9791 */
9792 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009793f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009794{
9795 linenr_T lnum;
9796 buf_T *buf;
9797
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009798 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009799 if (buf == NULL)
9800 rettv->vval.v_number = 1; /* FAIL */
9801 else
9802 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009803 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009804 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009805 }
9806}
9807
9808/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 * "setbufvar()" function
9810 */
9811 static void
9812f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9813{
9814 buf_T *buf;
9815 char_u *varname, *bufvarname;
9816 typval_T *varp;
9817 char_u nbuf[NUMBUFLEN];
9818
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009819 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009820 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009821 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
9822 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009823 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009824 varp = &argvars[2];
9825
9826 if (buf != NULL && varname != NULL && varp != NULL)
9827 {
9828 if (*varname == '&')
9829 {
9830 long numval;
9831 char_u *strval;
9832 int error = FALSE;
9833 aco_save_T aco;
9834
9835 /* set curbuf to be our buf, temporarily */
9836 aucmd_prepbuf(&aco, buf);
9837
9838 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009839 numval = (long)tv_get_number_chk(varp, &error);
9840 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009841 if (!error && strval != NULL)
9842 set_option_value(varname, numval, strval, OPT_LOCAL);
9843
9844 /* reset notion of buffer */
9845 aucmd_restbuf(&aco);
9846 }
9847 else
9848 {
9849 buf_T *save_curbuf = curbuf;
9850
Bram Moolenaar964b3742019-05-24 18:54:09 +02009851 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009852 if (bufvarname != NULL)
9853 {
9854 curbuf = buf;
9855 STRCPY(bufvarname, "b:");
9856 STRCPY(bufvarname + 2, varname);
9857 set_var(bufvarname, varp, TRUE);
9858 vim_free(bufvarname);
9859 curbuf = save_curbuf;
9860 }
9861 }
9862 }
9863}
9864
9865 static void
9866f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9867{
9868 dict_T *d;
9869 dictitem_T *di;
9870 char_u *csearch;
9871
9872 if (argvars[0].v_type != VAR_DICT)
9873 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009874 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009875 return;
9876 }
9877
9878 if ((d = argvars[0].vval.v_dict) != NULL)
9879 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009880 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009881 if (csearch != NULL)
9882 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009883 if (enc_utf8)
9884 {
9885 int pcc[MAX_MCO];
9886 int c = utfc_ptr2char(csearch, pcc);
9887
9888 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9889 }
9890 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009891 set_last_csearch(PTR2CHAR(csearch),
9892 csearch, MB_PTR2LEN(csearch));
9893 }
9894
9895 di = dict_find(d, (char_u *)"forward", -1);
9896 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009897 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009898 ? FORWARD : BACKWARD);
9899
9900 di = dict_find(d, (char_u *)"until", -1);
9901 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009902 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009903 }
9904}
9905
9906/*
9907 * "setcmdpos()" function
9908 */
9909 static void
9910f_setcmdpos(typval_T *argvars, typval_T *rettv)
9911{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009912 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009913
9914 if (pos >= 0)
9915 rettv->vval.v_number = set_cmdline_pos(pos);
9916}
9917
9918/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02009919 * "setenv()" function
9920 */
9921 static void
9922f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
9923{
9924 char_u namebuf[NUMBUFLEN];
9925 char_u valbuf[NUMBUFLEN];
9926 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
9927
9928 if (argvars[1].v_type == VAR_SPECIAL
9929 && argvars[1].vval.v_number == VVAL_NULL)
9930 vim_unsetenv(name);
9931 else
9932 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
9933}
9934
9935/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009936 * "setfperm({fname}, {mode})" function
9937 */
9938 static void
9939f_setfperm(typval_T *argvars, typval_T *rettv)
9940{
9941 char_u *fname;
9942 char_u modebuf[NUMBUFLEN];
9943 char_u *mode_str;
9944 int i;
9945 int mask;
9946 int mode = 0;
9947
9948 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009949 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009950 if (fname == NULL)
9951 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009952 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009953 if (mode_str == NULL)
9954 return;
9955 if (STRLEN(mode_str) != 9)
9956 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009957 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009958 return;
9959 }
9960
9961 mask = 1;
9962 for (i = 8; i >= 0; --i)
9963 {
9964 if (mode_str[i] != '-')
9965 mode |= mask;
9966 mask = mask << 1;
9967 }
9968 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9969}
9970
9971/*
9972 * "setline()" function
9973 */
9974 static void
9975f_setline(typval_T *argvars, typval_T *rettv)
9976{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009977 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009978
Bram Moolenaarca851592018-06-06 21:04:07 +02009979 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009980}
9981
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009982/*
9983 * Used by "setqflist()" and "setloclist()" functions
9984 */
9985 static void
9986set_qf_ll_list(
9987 win_T *wp UNUSED,
9988 typval_T *list_arg UNUSED,
9989 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +02009990 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009991 typval_T *rettv)
9992{
9993#ifdef FEAT_QUICKFIX
9994 static char *e_invact = N_("E927: Invalid action: '%s'");
9995 char_u *act;
9996 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009997 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009998#endif
9999
10000 rettv->vval.v_number = -1;
10001
10002#ifdef FEAT_QUICKFIX
10003 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010004 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010005 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010006 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010007 else
10008 {
10009 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010010 dict_T *d = NULL;
10011 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010012
10013 if (action_arg->v_type == VAR_STRING)
10014 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010015 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010016 if (act == NULL)
10017 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010018 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10019 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010020 action = *act;
10021 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010022 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010023 }
10024 else if (action_arg->v_type == VAR_UNKNOWN)
10025 action = ' ';
10026 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010027 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010028
Bram Moolenaard823fa92016-08-12 16:29:27 +020010029 if (action_arg->v_type != VAR_UNKNOWN
10030 && what_arg->v_type != VAR_UNKNOWN)
10031 {
10032 if (what_arg->v_type == VAR_DICT)
10033 d = what_arg->vval.v_dict;
10034 else
10035 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010036 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010037 valid_dict = FALSE;
10038 }
10039 }
10040
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010041 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010042 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010043 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10044 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010045 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010046 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010047 }
10048#endif
10049}
10050
10051/*
10052 * "setloclist()" function
10053 */
10054 static void
10055f_setloclist(typval_T *argvars, typval_T *rettv)
10056{
10057 win_T *win;
10058
10059 rettv->vval.v_number = -1;
10060
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010061 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010062 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010063 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010064}
10065
10066/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010067 * "setpos()" function
10068 */
10069 static void
10070f_setpos(typval_T *argvars, typval_T *rettv)
10071{
10072 pos_T pos;
10073 int fnum;
10074 char_u *name;
10075 colnr_T curswant = -1;
10076
10077 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010078 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010079 if (name != NULL)
10080 {
10081 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10082 {
10083 if (--pos.col < 0)
10084 pos.col = 0;
10085 if (name[0] == '.' && name[1] == NUL)
10086 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010087 /* set cursor; "fnum" is ignored */
10088 curwin->w_cursor = pos;
10089 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010090 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010091 curwin->w_curswant = curswant - 1;
10092 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010093 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010094 check_cursor();
10095 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010096 }
10097 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10098 {
10099 /* set mark */
10100 if (setmark_pos(name[1], &pos, fnum) == OK)
10101 rettv->vval.v_number = 0;
10102 }
10103 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010104 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010105 }
10106 }
10107}
10108
10109/*
10110 * "setqflist()" function
10111 */
10112 static void
10113f_setqflist(typval_T *argvars, typval_T *rettv)
10114{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010115 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010116}
10117
10118/*
10119 * "setreg()" function
10120 */
10121 static void
10122f_setreg(typval_T *argvars, typval_T *rettv)
10123{
10124 int regname;
10125 char_u *strregname;
10126 char_u *stropt;
10127 char_u *strval;
10128 int append;
10129 char_u yank_type;
10130 long block_len;
10131
10132 block_len = -1;
10133 yank_type = MAUTO;
10134 append = FALSE;
10135
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010136 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010137 rettv->vval.v_number = 1; /* FAIL is default */
10138
10139 if (strregname == NULL)
10140 return; /* type error; errmsg already given */
10141 regname = *strregname;
10142 if (regname == 0 || regname == '@')
10143 regname = '"';
10144
10145 if (argvars[2].v_type != VAR_UNKNOWN)
10146 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010147 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010148 if (stropt == NULL)
10149 return; /* type error */
10150 for (; *stropt != NUL; ++stropt)
10151 switch (*stropt)
10152 {
10153 case 'a': case 'A': /* append */
10154 append = TRUE;
10155 break;
10156 case 'v': case 'c': /* character-wise selection */
10157 yank_type = MCHAR;
10158 break;
10159 case 'V': case 'l': /* line-wise selection */
10160 yank_type = MLINE;
10161 break;
10162 case 'b': case Ctrl_V: /* block-wise selection */
10163 yank_type = MBLOCK;
10164 if (VIM_ISDIGIT(stropt[1]))
10165 {
10166 ++stropt;
10167 block_len = getdigits(&stropt) - 1;
10168 --stropt;
10169 }
10170 break;
10171 }
10172 }
10173
10174 if (argvars[1].v_type == VAR_LIST)
10175 {
10176 char_u **lstval;
10177 char_u **allocval;
10178 char_u buf[NUMBUFLEN];
10179 char_u **curval;
10180 char_u **curallocval;
10181 list_T *ll = argvars[1].vval.v_list;
10182 listitem_T *li;
10183 int len;
10184
10185 /* If the list is NULL handle like an empty list. */
10186 len = ll == NULL ? 0 : ll->lv_len;
10187
10188 /* First half: use for pointers to result lines; second half: use for
10189 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010190 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010191 if (lstval == NULL)
10192 return;
10193 curval = lstval;
10194 allocval = lstval + len + 2;
10195 curallocval = allocval;
10196
10197 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10198 li = li->li_next)
10199 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010200 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010201 if (strval == NULL)
10202 goto free_lstval;
10203 if (strval == buf)
10204 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010205 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010206 * overwrite the string. */
10207 strval = vim_strsave(buf);
10208 if (strval == NULL)
10209 goto free_lstval;
10210 *curallocval++ = strval;
10211 }
10212 *curval++ = strval;
10213 }
10214 *curval++ = NULL;
10215
10216 write_reg_contents_lst(regname, lstval, -1,
10217 append, yank_type, block_len);
10218free_lstval:
10219 while (curallocval > allocval)
10220 vim_free(*--curallocval);
10221 vim_free(lstval);
10222 }
10223 else
10224 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010225 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010226 if (strval == NULL)
10227 return;
10228 write_reg_contents_ex(regname, strval, -1,
10229 append, yank_type, block_len);
10230 }
10231 rettv->vval.v_number = 0;
10232}
10233
10234/*
10235 * "settabvar()" function
10236 */
10237 static void
10238f_settabvar(typval_T *argvars, typval_T *rettv)
10239{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010240 tabpage_T *save_curtab;
10241 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010242 char_u *varname, *tabvarname;
10243 typval_T *varp;
10244
10245 rettv->vval.v_number = 0;
10246
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010247 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010248 return;
10249
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010250 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10251 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010252 varp = &argvars[2];
10253
Bram Moolenaar4033c552017-09-16 20:54:51 +020010254 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010255 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010256 save_curtab = curtab;
10257 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010258
Bram Moolenaar964b3742019-05-24 18:54:09 +020010259 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010260 if (tabvarname != NULL)
10261 {
10262 STRCPY(tabvarname, "t:");
10263 STRCPY(tabvarname + 2, varname);
10264 set_var(tabvarname, varp, TRUE);
10265 vim_free(tabvarname);
10266 }
10267
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010268 /* Restore current tabpage */
10269 if (valid_tabpage(save_curtab))
10270 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010271 }
10272}
10273
10274/*
10275 * "settabwinvar()" function
10276 */
10277 static void
10278f_settabwinvar(typval_T *argvars, typval_T *rettv)
10279{
10280 setwinvar(argvars, rettv, 1);
10281}
10282
10283/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010284 * "settagstack()" function
10285 */
10286 static void
10287f_settagstack(typval_T *argvars, typval_T *rettv)
10288{
10289 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10290 win_T *wp;
10291 dict_T *d;
10292 int action = 'r';
10293
10294 rettv->vval.v_number = -1;
10295
10296 // first argument: window number or id
10297 wp = find_win_by_nr_or_id(&argvars[0]);
10298 if (wp == NULL)
10299 return;
10300
10301 // second argument: dict with items to set in the tag stack
10302 if (argvars[1].v_type != VAR_DICT)
10303 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010304 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010305 return;
10306 }
10307 d = argvars[1].vval.v_dict;
10308 if (d == NULL)
10309 return;
10310
10311 // third argument: action - 'a' for append and 'r' for replace.
10312 // default is to replace the stack.
10313 if (argvars[2].v_type == VAR_UNKNOWN)
10314 action = 'r';
10315 else if (argvars[2].v_type == VAR_STRING)
10316 {
10317 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010318 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010319 if (actstr == NULL)
10320 return;
10321 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10322 action = *actstr;
10323 else
10324 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010325 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010326 return;
10327 }
10328 }
10329 else
10330 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010331 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010332 return;
10333 }
10334
10335 if (set_tagstack(wp, d, action) == OK)
10336 rettv->vval.v_number = 0;
10337}
10338
10339/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010340 * "setwinvar()" function
10341 */
10342 static void
10343f_setwinvar(typval_T *argvars, typval_T *rettv)
10344{
10345 setwinvar(argvars, rettv, 0);
10346}
10347
10348#ifdef FEAT_CRYPT
10349/*
10350 * "sha256({string})" function
10351 */
10352 static void
10353f_sha256(typval_T *argvars, typval_T *rettv)
10354{
10355 char_u *p;
10356
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010357 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010358 rettv->vval.v_string = vim_strsave(
10359 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10360 rettv->v_type = VAR_STRING;
10361}
10362#endif /* FEAT_CRYPT */
10363
10364/*
10365 * "shellescape({string})" function
10366 */
10367 static void
10368f_shellescape(typval_T *argvars, typval_T *rettv)
10369{
Bram Moolenaar20615522017-06-05 18:46:26 +020010370 int do_special = non_zero_arg(&argvars[1]);
10371
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010372 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010373 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010374 rettv->v_type = VAR_STRING;
10375}
10376
10377/*
10378 * shiftwidth() function
10379 */
10380 static void
10381f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10382{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010383 rettv->vval.v_number = 0;
10384
10385 if (argvars[0].v_type != VAR_UNKNOWN)
10386 {
10387 long col;
10388
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010389 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010390 if (col < 0)
10391 return; // type error; errmsg already given
10392#ifdef FEAT_VARTABS
10393 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10394 return;
10395#endif
10396 }
10397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010398 rettv->vval.v_number = get_sw_value(curbuf);
10399}
10400
10401/*
10402 * "simplify()" function
10403 */
10404 static void
10405f_simplify(typval_T *argvars, typval_T *rettv)
10406{
10407 char_u *p;
10408
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010409 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010410 rettv->vval.v_string = vim_strsave(p);
10411 simplify_filename(rettv->vval.v_string); /* simplify in place */
10412 rettv->v_type = VAR_STRING;
10413}
10414
10415#ifdef FEAT_FLOAT
10416/*
10417 * "sin()" function
10418 */
10419 static void
10420f_sin(typval_T *argvars, typval_T *rettv)
10421{
10422 float_T f = 0.0;
10423
10424 rettv->v_type = VAR_FLOAT;
10425 if (get_float_arg(argvars, &f) == OK)
10426 rettv->vval.v_float = sin(f);
10427 else
10428 rettv->vval.v_float = 0.0;
10429}
10430
10431/*
10432 * "sinh()" function
10433 */
10434 static void
10435f_sinh(typval_T *argvars, typval_T *rettv)
10436{
10437 float_T f = 0.0;
10438
10439 rettv->v_type = VAR_FLOAT;
10440 if (get_float_arg(argvars, &f) == OK)
10441 rettv->vval.v_float = sinh(f);
10442 else
10443 rettv->vval.v_float = 0.0;
10444}
10445#endif
10446
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010447/*
10448 * "soundfold({word})" function
10449 */
10450 static void
10451f_soundfold(typval_T *argvars, typval_T *rettv)
10452{
10453 char_u *s;
10454
10455 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010456 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010457#ifdef FEAT_SPELL
10458 rettv->vval.v_string = eval_soundfold(s);
10459#else
10460 rettv->vval.v_string = vim_strsave(s);
10461#endif
10462}
10463
10464/*
10465 * "spellbadword()" function
10466 */
10467 static void
10468f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10469{
10470 char_u *word = (char_u *)"";
10471 hlf_T attr = HLF_COUNT;
10472 int len = 0;
10473
10474 if (rettv_list_alloc(rettv) == FAIL)
10475 return;
10476
10477#ifdef FEAT_SPELL
10478 if (argvars[0].v_type == VAR_UNKNOWN)
10479 {
10480 /* Find the start and length of the badly spelled word. */
10481 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10482 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010483 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010484 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010485 curwin->w_set_curswant = TRUE;
10486 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010487 }
10488 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10489 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010490 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010491 int capcol = -1;
10492
10493 if (str != NULL)
10494 {
10495 /* Check the argument for spelling. */
10496 while (*str != NUL)
10497 {
10498 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10499 if (attr != HLF_COUNT)
10500 {
10501 word = str;
10502 break;
10503 }
10504 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010505 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010506 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010507 }
10508 }
10509 }
10510#endif
10511
10512 list_append_string(rettv->vval.v_list, word, len);
10513 list_append_string(rettv->vval.v_list, (char_u *)(
10514 attr == HLF_SPB ? "bad" :
10515 attr == HLF_SPR ? "rare" :
10516 attr == HLF_SPL ? "local" :
10517 attr == HLF_SPC ? "caps" :
10518 ""), -1);
10519}
10520
10521/*
10522 * "spellsuggest()" function
10523 */
10524 static void
10525f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10526{
10527#ifdef FEAT_SPELL
10528 char_u *str;
10529 int typeerr = FALSE;
10530 int maxcount;
10531 garray_T ga;
10532 int i;
10533 listitem_T *li;
10534 int need_capital = FALSE;
10535#endif
10536
10537 if (rettv_list_alloc(rettv) == FAIL)
10538 return;
10539
10540#ifdef FEAT_SPELL
10541 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10542 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010543 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010544 if (argvars[1].v_type != VAR_UNKNOWN)
10545 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010546 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010547 if (maxcount <= 0)
10548 return;
10549 if (argvars[2].v_type != VAR_UNKNOWN)
10550 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010551 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010552 if (typeerr)
10553 return;
10554 }
10555 }
10556 else
10557 maxcount = 25;
10558
10559 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10560
10561 for (i = 0; i < ga.ga_len; ++i)
10562 {
10563 str = ((char_u **)ga.ga_data)[i];
10564
10565 li = listitem_alloc();
10566 if (li == NULL)
10567 vim_free(str);
10568 else
10569 {
10570 li->li_tv.v_type = VAR_STRING;
10571 li->li_tv.v_lock = 0;
10572 li->li_tv.vval.v_string = str;
10573 list_append(rettv->vval.v_list, li);
10574 }
10575 }
10576 ga_clear(&ga);
10577 }
10578#endif
10579}
10580
10581 static void
10582f_split(typval_T *argvars, typval_T *rettv)
10583{
10584 char_u *str;
10585 char_u *end;
10586 char_u *pat = NULL;
10587 regmatch_T regmatch;
10588 char_u patbuf[NUMBUFLEN];
10589 char_u *save_cpo;
10590 int match;
10591 colnr_T col = 0;
10592 int keepempty = FALSE;
10593 int typeerr = FALSE;
10594
10595 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10596 save_cpo = p_cpo;
10597 p_cpo = (char_u *)"";
10598
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010599 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010600 if (argvars[1].v_type != VAR_UNKNOWN)
10601 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010602 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010603 if (pat == NULL)
10604 typeerr = TRUE;
10605 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010606 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010607 }
10608 if (pat == NULL || *pat == NUL)
10609 pat = (char_u *)"[\\x01- ]\\+";
10610
10611 if (rettv_list_alloc(rettv) == FAIL)
10612 return;
10613 if (typeerr)
10614 return;
10615
10616 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10617 if (regmatch.regprog != NULL)
10618 {
10619 regmatch.rm_ic = FALSE;
10620 while (*str != NUL || keepempty)
10621 {
10622 if (*str == NUL)
10623 match = FALSE; /* empty item at the end */
10624 else
10625 match = vim_regexec_nl(&regmatch, str, col);
10626 if (match)
10627 end = regmatch.startp[0];
10628 else
10629 end = str + STRLEN(str);
10630 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10631 && *str != NUL && match && end < regmatch.endp[0]))
10632 {
10633 if (list_append_string(rettv->vval.v_list, str,
10634 (int)(end - str)) == FAIL)
10635 break;
10636 }
10637 if (!match)
10638 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010639 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010640 if (regmatch.endp[0] > str)
10641 col = 0;
10642 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010643 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010645 str = regmatch.endp[0];
10646 }
10647
10648 vim_regfree(regmatch.regprog);
10649 }
10650
10651 p_cpo = save_cpo;
10652}
10653
10654#ifdef FEAT_FLOAT
10655/*
10656 * "sqrt()" function
10657 */
10658 static void
10659f_sqrt(typval_T *argvars, typval_T *rettv)
10660{
10661 float_T f = 0.0;
10662
10663 rettv->v_type = VAR_FLOAT;
10664 if (get_float_arg(argvars, &f) == OK)
10665 rettv->vval.v_float = sqrt(f);
10666 else
10667 rettv->vval.v_float = 0.0;
10668}
10669
10670/*
10671 * "str2float()" function
10672 */
10673 static void
10674f_str2float(typval_T *argvars, typval_T *rettv)
10675{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010676 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010677 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010678
Bram Moolenaar08243d22017-01-10 16:12:29 +010010679 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010680 p = skipwhite(p + 1);
10681 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010682 if (isneg)
10683 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010684 rettv->v_type = VAR_FLOAT;
10685}
10686#endif
10687
10688/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010689 * "str2list()" function
10690 */
10691 static void
10692f_str2list(typval_T *argvars, typval_T *rettv)
10693{
10694 char_u *p;
10695 int utf8 = FALSE;
10696
10697 if (rettv_list_alloc(rettv) == FAIL)
10698 return;
10699
10700 if (argvars[1].v_type != VAR_UNKNOWN)
10701 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10702
10703 p = tv_get_string(&argvars[0]);
10704
10705 if (has_mbyte || utf8)
10706 {
10707 int (*ptr2len)(char_u *);
10708 int (*ptr2char)(char_u *);
10709
10710 if (utf8 || enc_utf8)
10711 {
10712 ptr2len = utf_ptr2len;
10713 ptr2char = utf_ptr2char;
10714 }
10715 else
10716 {
10717 ptr2len = mb_ptr2len;
10718 ptr2char = mb_ptr2char;
10719 }
10720
10721 for ( ; *p != NUL; p += (*ptr2len)(p))
10722 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10723 }
10724 else
10725 for ( ; *p != NUL; ++p)
10726 list_append_number(rettv->vval.v_list, *p);
10727}
10728
10729/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010730 * "str2nr()" function
10731 */
10732 static void
10733f_str2nr(typval_T *argvars, typval_T *rettv)
10734{
10735 int base = 10;
10736 char_u *p;
10737 varnumber_T n;
10738 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010739 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010740
10741 if (argvars[1].v_type != VAR_UNKNOWN)
10742 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010743 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010744 if (base != 2 && base != 8 && base != 10 && base != 16)
10745 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010746 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010747 return;
10748 }
10749 }
10750
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010751 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010752 isneg = (*p == '-');
10753 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010754 p = skipwhite(p + 1);
10755 switch (base)
10756 {
10757 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10758 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10759 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10760 default: what = 0;
10761 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010762 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10763 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010764 if (isneg)
10765 rettv->vval.v_number = -n;
10766 else
10767 rettv->vval.v_number = n;
10768
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010769}
10770
10771#ifdef HAVE_STRFTIME
10772/*
10773 * "strftime({format}[, {time}])" function
10774 */
10775 static void
10776f_strftime(typval_T *argvars, typval_T *rettv)
10777{
10778 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010779 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010780 struct tm *curtime;
10781 time_t seconds;
10782 char_u *p;
10783
10784 rettv->v_type = VAR_STRING;
10785
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010786 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010787 if (argvars[1].v_type == VAR_UNKNOWN)
10788 seconds = time(NULL);
10789 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010790 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010791 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010792 /* MSVC returns NULL for an invalid value of seconds. */
10793 if (curtime == NULL)
10794 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10795 else
10796 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010797 vimconv_T conv;
10798 char_u *enc;
10799
10800 conv.vc_type = CONV_NONE;
10801 enc = enc_locale();
10802 convert_setup(&conv, p_enc, enc);
10803 if (conv.vc_type != CONV_NONE)
10804 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010805 if (p != NULL)
10806 (void)strftime((char *)result_buf, sizeof(result_buf),
10807 (char *)p, curtime);
10808 else
10809 result_buf[0] = NUL;
10810
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010811 if (conv.vc_type != CONV_NONE)
10812 vim_free(p);
10813 convert_setup(&conv, enc, p_enc);
10814 if (conv.vc_type != CONV_NONE)
10815 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10816 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010817 rettv->vval.v_string = vim_strsave(result_buf);
10818
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010819 /* Release conversion descriptors */
10820 convert_setup(&conv, NULL, NULL);
10821 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010822 }
10823}
10824#endif
10825
10826/*
10827 * "strgetchar()" function
10828 */
10829 static void
10830f_strgetchar(typval_T *argvars, typval_T *rettv)
10831{
10832 char_u *str;
10833 int len;
10834 int error = FALSE;
10835 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010010836 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010837
10838 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010839 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010840 if (str == NULL)
10841 return;
10842 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010843 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010844 if (error)
10845 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010846
Bram Moolenaar13505972019-01-24 15:04:48 +010010847 while (charidx >= 0 && byteidx < len)
10848 {
10849 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010850 {
Bram Moolenaar13505972019-01-24 15:04:48 +010010851 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10852 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010853 }
Bram Moolenaar13505972019-01-24 15:04:48 +010010854 --charidx;
10855 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010856 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010857}
10858
10859/*
10860 * "stridx()" function
10861 */
10862 static void
10863f_stridx(typval_T *argvars, typval_T *rettv)
10864{
10865 char_u buf[NUMBUFLEN];
10866 char_u *needle;
10867 char_u *haystack;
10868 char_u *save_haystack;
10869 char_u *pos;
10870 int start_idx;
10871
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010872 needle = tv_get_string_chk(&argvars[1]);
10873 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010874 rettv->vval.v_number = -1;
10875 if (needle == NULL || haystack == NULL)
10876 return; /* type error; errmsg already given */
10877
10878 if (argvars[2].v_type != VAR_UNKNOWN)
10879 {
10880 int error = FALSE;
10881
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010882 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010883 if (error || start_idx >= (int)STRLEN(haystack))
10884 return;
10885 if (start_idx >= 0)
10886 haystack += start_idx;
10887 }
10888
10889 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10890 if (pos != NULL)
10891 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10892}
10893
10894/*
10895 * "string()" function
10896 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010010897 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010898f_string(typval_T *argvars, typval_T *rettv)
10899{
10900 char_u *tofree;
10901 char_u numbuf[NUMBUFLEN];
10902
10903 rettv->v_type = VAR_STRING;
10904 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10905 get_copyID());
10906 /* Make a copy if we have a value but it's not in allocated memory. */
10907 if (rettv->vval.v_string != NULL && tofree == NULL)
10908 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10909}
10910
10911/*
10912 * "strlen()" function
10913 */
10914 static void
10915f_strlen(typval_T *argvars, typval_T *rettv)
10916{
10917 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010918 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010919}
10920
10921/*
10922 * "strchars()" function
10923 */
10924 static void
10925f_strchars(typval_T *argvars, typval_T *rettv)
10926{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010927 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010928 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010929 varnumber_T len = 0;
10930 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010931
10932 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010933 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010934 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010935 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010936 else
10937 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010938 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10939 while (*s != NUL)
10940 {
10941 func_mb_ptr2char_adv(&s);
10942 ++len;
10943 }
10944 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010945 }
10946}
10947
10948/*
10949 * "strdisplaywidth()" function
10950 */
10951 static void
10952f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10953{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010954 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010955 int col = 0;
10956
10957 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010958 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010959
10960 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10961}
10962
10963/*
10964 * "strwidth()" function
10965 */
10966 static void
10967f_strwidth(typval_T *argvars, typval_T *rettv)
10968{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010969 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010970
Bram Moolenaar13505972019-01-24 15:04:48 +010010971 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010972}
10973
10974/*
10975 * "strcharpart()" function
10976 */
10977 static void
10978f_strcharpart(typval_T *argvars, typval_T *rettv)
10979{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010980 char_u *p;
10981 int nchar;
10982 int nbyte = 0;
10983 int charlen;
10984 int len = 0;
10985 int slen;
10986 int error = FALSE;
10987
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010988 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010989 slen = (int)STRLEN(p);
10990
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010991 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010992 if (!error)
10993 {
10994 if (nchar > 0)
10995 while (nchar > 0 && nbyte < slen)
10996 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010997 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010998 --nchar;
10999 }
11000 else
11001 nbyte = nchar;
11002 if (argvars[2].v_type != VAR_UNKNOWN)
11003 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011004 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011005 while (charlen > 0 && nbyte + len < slen)
11006 {
11007 int off = nbyte + len;
11008
11009 if (off < 0)
11010 len += 1;
11011 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011012 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011013 --charlen;
11014 }
11015 }
11016 else
11017 len = slen - nbyte; /* default: all bytes that are available. */
11018 }
11019
11020 /*
11021 * Only return the overlap between the specified part and the actual
11022 * string.
11023 */
11024 if (nbyte < 0)
11025 {
11026 len += nbyte;
11027 nbyte = 0;
11028 }
11029 else if (nbyte > slen)
11030 nbyte = slen;
11031 if (len < 0)
11032 len = 0;
11033 else if (nbyte + len > slen)
11034 len = slen - nbyte;
11035
11036 rettv->v_type = VAR_STRING;
11037 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038}
11039
11040/*
11041 * "strpart()" function
11042 */
11043 static void
11044f_strpart(typval_T *argvars, typval_T *rettv)
11045{
11046 char_u *p;
11047 int n;
11048 int len;
11049 int slen;
11050 int error = FALSE;
11051
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011052 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011053 slen = (int)STRLEN(p);
11054
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011055 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011056 if (error)
11057 len = 0;
11058 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011059 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011060 else
11061 len = slen - n; /* default len: all bytes that are available. */
11062
11063 /*
11064 * Only return the overlap between the specified part and the actual
11065 * string.
11066 */
11067 if (n < 0)
11068 {
11069 len += n;
11070 n = 0;
11071 }
11072 else if (n > slen)
11073 n = slen;
11074 if (len < 0)
11075 len = 0;
11076 else if (n + len > slen)
11077 len = slen - n;
11078
11079 rettv->v_type = VAR_STRING;
11080 rettv->vval.v_string = vim_strnsave(p + n, len);
11081}
11082
11083/*
11084 * "strridx()" function
11085 */
11086 static void
11087f_strridx(typval_T *argvars, typval_T *rettv)
11088{
11089 char_u buf[NUMBUFLEN];
11090 char_u *needle;
11091 char_u *haystack;
11092 char_u *rest;
11093 char_u *lastmatch = NULL;
11094 int haystack_len, end_idx;
11095
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011096 needle = tv_get_string_chk(&argvars[1]);
11097 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011098
11099 rettv->vval.v_number = -1;
11100 if (needle == NULL || haystack == NULL)
11101 return; /* type error; errmsg already given */
11102
11103 haystack_len = (int)STRLEN(haystack);
11104 if (argvars[2].v_type != VAR_UNKNOWN)
11105 {
11106 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011107 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011108 if (end_idx < 0)
11109 return; /* can never find a match */
11110 }
11111 else
11112 end_idx = haystack_len;
11113
11114 if (*needle == NUL)
11115 {
11116 /* Empty string matches past the end. */
11117 lastmatch = haystack + end_idx;
11118 }
11119 else
11120 {
11121 for (rest = haystack; *rest != '\0'; ++rest)
11122 {
11123 rest = (char_u *)strstr((char *)rest, (char *)needle);
11124 if (rest == NULL || rest > haystack + end_idx)
11125 break;
11126 lastmatch = rest;
11127 }
11128 }
11129
11130 if (lastmatch == NULL)
11131 rettv->vval.v_number = -1;
11132 else
11133 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11134}
11135
11136/*
11137 * "strtrans()" function
11138 */
11139 static void
11140f_strtrans(typval_T *argvars, typval_T *rettv)
11141{
11142 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011143 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011144}
11145
11146/*
11147 * "submatch()" function
11148 */
11149 static void
11150f_submatch(typval_T *argvars, typval_T *rettv)
11151{
11152 int error = FALSE;
11153 int no;
11154 int retList = 0;
11155
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011156 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011157 if (error)
11158 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011159 if (no < 0 || no >= NSUBEXP)
11160 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011161 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011162 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011163 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011164 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011165 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011166 if (error)
11167 return;
11168
11169 if (retList == 0)
11170 {
11171 rettv->v_type = VAR_STRING;
11172 rettv->vval.v_string = reg_submatch(no);
11173 }
11174 else
11175 {
11176 rettv->v_type = VAR_LIST;
11177 rettv->vval.v_list = reg_submatch_list(no);
11178 }
11179}
11180
11181/*
11182 * "substitute()" function
11183 */
11184 static void
11185f_substitute(typval_T *argvars, typval_T *rettv)
11186{
11187 char_u patbuf[NUMBUFLEN];
11188 char_u subbuf[NUMBUFLEN];
11189 char_u flagsbuf[NUMBUFLEN];
11190
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011191 char_u *str = tv_get_string_chk(&argvars[0]);
11192 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011193 char_u *sub = NULL;
11194 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011195 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011196
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011197 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11198 expr = &argvars[2];
11199 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011200 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011202 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011203 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11204 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011205 rettv->vval.v_string = NULL;
11206 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011207 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011208}
11209
11210/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011211 * "swapinfo(swap_filename)" function
11212 */
11213 static void
11214f_swapinfo(typval_T *argvars, typval_T *rettv)
11215{
11216 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011217 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011218}
11219
11220/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011221 * "swapname(expr)" function
11222 */
11223 static void
11224f_swapname(typval_T *argvars, typval_T *rettv)
11225{
11226 buf_T *buf;
11227
11228 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011229 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011230 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11231 || buf->b_ml.ml_mfp->mf_fname == NULL)
11232 rettv->vval.v_string = NULL;
11233 else
11234 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11235}
11236
11237/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011238 * "synID(lnum, col, trans)" function
11239 */
11240 static void
11241f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11242{
11243 int id = 0;
11244#ifdef FEAT_SYN_HL
11245 linenr_T lnum;
11246 colnr_T col;
11247 int trans;
11248 int transerr = FALSE;
11249
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011250 lnum = tv_get_lnum(argvars); /* -1 on type error */
11251 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11252 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011253
11254 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11255 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11256 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11257#endif
11258
11259 rettv->vval.v_number = id;
11260}
11261
11262/*
11263 * "synIDattr(id, what [, mode])" function
11264 */
11265 static void
11266f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11267{
11268 char_u *p = NULL;
11269#ifdef FEAT_SYN_HL
11270 int id;
11271 char_u *what;
11272 char_u *mode;
11273 char_u modebuf[NUMBUFLEN];
11274 int modec;
11275
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011276 id = (int)tv_get_number(&argvars[0]);
11277 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011278 if (argvars[2].v_type != VAR_UNKNOWN)
11279 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011280 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011281 modec = TOLOWER_ASC(mode[0]);
11282 if (modec != 't' && modec != 'c' && modec != 'g')
11283 modec = 0; /* replace invalid with current */
11284 }
11285 else
11286 {
11287#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11288 if (USE_24BIT)
11289 modec = 'g';
11290 else
11291#endif
11292 if (t_colors > 1)
11293 modec = 'c';
11294 else
11295 modec = 't';
11296 }
11297
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011298 switch (TOLOWER_ASC(what[0]))
11299 {
11300 case 'b':
11301 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11302 p = highlight_color(id, what, modec);
11303 else /* bold */
11304 p = highlight_has_attr(id, HL_BOLD, modec);
11305 break;
11306
11307 case 'f': /* fg[#] or font */
11308 p = highlight_color(id, what, modec);
11309 break;
11310
11311 case 'i':
11312 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11313 p = highlight_has_attr(id, HL_INVERSE, modec);
11314 else /* italic */
11315 p = highlight_has_attr(id, HL_ITALIC, modec);
11316 break;
11317
11318 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011319 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011320 break;
11321
11322 case 'r': /* reverse */
11323 p = highlight_has_attr(id, HL_INVERSE, modec);
11324 break;
11325
11326 case 's':
11327 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11328 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011329 /* strikeout */
11330 else if (TOLOWER_ASC(what[1]) == 't' &&
11331 TOLOWER_ASC(what[2]) == 'r')
11332 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011333 else /* standout */
11334 p = highlight_has_attr(id, HL_STANDOUT, modec);
11335 break;
11336
11337 case 'u':
11338 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11339 /* underline */
11340 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11341 else
11342 /* undercurl */
11343 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11344 break;
11345 }
11346
11347 if (p != NULL)
11348 p = vim_strsave(p);
11349#endif
11350 rettv->v_type = VAR_STRING;
11351 rettv->vval.v_string = p;
11352}
11353
11354/*
11355 * "synIDtrans(id)" function
11356 */
11357 static void
11358f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11359{
11360 int id;
11361
11362#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011363 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011364
11365 if (id > 0)
11366 id = syn_get_final_id(id);
11367 else
11368#endif
11369 id = 0;
11370
11371 rettv->vval.v_number = id;
11372}
11373
11374/*
11375 * "synconcealed(lnum, col)" function
11376 */
11377 static void
11378f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11379{
11380#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11381 linenr_T lnum;
11382 colnr_T col;
11383 int syntax_flags = 0;
11384 int cchar;
11385 int matchid = 0;
11386 char_u str[NUMBUFLEN];
11387#endif
11388
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011389 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011390
11391#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011392 lnum = tv_get_lnum(argvars); /* -1 on type error */
11393 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011394
11395 vim_memset(str, NUL, sizeof(str));
11396
11397 if (rettv_list_alloc(rettv) != FAIL)
11398 {
11399 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11400 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11401 && curwin->w_p_cole > 0)
11402 {
11403 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11404 syntax_flags = get_syntax_info(&matchid);
11405
11406 /* get the conceal character */
11407 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11408 {
11409 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011410 if (cchar == NUL && curwin->w_p_cole == 1)
11411 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011412 if (cchar != NUL)
11413 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011414 if (has_mbyte)
11415 (*mb_char2bytes)(cchar, str);
11416 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011417 str[0] = cchar;
11418 }
11419 }
11420 }
11421
11422 list_append_number(rettv->vval.v_list,
11423 (syntax_flags & HL_CONCEAL) != 0);
11424 /* -1 to auto-determine strlen */
11425 list_append_string(rettv->vval.v_list, str, -1);
11426 list_append_number(rettv->vval.v_list, matchid);
11427 }
11428#endif
11429}
11430
11431/*
11432 * "synstack(lnum, col)" function
11433 */
11434 static void
11435f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11436{
11437#ifdef FEAT_SYN_HL
11438 linenr_T lnum;
11439 colnr_T col;
11440 int i;
11441 int id;
11442#endif
11443
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011444 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011445
11446#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011447 lnum = tv_get_lnum(argvars); /* -1 on type error */
11448 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011449
11450 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11451 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11452 && rettv_list_alloc(rettv) != FAIL)
11453 {
11454 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11455 for (i = 0; ; ++i)
11456 {
11457 id = syn_get_stack_item(i);
11458 if (id < 0)
11459 break;
11460 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11461 break;
11462 }
11463 }
11464#endif
11465}
11466
11467 static void
11468get_cmd_output_as_rettv(
11469 typval_T *argvars,
11470 typval_T *rettv,
11471 int retlist)
11472{
11473 char_u *res = NULL;
11474 char_u *p;
11475 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011476 int err = FALSE;
11477 FILE *fd;
11478 list_T *list = NULL;
11479 int flags = SHELL_SILENT;
11480
11481 rettv->v_type = VAR_STRING;
11482 rettv->vval.v_string = NULL;
11483 if (check_restricted() || check_secure())
11484 goto errret;
11485
11486 if (argvars[1].v_type != VAR_UNKNOWN)
11487 {
11488 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011489 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011490 * command.
11491 */
11492 if ((infile = vim_tempname('i', TRUE)) == NULL)
11493 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011494 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011495 goto errret;
11496 }
11497
11498 fd = mch_fopen((char *)infile, WRITEBIN);
11499 if (fd == NULL)
11500 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011501 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011502 goto errret;
11503 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011504 if (argvars[1].v_type == VAR_NUMBER)
11505 {
11506 linenr_T lnum;
11507 buf_T *buf;
11508
11509 buf = buflist_findnr(argvars[1].vval.v_number);
11510 if (buf == NULL)
11511 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011512 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011513 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011514 goto errret;
11515 }
11516
11517 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11518 {
11519 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11520 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11521 {
11522 err = TRUE;
11523 break;
11524 }
11525 if (putc(NL, fd) == EOF)
11526 {
11527 err = TRUE;
11528 break;
11529 }
11530 }
11531 }
11532 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011533 {
11534 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11535 err = TRUE;
11536 }
11537 else
11538 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011539 size_t len;
11540 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011541
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011542 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011543 if (p == NULL)
11544 {
11545 fclose(fd);
11546 goto errret; /* type error; errmsg already given */
11547 }
11548 len = STRLEN(p);
11549 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11550 err = TRUE;
11551 }
11552 if (fclose(fd) != 0)
11553 err = TRUE;
11554 if (err)
11555 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011556 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011557 goto errret;
11558 }
11559 }
11560
11561 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11562 * echoes typeahead, that messes up the display. */
11563 if (!msg_silent)
11564 flags += SHELL_COOKED;
11565
11566 if (retlist)
11567 {
11568 int len;
11569 listitem_T *li;
11570 char_u *s = NULL;
11571 char_u *start;
11572 char_u *end;
11573 int i;
11574
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011575 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011576 if (res == NULL)
11577 goto errret;
11578
11579 list = list_alloc();
11580 if (list == NULL)
11581 goto errret;
11582
11583 for (i = 0; i < len; ++i)
11584 {
11585 start = res + i;
11586 while (i < len && res[i] != NL)
11587 ++i;
11588 end = res + i;
11589
Bram Moolenaar964b3742019-05-24 18:54:09 +020011590 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011591 if (s == NULL)
11592 goto errret;
11593
11594 for (p = s; start < end; ++p, ++start)
11595 *p = *start == NUL ? NL : *start;
11596 *p = NUL;
11597
11598 li = listitem_alloc();
11599 if (li == NULL)
11600 {
11601 vim_free(s);
11602 goto errret;
11603 }
11604 li->li_tv.v_type = VAR_STRING;
11605 li->li_tv.v_lock = 0;
11606 li->li_tv.vval.v_string = s;
11607 list_append(list, li);
11608 }
11609
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011610 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011611 list = NULL;
11612 }
11613 else
11614 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011615 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011616#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011617 /* translate <CR><NL> into <NL> */
11618 if (res != NULL)
11619 {
11620 char_u *s, *d;
11621
11622 d = res;
11623 for (s = res; *s; ++s)
11624 {
11625 if (s[0] == CAR && s[1] == NL)
11626 ++s;
11627 *d++ = *s;
11628 }
11629 *d = NUL;
11630 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011631#endif
11632 rettv->vval.v_string = res;
11633 res = NULL;
11634 }
11635
11636errret:
11637 if (infile != NULL)
11638 {
11639 mch_remove(infile);
11640 vim_free(infile);
11641 }
11642 if (res != NULL)
11643 vim_free(res);
11644 if (list != NULL)
11645 list_free(list);
11646}
11647
11648/*
11649 * "system()" function
11650 */
11651 static void
11652f_system(typval_T *argvars, typval_T *rettv)
11653{
11654 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11655}
11656
11657/*
11658 * "systemlist()" function
11659 */
11660 static void
11661f_systemlist(typval_T *argvars, typval_T *rettv)
11662{
11663 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11664}
11665
11666/*
11667 * "tabpagebuflist()" function
11668 */
11669 static void
11670f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11671{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011672 tabpage_T *tp;
11673 win_T *wp = NULL;
11674
11675 if (argvars[0].v_type == VAR_UNKNOWN)
11676 wp = firstwin;
11677 else
11678 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011679 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011680 if (tp != NULL)
11681 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11682 }
11683 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11684 {
11685 for (; wp != NULL; wp = wp->w_next)
11686 if (list_append_number(rettv->vval.v_list,
11687 wp->w_buffer->b_fnum) == FAIL)
11688 break;
11689 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011690}
11691
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011692/*
11693 * "tabpagenr()" function
11694 */
11695 static void
11696f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11697{
11698 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011699 char_u *arg;
11700
11701 if (argvars[0].v_type != VAR_UNKNOWN)
11702 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011703 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011704 nr = 0;
11705 if (arg != NULL)
11706 {
11707 if (STRCMP(arg, "$") == 0)
11708 nr = tabpage_index(NULL) - 1;
11709 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011710 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011711 }
11712 }
11713 else
11714 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011715 rettv->vval.v_number = nr;
11716}
11717
11718
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011719/*
11720 * Common code for tabpagewinnr() and winnr().
11721 */
11722 static int
11723get_winnr(tabpage_T *tp, typval_T *argvar)
11724{
11725 win_T *twin;
11726 int nr = 1;
11727 win_T *wp;
11728 char_u *arg;
11729
11730 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11731 if (argvar->v_type != VAR_UNKNOWN)
11732 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011733 int invalid_arg = FALSE;
11734
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011735 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011736 if (arg == NULL)
11737 nr = 0; /* type error; errmsg already given */
11738 else if (STRCMP(arg, "$") == 0)
11739 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11740 else if (STRCMP(arg, "#") == 0)
11741 {
11742 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11743 if (twin == NULL)
11744 nr = 0;
11745 }
11746 else
11747 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011748 long count;
11749 char_u *endp;
11750
11751 // Extract the window count (if specified). e.g. winnr('3j')
11752 count = strtol((char *)arg, (char **)&endp, 10);
11753 if (count <= 0)
11754 count = 1; // if count is not specified, default to 1
11755 if (endp != NULL && *endp != '\0')
11756 {
11757 if (STRCMP(endp, "j") == 0)
11758 twin = win_vert_neighbor(tp, twin, FALSE, count);
11759 else if (STRCMP(endp, "k") == 0)
11760 twin = win_vert_neighbor(tp, twin, TRUE, count);
11761 else if (STRCMP(endp, "h") == 0)
11762 twin = win_horz_neighbor(tp, twin, TRUE, count);
11763 else if (STRCMP(endp, "l") == 0)
11764 twin = win_horz_neighbor(tp, twin, FALSE, count);
11765 else
11766 invalid_arg = TRUE;
11767 }
11768 else
11769 invalid_arg = TRUE;
11770 }
11771
11772 if (invalid_arg)
11773 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011774 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011775 nr = 0;
11776 }
11777 }
11778
11779 if (nr > 0)
11780 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11781 wp != twin; wp = wp->w_next)
11782 {
11783 if (wp == NULL)
11784 {
11785 /* didn't find it in this tabpage */
11786 nr = 0;
11787 break;
11788 }
11789 ++nr;
11790 }
11791 return nr;
11792}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011793
11794/*
11795 * "tabpagewinnr()" function
11796 */
11797 static void
11798f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11799{
11800 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011801 tabpage_T *tp;
11802
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011803 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011804 if (tp == NULL)
11805 nr = 0;
11806 else
11807 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011808 rettv->vval.v_number = nr;
11809}
11810
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011811/*
11812 * "tagfiles()" function
11813 */
11814 static void
11815f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11816{
11817 char_u *fname;
11818 tagname_T tn;
11819 int first;
11820
11821 if (rettv_list_alloc(rettv) == FAIL)
11822 return;
11823 fname = alloc(MAXPATHL);
11824 if (fname == NULL)
11825 return;
11826
11827 for (first = TRUE; ; first = FALSE)
11828 if (get_tagfname(&tn, first, fname) == FAIL
11829 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11830 break;
11831 tagname_free(&tn);
11832 vim_free(fname);
11833}
11834
11835/*
11836 * "taglist()" function
11837 */
11838 static void
11839f_taglist(typval_T *argvars, typval_T *rettv)
11840{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011841 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011842 char_u *tag_pattern;
11843
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011844 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011845
11846 rettv->vval.v_number = FALSE;
11847 if (*tag_pattern == NUL)
11848 return;
11849
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011850 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011851 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011852 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011853 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011854}
11855
11856/*
11857 * "tempname()" function
11858 */
11859 static void
11860f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11861{
11862 static int x = 'A';
11863
11864 rettv->v_type = VAR_STRING;
11865 rettv->vval.v_string = vim_tempname(x, FALSE);
11866
11867 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11868 * names. Skip 'I' and 'O', they are used for shell redirection. */
11869 do
11870 {
11871 if (x == 'Z')
11872 x = '0';
11873 else if (x == '9')
11874 x = 'A';
11875 else
11876 {
11877#ifdef EBCDIC
11878 if (x == 'I')
11879 x = 'J';
11880 else if (x == 'R')
11881 x = 'S';
11882 else
11883#endif
11884 ++x;
11885 }
11886 } while (x == 'I' || x == 'O');
11887}
11888
11889#ifdef FEAT_FLOAT
11890/*
11891 * "tan()" function
11892 */
11893 static void
11894f_tan(typval_T *argvars, typval_T *rettv)
11895{
11896 float_T f = 0.0;
11897
11898 rettv->v_type = VAR_FLOAT;
11899 if (get_float_arg(argvars, &f) == OK)
11900 rettv->vval.v_float = tan(f);
11901 else
11902 rettv->vval.v_float = 0.0;
11903}
11904
11905/*
11906 * "tanh()" function
11907 */
11908 static void
11909f_tanh(typval_T *argvars, typval_T *rettv)
11910{
11911 float_T f = 0.0;
11912
11913 rettv->v_type = VAR_FLOAT;
11914 if (get_float_arg(argvars, &f) == OK)
11915 rettv->vval.v_float = tanh(f);
11916 else
11917 rettv->vval.v_float = 0.0;
11918}
11919#endif
11920
11921/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011922 * Get a callback from "arg". It can be a Funcref or a function name.
11923 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011924 * "cb_name" is not allocated.
11925 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011926 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011927 callback_T
11928get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011929{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011930 callback_T res;
11931
11932 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011933 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11934 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011935 res.cb_partial = arg->vval.v_partial;
11936 ++res.cb_partial->pt_refcount;
11937 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011938 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011939 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011940 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011941 res.cb_partial = NULL;
11942 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
11943 {
11944 // Note that we don't make a copy of the string.
11945 res.cb_name = arg->vval.v_string;
11946 func_ref(res.cb_name);
11947 }
11948 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11949 {
11950 res.cb_name = (char_u *)"";
11951 }
11952 else
11953 {
11954 emsg(_("E921: Invalid callback argument"));
11955 res.cb_name = NULL;
11956 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011957 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011958 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011959}
11960
11961/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011962 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011963 */
11964 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011965put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011966{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011967 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011968 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011969 tv->v_type = VAR_PARTIAL;
11970 tv->vval.v_partial = cb->cb_partial;
11971 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011972 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011973 else
11974 {
11975 tv->v_type = VAR_FUNC;
11976 tv->vval.v_string = vim_strsave(cb->cb_name);
11977 func_ref(cb->cb_name);
11978 }
11979}
11980
11981/*
11982 * Make a copy of "src" into "dest", allocating the function name if needed,
11983 * without incrementing the refcount.
11984 */
11985 void
11986set_callback(callback_T *dest, callback_T *src)
11987{
11988 if (src->cb_partial == NULL)
11989 {
11990 // just a function name, make a copy
11991 dest->cb_name = vim_strsave(src->cb_name);
11992 dest->cb_free_name = TRUE;
11993 }
11994 else
11995 {
11996 // cb_name is a pointer into cb_partial
11997 dest->cb_name = src->cb_name;
11998 dest->cb_free_name = FALSE;
11999 }
12000 dest->cb_partial = src->cb_partial;
12001}
12002
12003/*
12004 * Unref/free "callback" returned by get_callback() or set_callback().
12005 */
12006 void
12007free_callback(callback_T *callback)
12008{
12009 if (callback->cb_partial != NULL)
12010 {
12011 partial_unref(callback->cb_partial);
12012 callback->cb_partial = NULL;
12013 }
12014 else if (callback->cb_name != NULL)
12015 func_unref(callback->cb_name);
12016 if (callback->cb_free_name)
12017 {
12018 vim_free(callback->cb_name);
12019 callback->cb_free_name = FALSE;
12020 }
12021 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012022}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012023
12024#ifdef FEAT_TIMERS
12025/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012026 * "timer_info([timer])" function
12027 */
12028 static void
12029f_timer_info(typval_T *argvars, typval_T *rettv)
12030{
12031 timer_T *timer = NULL;
12032
12033 if (rettv_list_alloc(rettv) != OK)
12034 return;
12035 if (argvars[0].v_type != VAR_UNKNOWN)
12036 {
12037 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012038 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012039 else
12040 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012041 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012042 if (timer != NULL)
12043 add_timer_info(rettv, timer);
12044 }
12045 }
12046 else
12047 add_timer_info_all(rettv);
12048}
12049
12050/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012051 * "timer_pause(timer, paused)" function
12052 */
12053 static void
12054f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12055{
12056 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012057 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012058
12059 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012060 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012061 else
12062 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012063 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012064 if (timer != NULL)
12065 timer->tr_paused = paused;
12066 }
12067}
12068
12069/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012070 * "timer_start(time, callback [, options])" function
12071 */
12072 static void
12073f_timer_start(typval_T *argvars, typval_T *rettv)
12074{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012075 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012076 timer_T *timer;
12077 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012078 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012079 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012080
Bram Moolenaar75537a92016-09-05 22:45:28 +020012081 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012082 if (check_secure())
12083 return;
12084 if (argvars[2].v_type != VAR_UNKNOWN)
12085 {
12086 if (argvars[2].v_type != VAR_DICT
12087 || (dict = argvars[2].vval.v_dict) == NULL)
12088 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012089 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012090 return;
12091 }
12092 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012093 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012094 }
12095
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012096 callback = get_callback(&argvars[1]);
12097 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012098 return;
12099
12100 timer = create_timer(msec, repeat);
12101 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012102 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012103 else
12104 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012105 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012106 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012107 }
12108}
12109
12110/*
12111 * "timer_stop(timer)" function
12112 */
12113 static void
12114f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12115{
12116 timer_T *timer;
12117
12118 if (argvars[0].v_type != VAR_NUMBER)
12119 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012120 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012121 return;
12122 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012123 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012124 if (timer != NULL)
12125 stop_timer(timer);
12126}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012127
12128/*
12129 * "timer_stopall()" function
12130 */
12131 static void
12132f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12133{
12134 stop_all_timers();
12135}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012136#endif
12137
12138/*
12139 * "tolower(string)" function
12140 */
12141 static void
12142f_tolower(typval_T *argvars, typval_T *rettv)
12143{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012144 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012145 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012146}
12147
12148/*
12149 * "toupper(string)" function
12150 */
12151 static void
12152f_toupper(typval_T *argvars, typval_T *rettv)
12153{
12154 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012155 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012156}
12157
12158/*
12159 * "tr(string, fromstr, tostr)" function
12160 */
12161 static void
12162f_tr(typval_T *argvars, typval_T *rettv)
12163{
12164 char_u *in_str;
12165 char_u *fromstr;
12166 char_u *tostr;
12167 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012168 int inlen;
12169 int fromlen;
12170 int tolen;
12171 int idx;
12172 char_u *cpstr;
12173 int cplen;
12174 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012175 char_u buf[NUMBUFLEN];
12176 char_u buf2[NUMBUFLEN];
12177 garray_T ga;
12178
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012179 in_str = tv_get_string(&argvars[0]);
12180 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12181 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012182
12183 /* Default return value: empty string. */
12184 rettv->v_type = VAR_STRING;
12185 rettv->vval.v_string = NULL;
12186 if (fromstr == NULL || tostr == NULL)
12187 return; /* type error; errmsg already given */
12188 ga_init2(&ga, (int)sizeof(char), 80);
12189
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012190 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012191 /* not multi-byte: fromstr and tostr must be the same length */
12192 if (STRLEN(fromstr) != STRLEN(tostr))
12193 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012194error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012195 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012196 ga_clear(&ga);
12197 return;
12198 }
12199
12200 /* fromstr and tostr have to contain the same number of chars */
12201 while (*in_str != NUL)
12202 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012203 if (has_mbyte)
12204 {
12205 inlen = (*mb_ptr2len)(in_str);
12206 cpstr = in_str;
12207 cplen = inlen;
12208 idx = 0;
12209 for (p = fromstr; *p != NUL; p += fromlen)
12210 {
12211 fromlen = (*mb_ptr2len)(p);
12212 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12213 {
12214 for (p = tostr; *p != NUL; p += tolen)
12215 {
12216 tolen = (*mb_ptr2len)(p);
12217 if (idx-- == 0)
12218 {
12219 cplen = tolen;
12220 cpstr = p;
12221 break;
12222 }
12223 }
12224 if (*p == NUL) /* tostr is shorter than fromstr */
12225 goto error;
12226 break;
12227 }
12228 ++idx;
12229 }
12230
12231 if (first && cpstr == in_str)
12232 {
12233 /* Check that fromstr and tostr have the same number of
12234 * (multi-byte) characters. Done only once when a character
12235 * of in_str doesn't appear in fromstr. */
12236 first = FALSE;
12237 for (p = tostr; *p != NUL; p += tolen)
12238 {
12239 tolen = (*mb_ptr2len)(p);
12240 --idx;
12241 }
12242 if (idx != 0)
12243 goto error;
12244 }
12245
12246 (void)ga_grow(&ga, cplen);
12247 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12248 ga.ga_len += cplen;
12249
12250 in_str += inlen;
12251 }
12252 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012253 {
12254 /* When not using multi-byte chars we can do it faster. */
12255 p = vim_strchr(fromstr, *in_str);
12256 if (p != NULL)
12257 ga_append(&ga, tostr[p - fromstr]);
12258 else
12259 ga_append(&ga, *in_str);
12260 ++in_str;
12261 }
12262 }
12263
12264 /* add a terminating NUL */
12265 (void)ga_grow(&ga, 1);
12266 ga_append(&ga, NUL);
12267
12268 rettv->vval.v_string = ga.ga_data;
12269}
12270
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012271/*
12272 * "trim({expr})" function
12273 */
12274 static void
12275f_trim(typval_T *argvars, typval_T *rettv)
12276{
12277 char_u buf1[NUMBUFLEN];
12278 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012279 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012280 char_u *mask = NULL;
12281 char_u *tail;
12282 char_u *prev;
12283 char_u *p;
12284 int c1;
12285
12286 rettv->v_type = VAR_STRING;
12287 if (head == NULL)
12288 {
12289 rettv->vval.v_string = NULL;
12290 return;
12291 }
12292
12293 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012294 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012295
12296 while (*head != NUL)
12297 {
12298 c1 = PTR2CHAR(head);
12299 if (mask == NULL)
12300 {
12301 if (c1 > ' ' && c1 != 0xa0)
12302 break;
12303 }
12304 else
12305 {
12306 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12307 if (c1 == PTR2CHAR(p))
12308 break;
12309 if (*p == NUL)
12310 break;
12311 }
12312 MB_PTR_ADV(head);
12313 }
12314
12315 for (tail = head + STRLEN(head); tail > head; tail = prev)
12316 {
12317 prev = tail;
12318 MB_PTR_BACK(head, prev);
12319 c1 = PTR2CHAR(prev);
12320 if (mask == NULL)
12321 {
12322 if (c1 > ' ' && c1 != 0xa0)
12323 break;
12324 }
12325 else
12326 {
12327 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12328 if (c1 == PTR2CHAR(p))
12329 break;
12330 if (*p == NUL)
12331 break;
12332 }
12333 }
12334 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12335}
12336
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012337#ifdef FEAT_FLOAT
12338/*
12339 * "trunc({float})" function
12340 */
12341 static void
12342f_trunc(typval_T *argvars, typval_T *rettv)
12343{
12344 float_T f = 0.0;
12345
12346 rettv->v_type = VAR_FLOAT;
12347 if (get_float_arg(argvars, &f) == OK)
12348 /* trunc() is not in C90, use floor() or ceil() instead. */
12349 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12350 else
12351 rettv->vval.v_float = 0.0;
12352}
12353#endif
12354
12355/*
12356 * "type(expr)" function
12357 */
12358 static void
12359f_type(typval_T *argvars, typval_T *rettv)
12360{
12361 int n = -1;
12362
12363 switch (argvars[0].v_type)
12364 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012365 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12366 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012367 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012368 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12369 case VAR_LIST: n = VAR_TYPE_LIST; break;
12370 case VAR_DICT: n = VAR_TYPE_DICT; break;
12371 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012372 case VAR_SPECIAL:
12373 if (argvars[0].vval.v_number == VVAL_FALSE
12374 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012375 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012376 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012377 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012378 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012379 case VAR_JOB: n = VAR_TYPE_JOB; break;
12380 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012381 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012382 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012383 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012384 n = -1;
12385 break;
12386 }
12387 rettv->vval.v_number = n;
12388}
12389
12390/*
12391 * "undofile(name)" function
12392 */
12393 static void
12394f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12395{
12396 rettv->v_type = VAR_STRING;
12397#ifdef FEAT_PERSISTENT_UNDO
12398 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012399 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012400
12401 if (*fname == NUL)
12402 {
12403 /* If there is no file name there will be no undo file. */
12404 rettv->vval.v_string = NULL;
12405 }
12406 else
12407 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012408 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012409
12410 if (ffname != NULL)
12411 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12412 vim_free(ffname);
12413 }
12414 }
12415#else
12416 rettv->vval.v_string = NULL;
12417#endif
12418}
12419
12420/*
12421 * "undotree()" function
12422 */
12423 static void
12424f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12425{
12426 if (rettv_dict_alloc(rettv) == OK)
12427 {
12428 dict_T *dict = rettv->vval.v_dict;
12429 list_T *list;
12430
Bram Moolenaare0be1672018-07-08 16:50:37 +020012431 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12432 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12433 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12434 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12435 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12436 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012437
12438 list = list_alloc();
12439 if (list != NULL)
12440 {
12441 u_eval_tree(curbuf->b_u_oldhead, list);
12442 dict_add_list(dict, "entries", list);
12443 }
12444 }
12445}
12446
12447/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012448 * "virtcol(string)" function
12449 */
12450 static void
12451f_virtcol(typval_T *argvars, typval_T *rettv)
12452{
12453 colnr_T vcol = 0;
12454 pos_T *fp;
12455 int fnum = curbuf->b_fnum;
12456
12457 fp = var2fpos(&argvars[0], FALSE, &fnum);
12458 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12459 && fnum == curbuf->b_fnum)
12460 {
12461 getvvcol(curwin, fp, NULL, NULL, &vcol);
12462 ++vcol;
12463 }
12464
12465 rettv->vval.v_number = vcol;
12466}
12467
12468/*
12469 * "visualmode()" function
12470 */
12471 static void
12472f_visualmode(typval_T *argvars, typval_T *rettv)
12473{
12474 char_u str[2];
12475
12476 rettv->v_type = VAR_STRING;
12477 str[0] = curbuf->b_visual_mode_eval;
12478 str[1] = NUL;
12479 rettv->vval.v_string = vim_strsave(str);
12480
12481 /* A non-zero number or non-empty string argument: reset mode. */
12482 if (non_zero_arg(&argvars[0]))
12483 curbuf->b_visual_mode_eval = NUL;
12484}
12485
12486/*
12487 * "wildmenumode()" function
12488 */
12489 static void
12490f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12491{
12492#ifdef FEAT_WILDMENU
12493 if (wild_menu_showing)
12494 rettv->vval.v_number = 1;
12495#endif
12496}
12497
12498/*
12499 * "winbufnr(nr)" function
12500 */
12501 static void
12502f_winbufnr(typval_T *argvars, typval_T *rettv)
12503{
12504 win_T *wp;
12505
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012506 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012507 if (wp == NULL)
12508 rettv->vval.v_number = -1;
12509 else
12510 rettv->vval.v_number = wp->w_buffer->b_fnum;
12511}
12512
12513/*
12514 * "wincol()" function
12515 */
12516 static void
12517f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12518{
12519 validate_cursor();
12520 rettv->vval.v_number = curwin->w_wcol + 1;
12521}
12522
12523/*
12524 * "winheight(nr)" function
12525 */
12526 static void
12527f_winheight(typval_T *argvars, typval_T *rettv)
12528{
12529 win_T *wp;
12530
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012531 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012532 if (wp == NULL)
12533 rettv->vval.v_number = -1;
12534 else
12535 rettv->vval.v_number = wp->w_height;
12536}
12537
12538/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012539 * "winlayout()" function
12540 */
12541 static void
12542f_winlayout(typval_T *argvars, typval_T *rettv)
12543{
12544 tabpage_T *tp;
12545
12546 if (rettv_list_alloc(rettv) != OK)
12547 return;
12548
12549 if (argvars[0].v_type == VAR_UNKNOWN)
12550 tp = curtab;
12551 else
12552 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012553 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012554 if (tp == NULL)
12555 return;
12556 }
12557
12558 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12559}
12560
12561/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012562 * "winline()" function
12563 */
12564 static void
12565f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12566{
12567 validate_cursor();
12568 rettv->vval.v_number = curwin->w_wrow + 1;
12569}
12570
12571/*
12572 * "winnr()" function
12573 */
12574 static void
12575f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12576{
12577 int nr = 1;
12578
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012579 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012580 rettv->vval.v_number = nr;
12581}
12582
12583/*
12584 * "winrestcmd()" function
12585 */
12586 static void
12587f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12588{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012589 win_T *wp;
12590 int winnr = 1;
12591 garray_T ga;
12592 char_u buf[50];
12593
12594 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012595 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012596 {
12597 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12598 ga_concat(&ga, buf);
12599 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12600 ga_concat(&ga, buf);
12601 ++winnr;
12602 }
12603 ga_append(&ga, NUL);
12604
12605 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012606 rettv->v_type = VAR_STRING;
12607}
12608
12609/*
12610 * "winrestview()" function
12611 */
12612 static void
12613f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12614{
12615 dict_T *dict;
12616
12617 if (argvars[0].v_type != VAR_DICT
12618 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012619 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012620 else
12621 {
12622 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012623 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012624 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012625 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012626 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012627 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012628 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12629 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012630 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012631 curwin->w_set_curswant = FALSE;
12632 }
12633
12634 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012635 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012636#ifdef FEAT_DIFF
12637 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012638 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012639#endif
12640 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012641 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012642 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012643 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012644
12645 check_cursor();
12646 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012647 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012648 changed_window_setting();
12649
12650 if (curwin->w_topline <= 0)
12651 curwin->w_topline = 1;
12652 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12653 curwin->w_topline = curbuf->b_ml.ml_line_count;
12654#ifdef FEAT_DIFF
12655 check_topfill(curwin, TRUE);
12656#endif
12657 }
12658}
12659
12660/*
12661 * "winsaveview()" function
12662 */
12663 static void
12664f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12665{
12666 dict_T *dict;
12667
12668 if (rettv_dict_alloc(rettv) == FAIL)
12669 return;
12670 dict = rettv->vval.v_dict;
12671
Bram Moolenaare0be1672018-07-08 16:50:37 +020012672 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12673 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012674 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012675 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012676 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012677
Bram Moolenaare0be1672018-07-08 16:50:37 +020012678 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012679#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012680 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012681#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012682 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12683 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012684}
12685
12686/*
12687 * "winwidth(nr)" function
12688 */
12689 static void
12690f_winwidth(typval_T *argvars, typval_T *rettv)
12691{
12692 win_T *wp;
12693
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012694 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012695 if (wp == NULL)
12696 rettv->vval.v_number = -1;
12697 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012698 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012699}
12700
12701/*
12702 * "wordcount()" function
12703 */
12704 static void
12705f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12706{
12707 if (rettv_dict_alloc(rettv) == FAIL)
12708 return;
12709 cursor_pos_info(rettv->vval.v_dict);
12710}
12711
12712/*
12713 * "writefile()" function
12714 */
12715 static void
12716f_writefile(typval_T *argvars, typval_T *rettv)
12717{
12718 int binary = FALSE;
12719 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012720#ifdef HAVE_FSYNC
12721 int do_fsync = p_fs;
12722#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012723 char_u *fname;
12724 FILE *fd;
12725 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012726 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012727 list_T *list = NULL;
12728 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012729
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012730 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012731 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012732 return;
12733
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012734 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012735 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012736 list = argvars[0].vval.v_list;
12737 if (list == NULL)
12738 return;
12739 for (li = list->lv_first; li != NULL; li = li->li_next)
12740 if (tv_get_string_chk(&li->li_tv) == NULL)
12741 return;
12742 }
12743 else if (argvars[0].v_type == VAR_BLOB)
12744 {
12745 blob = argvars[0].vval.v_blob;
12746 if (blob == NULL)
12747 return;
12748 }
12749 else
12750 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012751 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012752 return;
12753 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012754
12755 if (argvars[2].v_type != VAR_UNKNOWN)
12756 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012757 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012758
12759 if (arg2 == NULL)
12760 return;
12761 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012762 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012763 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012764 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012765#ifdef HAVE_FSYNC
12766 if (vim_strchr(arg2, 's') != NULL)
12767 do_fsync = TRUE;
12768 else if (vim_strchr(arg2, 'S') != NULL)
12769 do_fsync = FALSE;
12770#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771 }
12772
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012773 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012774 if (fname == NULL)
12775 return;
12776
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012777 /* Always open the file in binary mode, library functions have a mind of
12778 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012779 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12780 append ? APPENDBIN : WRITEBIN)) == NULL)
12781 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012782 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012783 ret = -1;
12784 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012785 else if (blob)
12786 {
12787 if (write_blob(fd, blob) == FAIL)
12788 ret = -1;
12789#ifdef HAVE_FSYNC
12790 else if (do_fsync)
12791 // Ignore the error, the user wouldn't know what to do about it.
12792 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012793 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012794#endif
12795 fclose(fd);
12796 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012797 else
12798 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012799 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012800 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012801#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012802 else if (do_fsync)
12803 /* Ignore the error, the user wouldn't know what to do about it.
12804 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012805 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012806#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012807 fclose(fd);
12808 }
12809
12810 rettv->vval.v_number = ret;
12811}
12812
12813/*
12814 * "xor(expr, expr)" function
12815 */
12816 static void
12817f_xor(typval_T *argvars, typval_T *rettv)
12818{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012819 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
12820 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012821}
12822
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012823#endif /* FEAT_EVAL */