blob: 89430937f2abdd29c9b8b63203b0591cd8010d77 [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);
138#if defined(FEAT_CMDL_COMPL)
139static void f_getcompletion(typval_T *argvars, typval_T *rettv);
140#endif
141static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
142static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
143static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
144static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200145static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200146static void f_getfontname(typval_T *argvars, typval_T *rettv);
147static void f_getfperm(typval_T *argvars, typval_T *rettv);
148static void f_getfsize(typval_T *argvars, typval_T *rettv);
149static void f_getftime(typval_T *argvars, typval_T *rettv);
150static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100151static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200152static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200153static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200154static void f_getpid(typval_T *argvars, typval_T *rettv);
155static void f_getcurpos(typval_T *argvars, typval_T *rettv);
156static void f_getpos(typval_T *argvars, typval_T *rettv);
157static void f_getqflist(typval_T *argvars, typval_T *rettv);
158static void f_getreg(typval_T *argvars, typval_T *rettv);
159static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200160static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200161static void f_gettabvar(typval_T *argvars, typval_T *rettv);
162static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100163static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200164static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100165static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200166static void f_getwinposx(typval_T *argvars, typval_T *rettv);
167static void f_getwinposy(typval_T *argvars, typval_T *rettv);
168static void f_getwinvar(typval_T *argvars, typval_T *rettv);
169static void f_glob(typval_T *argvars, typval_T *rettv);
170static void f_globpath(typval_T *argvars, typval_T *rettv);
171static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
172static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
174static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_hlID(typval_T *argvars, typval_T *rettv);
176static void f_hlexists(typval_T *argvars, typval_T *rettv);
177static void f_hostname(typval_T *argvars, typval_T *rettv);
178static void f_iconv(typval_T *argvars, typval_T *rettv);
179static void f_indent(typval_T *argvars, typval_T *rettv);
180static void f_index(typval_T *argvars, typval_T *rettv);
181static void f_input(typval_T *argvars, typval_T *rettv);
182static void f_inputdialog(typval_T *argvars, typval_T *rettv);
183static void f_inputlist(typval_T *argvars, typval_T *rettv);
184static void f_inputrestore(typval_T *argvars, typval_T *rettv);
185static void f_inputsave(typval_T *argvars, typval_T *rettv);
186static void f_inputsecret(typval_T *argvars, typval_T *rettv);
187static void f_insert(typval_T *argvars, typval_T *rettv);
188static void f_invert(typval_T *argvars, typval_T *rettv);
189static void f_isdirectory(typval_T *argvars, typval_T *rettv);
190static void f_islocked(typval_T *argvars, typval_T *rettv);
191#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200192static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_isnan(typval_T *argvars, typval_T *rettv);
194#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
196static void f_len(typval_T *argvars, typval_T *rettv);
197static void f_libcall(typval_T *argvars, typval_T *rettv);
198static void f_libcallnr(typval_T *argvars, typval_T *rettv);
199static void f_line(typval_T *argvars, typval_T *rettv);
200static void f_line2byte(typval_T *argvars, typval_T *rettv);
201static void f_lispindent(typval_T *argvars, typval_T *rettv);
202static void f_localtime(typval_T *argvars, typval_T *rettv);
203#ifdef FEAT_FLOAT
204static void f_log(typval_T *argvars, typval_T *rettv);
205static void f_log10(typval_T *argvars, typval_T *rettv);
206#endif
207#ifdef FEAT_LUA
208static void f_luaeval(typval_T *argvars, typval_T *rettv);
209#endif
210static void f_map(typval_T *argvars, typval_T *rettv);
211static void f_maparg(typval_T *argvars, typval_T *rettv);
212static void f_mapcheck(typval_T *argvars, typval_T *rettv);
213static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200214static void f_matchend(typval_T *argvars, typval_T *rettv);
215static void f_matchlist(typval_T *argvars, typval_T *rettv);
216static void f_matchstr(typval_T *argvars, typval_T *rettv);
217static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
218static void f_max(typval_T *argvars, typval_T *rettv);
219static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200220static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_mode(typval_T *argvars, typval_T *rettv);
222#ifdef FEAT_MZSCHEME
223static void f_mzeval(typval_T *argvars, typval_T *rettv);
224#endif
225static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
226static void f_nr2char(typval_T *argvars, typval_T *rettv);
227static void f_or(typval_T *argvars, typval_T *rettv);
228static void f_pathshorten(typval_T *argvars, typval_T *rettv);
229#ifdef FEAT_PERL
230static void f_perleval(typval_T *argvars, typval_T *rettv);
231#endif
232#ifdef FEAT_FLOAT
233static void f_pow(typval_T *argvars, typval_T *rettv);
234#endif
235static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
236static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200237static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200238static void f_pumvisible(typval_T *argvars, typval_T *rettv);
239#ifdef FEAT_PYTHON3
240static void f_py3eval(typval_T *argvars, typval_T *rettv);
241#endif
242#ifdef FEAT_PYTHON
243static void f_pyeval(typval_T *argvars, typval_T *rettv);
244#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100245#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
246static void f_pyxeval(typval_T *argvars, typval_T *rettv);
247#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200249static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200250static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200251static void f_reg_executing(typval_T *argvars, typval_T *rettv);
252static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200253static void f_reltime(typval_T *argvars, typval_T *rettv);
254#ifdef FEAT_FLOAT
255static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
256#endif
257static void f_reltimestr(typval_T *argvars, typval_T *rettv);
258static void f_remote_expr(typval_T *argvars, typval_T *rettv);
259static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
260static void f_remote_peek(typval_T *argvars, typval_T *rettv);
261static void f_remote_read(typval_T *argvars, typval_T *rettv);
262static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100263static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_remove(typval_T *argvars, typval_T *rettv);
265static void f_rename(typval_T *argvars, typval_T *rettv);
266static void f_repeat(typval_T *argvars, typval_T *rettv);
267static void f_resolve(typval_T *argvars, typval_T *rettv);
268static void f_reverse(typval_T *argvars, typval_T *rettv);
269#ifdef FEAT_FLOAT
270static void f_round(typval_T *argvars, typval_T *rettv);
271#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100272#ifdef FEAT_RUBY
273static void f_rubyeval(typval_T *argvars, typval_T *rettv);
274#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200275static void f_screenattr(typval_T *argvars, typval_T *rettv);
276static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100277static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200278static void f_screencol(typval_T *argvars, typval_T *rettv);
279static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100280static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200281static void f_search(typval_T *argvars, typval_T *rettv);
282static void f_searchdecl(typval_T *argvars, typval_T *rettv);
283static void f_searchpair(typval_T *argvars, typval_T *rettv);
284static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
285static void f_searchpos(typval_T *argvars, typval_T *rettv);
286static void f_server2client(typval_T *argvars, typval_T *rettv);
287static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200288static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200289static void f_setbufvar(typval_T *argvars, typval_T *rettv);
290static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
291static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200292static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200293static void f_setfperm(typval_T *argvars, typval_T *rettv);
294static void f_setline(typval_T *argvars, typval_T *rettv);
295static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200296static void f_setpos(typval_T *argvars, typval_T *rettv);
297static void f_setqflist(typval_T *argvars, typval_T *rettv);
298static void f_setreg(typval_T *argvars, typval_T *rettv);
299static void f_settabvar(typval_T *argvars, typval_T *rettv);
300static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100301static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_setwinvar(typval_T *argvars, typval_T *rettv);
303#ifdef FEAT_CRYPT
304static void f_sha256(typval_T *argvars, typval_T *rettv);
305#endif /* FEAT_CRYPT */
306static void f_shellescape(typval_T *argvars, typval_T *rettv);
307static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
308static void f_simplify(typval_T *argvars, typval_T *rettv);
309#ifdef FEAT_FLOAT
310static void f_sin(typval_T *argvars, typval_T *rettv);
311static void f_sinh(typval_T *argvars, typval_T *rettv);
312#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200313static void f_soundfold(typval_T *argvars, typval_T *rettv);
314static void f_spellbadword(typval_T *argvars, typval_T *rettv);
315static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
316static void f_split(typval_T *argvars, typval_T *rettv);
317#ifdef FEAT_FLOAT
318static void f_sqrt(typval_T *argvars, typval_T *rettv);
319static void f_str2float(typval_T *argvars, typval_T *rettv);
320#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200321static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200322static void f_str2nr(typval_T *argvars, typval_T *rettv);
323static void f_strchars(typval_T *argvars, typval_T *rettv);
324#ifdef HAVE_STRFTIME
325static void f_strftime(typval_T *argvars, typval_T *rettv);
326#endif
327static void f_strgetchar(typval_T *argvars, typval_T *rettv);
328static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200329static void f_strlen(typval_T *argvars, typval_T *rettv);
330static void f_strcharpart(typval_T *argvars, typval_T *rettv);
331static void f_strpart(typval_T *argvars, typval_T *rettv);
332static void f_strridx(typval_T *argvars, typval_T *rettv);
333static void f_strtrans(typval_T *argvars, typval_T *rettv);
334static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
335static void f_strwidth(typval_T *argvars, typval_T *rettv);
336static void f_submatch(typval_T *argvars, typval_T *rettv);
337static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200338static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200339static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200340static void f_synID(typval_T *argvars, typval_T *rettv);
341static void f_synIDattr(typval_T *argvars, typval_T *rettv);
342static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
343static void f_synstack(typval_T *argvars, typval_T *rettv);
344static void f_synconcealed(typval_T *argvars, typval_T *rettv);
345static void f_system(typval_T *argvars, typval_T *rettv);
346static void f_systemlist(typval_T *argvars, typval_T *rettv);
347static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
348static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
349static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
350static void f_taglist(typval_T *argvars, typval_T *rettv);
351static void f_tagfiles(typval_T *argvars, typval_T *rettv);
352static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353#ifdef FEAT_FLOAT
354static void f_tan(typval_T *argvars, typval_T *rettv);
355static void f_tanh(typval_T *argvars, typval_T *rettv);
356#endif
357#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200358static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200359static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200360static void f_timer_start(typval_T *argvars, typval_T *rettv);
361static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200362static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200363#endif
364static void f_tolower(typval_T *argvars, typval_T *rettv);
365static void f_toupper(typval_T *argvars, typval_T *rettv);
366static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100367static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200368#ifdef FEAT_FLOAT
369static void f_trunc(typval_T *argvars, typval_T *rettv);
370#endif
371static void f_type(typval_T *argvars, typval_T *rettv);
372static void f_undofile(typval_T *argvars, typval_T *rettv);
373static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200374static void f_virtcol(typval_T *argvars, typval_T *rettv);
375static void f_visualmode(typval_T *argvars, typval_T *rettv);
376static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200377static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
379static void f_win_getid(typval_T *argvars, typval_T *rettv);
380static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
381static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
382static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100383static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200384static void f_winbufnr(typval_T *argvars, typval_T *rettv);
385static void f_wincol(typval_T *argvars, typval_T *rettv);
386static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200387static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200388static void f_winline(typval_T *argvars, typval_T *rettv);
389static void f_winnr(typval_T *argvars, typval_T *rettv);
390static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
391static void f_winrestview(typval_T *argvars, typval_T *rettv);
392static void f_winsaveview(typval_T *argvars, typval_T *rettv);
393static void f_winwidth(typval_T *argvars, typval_T *rettv);
394static void f_writefile(typval_T *argvars, typval_T *rettv);
395static void f_wordcount(typval_T *argvars, typval_T *rettv);
396static void f_xor(typval_T *argvars, typval_T *rettv);
397
398/*
399 * Array with names and number of arguments of all internal functions
400 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
401 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200402typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200403{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200404 char *f_name; // function name
405 char f_min_argc; // minimal number of arguments
406 char f_max_argc; // maximal number of arguments
407 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200408 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200409 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200410} funcentry_T;
411
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200412// values for f_argtype; zero means it cannot be used as a method
413#define FEARG_1 1 // base is the first argument
414#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200415#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200416#define FEARG_LAST 9 // base is the last argument
417
Bram Moolenaarac92e252019-08-03 21:58:38 +0200418static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419{
420#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200421 {"abs", 1, 1, 0, f_abs},
422 {"acos", 1, 1, 0, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200423#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200424 {"add", 2, 2, FEARG_1, f_add},
425 {"and", 2, 2, 0, f_and},
426 {"append", 2, 2, FEARG_LAST, f_append},
427 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
428 {"argc", 0, 1, 0, f_argc},
429 {"argidx", 0, 0, 0, f_argidx},
430 {"arglistid", 0, 2, 0, f_arglistid},
431 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200432#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200433 {"asin", 1, 1, 0, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200435 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200436 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
437 {"assert_equalfile", 2, 2, 0, f_assert_equalfile},
438 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200439 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
440 {"assert_false", 1, 2, FEARG_1, f_assert_false},
441 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
442 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200443 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200444 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200445 {"assert_report", 1, 1, 0, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200446 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200448 {"atan", 1, 1, 0, f_atan},
449 {"atan2", 2, 2, 0, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200450#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100451#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200452 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
453 {"balloon_show", 1, 1, 0, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100454# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200455 {"balloon_split", 1, 1, 0, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100456# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100457#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200458 {"browse", 4, 4, 0, f_browse},
459 {"browsedir", 2, 2, 0, f_browsedir},
460 {"bufadd", 1, 1, 0, f_bufadd},
461 {"bufexists", 1, 1, 0, f_bufexists},
462 {"buffer_exists", 1, 1, 0, f_bufexists}, // obsolete
463 {"buffer_name", 1, 1, 0, f_bufname}, // obsolete
464 {"buffer_number", 1, 1, 0, f_bufnr}, // obsolete
465 {"buflisted", 1, 1, 0, f_buflisted},
466 {"bufload", 1, 1, 0, f_bufload},
467 {"bufloaded", 1, 1, 0, f_bufloaded},
468 {"bufname", 1, 1, 0, f_bufname},
469 {"bufnr", 1, 2, 0, f_bufnr},
470 {"bufwinid", 1, 1, 0, f_bufwinid},
471 {"bufwinnr", 1, 1, 0, f_bufwinnr},
472 {"byte2line", 1, 1, 0, f_byte2line},
473 {"byteidx", 2, 2, 0, f_byteidx},
474 {"byteidxcomp", 2, 2, 0, f_byteidxcomp},
475 {"call", 2, 3, 0, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200476#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200477 {"ceil", 1, 1, 0, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200478#endif
479#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200480 {"ch_canread", 1, 1, 0, f_ch_canread},
481 {"ch_close", 1, 1, 0, f_ch_close},
482 {"ch_close_in", 1, 1, 0, f_ch_close_in},
483 {"ch_evalexpr", 2, 3, 0, f_ch_evalexpr},
484 {"ch_evalraw", 2, 3, 0, f_ch_evalraw},
485 {"ch_getbufnr", 2, 2, 0, f_ch_getbufnr},
486 {"ch_getjob", 1, 1, 0, f_ch_getjob},
487 {"ch_info", 1, 1, 0, f_ch_info},
488 {"ch_log", 1, 2, 0, f_ch_log},
489 {"ch_logfile", 1, 2, 0, f_ch_logfile},
490 {"ch_open", 1, 2, 0, f_ch_open},
491 {"ch_read", 1, 2, 0, f_ch_read},
492 {"ch_readblob", 1, 2, 0, f_ch_readblob},
493 {"ch_readraw", 1, 2, 0, f_ch_readraw},
494 {"ch_sendexpr", 2, 3, 0, f_ch_sendexpr},
495 {"ch_sendraw", 2, 3, 0, f_ch_sendraw},
496 {"ch_setoptions", 2, 2, 0, f_ch_setoptions},
497 {"ch_status", 1, 2, 0, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200499 {"changenr", 0, 0, 0, f_changenr},
500 {"char2nr", 1, 2, 0, f_char2nr},
501 {"chdir", 1, 1, 0, f_chdir},
502 {"cindent", 1, 1, 0, f_cindent},
503 {"clearmatches", 0, 1, 0, f_clearmatches},
504 {"col", 1, 1, 0, f_col},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200505#if defined(FEAT_INS_EXPAND)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200506 {"complete", 2, 2, 0, f_complete},
507 {"complete_add", 1, 1, 0, f_complete_add},
508 {"complete_check", 0, 0, 0, f_complete_check},
509 {"complete_info", 0, 1, 0, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200510#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200511 {"confirm", 1, 4, 0, f_confirm},
512 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200514 {"cos", 1, 1, 0, f_cos},
515 {"cosh", 1, 1, 0, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200517 {"count", 2, 4, FEARG_1, f_count},
518 {"cscope_connection",0,3, 0, f_cscope_connection},
519 {"cursor", 1, 3, 0, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100520#ifdef MSWIN
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200521 {"debugbreak", 1, 1, 0, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200522#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200523 {"deepcopy", 1, 2, 0, f_deepcopy},
524 {"delete", 1, 2, 0, f_delete},
525 {"deletebufline", 2, 3, 0, f_deletebufline},
526 {"did_filetype", 0, 0, 0, f_did_filetype},
527 {"diff_filler", 1, 1, 0, f_diff_filler},
528 {"diff_hlID", 2, 2, 0, f_diff_hlID},
529 {"empty", 1, 1, FEARG_1, f_empty},
530 {"environ", 0, 0, 0, f_environ},
531 {"escape", 2, 2, 0, f_escape},
532 {"eval", 1, 1, FEARG_1, f_eval},
533 {"eventhandler", 0, 0, 0, f_eventhandler},
534 {"executable", 1, 1, 0, f_executable},
535 {"execute", 1, 2, 0, f_execute},
536 {"exepath", 1, 1, 0, f_exepath},
537 {"exists", 1, 1, 0, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200538#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200539 {"exp", 1, 1, 0, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200540#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200541 {"expand", 1, 3, 0, f_expand},
542 {"expandcmd", 1, 1, 0, f_expandcmd},
543 {"extend", 2, 3, FEARG_1, f_extend},
544 {"feedkeys", 1, 2, 0, f_feedkeys},
545 {"file_readable", 1, 1, 0, f_filereadable}, // obsolete
546 {"filereadable", 1, 1, 0, f_filereadable},
547 {"filewritable", 1, 1, 0, f_filewritable},
548 {"filter", 2, 2, FEARG_1, f_filter},
549 {"finddir", 1, 3, 0, f_finddir},
550 {"findfile", 1, 3, 0, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200551#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200552 {"float2nr", 1, 1, 0, f_float2nr},
553 {"floor", 1, 1, 0, f_floor},
554 {"fmod", 2, 2, 0, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200555#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200556 {"fnameescape", 1, 1, 0, f_fnameescape},
557 {"fnamemodify", 2, 2, 0, f_fnamemodify},
558 {"foldclosed", 1, 1, 0, f_foldclosed},
559 {"foldclosedend", 1, 1, 0, f_foldclosedend},
560 {"foldlevel", 1, 1, 0, f_foldlevel},
561 {"foldtext", 0, 0, 0, f_foldtext},
562 {"foldtextresult", 1, 1, 0, f_foldtextresult},
563 {"foreground", 0, 0, 0, f_foreground},
564 {"funcref", 1, 3, 0, f_funcref},
565 {"function", 1, 3, 0, f_function},
566 {"garbagecollect", 0, 1, 0, f_garbagecollect},
567 {"get", 2, 3, FEARG_1, f_get},
568 {"getbufinfo", 0, 1, 0, f_getbufinfo},
569 {"getbufline", 2, 3, 0, f_getbufline},
570 {"getbufvar", 2, 3, 0, f_getbufvar},
571 {"getchangelist", 1, 1, 0, f_getchangelist},
572 {"getchar", 0, 1, 0, f_getchar},
573 {"getcharmod", 0, 0, 0, f_getcharmod},
574 {"getcharsearch", 0, 0, 0, f_getcharsearch},
575 {"getcmdline", 0, 0, 0, f_getcmdline},
576 {"getcmdpos", 0, 0, 0, f_getcmdpos},
577 {"getcmdtype", 0, 0, 0, f_getcmdtype},
578 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200579#if defined(FEAT_CMDL_COMPL)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200580 {"getcompletion", 2, 3, 0, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200581#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200582 {"getcurpos", 0, 0, 0, f_getcurpos},
583 {"getcwd", 0, 2, 0, f_getcwd},
584 {"getenv", 1, 1, 0, f_getenv},
585 {"getfontname", 0, 1, 0, f_getfontname},
586 {"getfperm", 1, 1, 0, f_getfperm},
587 {"getfsize", 1, 1, 0, f_getfsize},
588 {"getftime", 1, 1, 0, f_getftime},
589 {"getftype", 1, 1, 0, f_getftype},
590 {"getjumplist", 0, 2, 0, f_getjumplist},
591 {"getline", 1, 2, 0, f_getline},
592 {"getloclist", 1, 2, 0, f_getloclist},
593 {"getmatches", 0, 1, 0, f_getmatches},
594 {"getpid", 0, 0, 0, f_getpid},
595 {"getpos", 1, 1, 0, f_getpos},
596 {"getqflist", 0, 1, 0, f_getqflist},
597 {"getreg", 0, 3, 0, f_getreg},
598 {"getregtype", 0, 1, 0, f_getregtype},
599 {"gettabinfo", 0, 1, 0, f_gettabinfo},
600 {"gettabvar", 2, 3, 0, f_gettabvar},
601 {"gettabwinvar", 3, 4, 0, f_gettabwinvar},
602 {"gettagstack", 0, 1, 0, f_gettagstack},
603 {"getwininfo", 0, 1, 0, f_getwininfo},
604 {"getwinpos", 0, 1, 0, f_getwinpos},
605 {"getwinposx", 0, 0, 0, f_getwinposx},
606 {"getwinposy", 0, 0, 0, f_getwinposy},
607 {"getwinvar", 2, 3, 0, f_getwinvar},
608 {"glob", 1, 4, 0, f_glob},
609 {"glob2regpat", 1, 1, 0, f_glob2regpat},
610 {"globpath", 2, 5, 0, f_globpath},
611 {"has", 1, 1, 0, f_has},
612 {"has_key", 2, 2, FEARG_1, f_has_key},
613 {"haslocaldir", 0, 2, 0, f_haslocaldir},
614 {"hasmapto", 1, 3, 0, f_hasmapto},
615 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
616 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
617 {"histadd", 2, 2, 0, f_histadd},
618 {"histdel", 1, 2, 0, f_histdel},
619 {"histget", 1, 2, 0, f_histget},
620 {"histnr", 1, 1, 0, f_histnr},
621 {"hlID", 1, 1, 0, f_hlID},
622 {"hlexists", 1, 1, 0, f_hlexists},
623 {"hostname", 0, 0, 0, f_hostname},
624 {"iconv", 3, 3, 0, f_iconv},
625 {"indent", 1, 1, 0, f_indent},
626 {"index", 2, 4, FEARG_1, f_index},
627 {"input", 1, 3, 0, f_input},
628 {"inputdialog", 1, 3, 0, f_inputdialog},
629 {"inputlist", 1, 1, 0, f_inputlist},
630 {"inputrestore", 0, 0, 0, f_inputrestore},
631 {"inputsave", 0, 0, 0, f_inputsave},
632 {"inputsecret", 1, 2, 0, f_inputsecret},
633 {"insert", 2, 3, FEARG_1, f_insert},
634 {"invert", 1, 1, 0, f_invert},
635 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200636#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200637 {"isinf", 1, 1, 0, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200638#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200639 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200641 {"isnan", 1, 1, 0, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200642#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200643 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200645 {"job_getchannel", 1, 1, 0, f_job_getchannel},
646 {"job_info", 0, 1, 0, f_job_info},
647 {"job_setoptions", 2, 2, 0, f_job_setoptions},
648 {"job_start", 1, 2, 0, f_job_start},
649 {"job_status", 1, 1, 0, f_job_status},
650 {"job_stop", 1, 2, 0, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200652 {"join", 1, 2, FEARG_1, f_join},
653 {"js_decode", 1, 1, 0, f_js_decode},
654 {"js_encode", 1, 1, 0, f_js_encode},
655 {"json_decode", 1, 1, 0, f_json_decode},
656 {"json_encode", 1, 1, 0, f_json_encode},
657 {"keys", 1, 1, FEARG_1, f_keys},
658 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
659 {"len", 1, 1, FEARG_1, f_len},
660 {"libcall", 3, 3, 0, f_libcall},
661 {"libcallnr", 3, 3, 0, f_libcallnr},
662 {"line", 1, 1, 0, f_line},
663 {"line2byte", 1, 1, 0, f_line2byte},
664 {"lispindent", 1, 1, 0, f_lispindent},
665 {"list2str", 1, 2, 0, f_list2str},
666 {"listener_add", 1, 2, 0, f_listener_add},
667 {"listener_flush", 0, 1, 0, f_listener_flush},
668 {"listener_remove", 1, 1, 0, f_listener_remove},
669 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200670#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200671 {"log", 1, 1, 0, f_log},
672 {"log10", 1, 1, 0, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200673#endif
674#ifdef FEAT_LUA
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200675 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200676#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200677 {"map", 2, 2, FEARG_1, f_map},
678 {"maparg", 1, 4, 0, f_maparg},
679 {"mapcheck", 1, 3, 0, f_mapcheck},
680 {"match", 2, 4, 0, f_match},
681 {"matchadd", 2, 5, 0, f_matchadd},
682 {"matchaddpos", 2, 5, 0, f_matchaddpos},
683 {"matcharg", 1, 1, 0, f_matcharg},
684 {"matchdelete", 1, 2, 0, f_matchdelete},
685 {"matchend", 2, 4, 0, f_matchend},
686 {"matchlist", 2, 4, 0, f_matchlist},
687 {"matchstr", 2, 4, 0, f_matchstr},
688 {"matchstrpos", 2, 4, 0, f_matchstrpos},
689 {"max", 1, 1, FEARG_1, f_max},
690 {"min", 1, 1, FEARG_1, f_min},
691 {"mkdir", 1, 3, 0, f_mkdir},
692 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693#ifdef FEAT_MZSCHEME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200694 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200696 {"nextnonblank", 1, 1, 0, f_nextnonblank},
697 {"nr2char", 1, 2, 0, f_nr2char},
698 {"or", 2, 2, 0, f_or},
699 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200700#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200701 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200702#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200703#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200704 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
705 {"popup_beval", 2, 2, 0, f_popup_beval},
706 {"popup_clear", 0, 0, 0, f_popup_clear},
707 {"popup_close", 1, 2, 0, f_popup_close},
708 {"popup_create", 2, 2, 0, f_popup_create},
709 {"popup_dialog", 2, 2, 0, f_popup_dialog},
710 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
711 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
712 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
713 {"popup_getpos", 1, 1, 0, f_popup_getpos},
714 {"popup_getpreview", 0, 0, 0, f_popup_getpreview},
715 {"popup_hide", 1, 1, 0, f_popup_hide},
716 {"popup_locate", 2, 2, 0, f_popup_locate},
717 {"popup_menu", 2, 2, 0, f_popup_menu},
718 {"popup_move", 2, 2, 0, f_popup_move},
719 {"popup_notification", 2, 2, 0, f_popup_notification},
720 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
721 {"popup_settext", 2, 2, 0, f_popup_settext},
722 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200723#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200724#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200725 {"pow", 2, 2, 0, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200726#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200727 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200728 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200729#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200730 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
731 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
732 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200733#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100734#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200735 {"prop_add", 3, 3, 0, f_prop_add},
736 {"prop_clear", 1, 3, 0, f_prop_clear},
737 {"prop_list", 1, 2, 0, f_prop_list},
738 {"prop_remove", 1, 3, 0, f_prop_remove},
739 {"prop_type_add", 2, 2, 0, f_prop_type_add},
740 {"prop_type_change", 2, 2, 0, f_prop_type_change},
741 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
742 {"prop_type_get", 1, 2, 0, f_prop_type_get},
743 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100744#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200745 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200746 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200748 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200749#endif
750#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200751 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200752#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100753#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200754 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100755#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200756 {"range", 1, 3, 0, f_range},
757 {"readdir", 1, 2, 0, f_readdir},
758 {"readfile", 1, 3, 0, f_readfile},
759 {"reg_executing", 0, 0, 0, f_reg_executing},
760 {"reg_recording", 0, 0, 0, f_reg_recording},
761 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200763 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200764#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200765 {"reltimestr", 1, 1, 0, f_reltimestr},
766 {"remote_expr", 2, 4, 0, f_remote_expr},
767 {"remote_foreground", 1, 1, 0, f_remote_foreground},
768 {"remote_peek", 1, 2, 0, f_remote_peek},
769 {"remote_read", 1, 2, 0, f_remote_read},
770 {"remote_send", 2, 3, 0, f_remote_send},
771 {"remote_startserver", 1, 1, 0, f_remote_startserver},
772 {"remove", 2, 3, FEARG_1, f_remove},
773 {"rename", 2, 2, 0, f_rename},
774 {"repeat", 2, 2, FEARG_1, f_repeat},
775 {"resolve", 1, 1, 0, f_resolve},
776 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200778 {"round", 1, 1, 0, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100780#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200781 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100782#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200783 {"screenattr", 2, 2, 0, f_screenattr},
784 {"screenchar", 2, 2, 0, f_screenchar},
785 {"screenchars", 2, 2, 0, f_screenchars},
786 {"screencol", 0, 0, 0, f_screencol},
787 {"screenpos", 3, 3, 0, f_screenpos},
788 {"screenrow", 0, 0, 0, f_screenrow},
789 {"screenstring", 2, 2, 0, f_screenstring},
790 {"search", 1, 4, 0, f_search},
791 {"searchdecl", 1, 3, 0, f_searchdecl},
792 {"searchpair", 3, 7, 0, f_searchpair},
793 {"searchpairpos", 3, 7, 0, f_searchpairpos},
794 {"searchpos", 1, 4, 0, f_searchpos},
795 {"server2client", 2, 2, 0, f_server2client},
796 {"serverlist", 0, 0, 0, f_serverlist},
797 {"setbufline", 3, 3, 0, f_setbufline},
798 {"setbufvar", 3, 3, 0, f_setbufvar},
799 {"setcharsearch", 1, 1, 0, f_setcharsearch},
800 {"setcmdpos", 1, 1, 0, f_setcmdpos},
801 {"setenv", 2, 2, 0, f_setenv},
802 {"setfperm", 2, 2, 0, f_setfperm},
803 {"setline", 2, 2, 0, f_setline},
804 {"setloclist", 2, 4, 0, f_setloclist},
805 {"setmatches", 1, 2, 0, f_setmatches},
806 {"setpos", 2, 2, 0, f_setpos},
807 {"setqflist", 1, 3, 0, f_setqflist},
808 {"setreg", 2, 3, 0, f_setreg},
809 {"settabvar", 3, 3, 0, f_settabvar},
810 {"settabwinvar", 4, 4, 0, f_settabwinvar},
811 {"settagstack", 2, 3, 0, f_settagstack},
812 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200813#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200814 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200815#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200816 {"shellescape", 1, 2, 0, f_shellescape},
817 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100818#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200819 {"sign_define", 1, 2, 0, f_sign_define},
820 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
821 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
822 {"sign_jump", 3, 3, 0, f_sign_jump},
823 {"sign_place", 4, 5, 0, f_sign_place},
824 {"sign_placelist", 1, 1, 0, f_sign_placelist},
825 {"sign_undefine", 0, 1, 0, f_sign_undefine},
826 {"sign_unplace", 1, 2, 0, f_sign_unplace},
827 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100828#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200829 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200831 {"sin", 1, 1, 0, f_sin},
832 {"sinh", 1, 1, 0, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200833#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200834 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200835#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200836 {"sound_clear", 0, 0, 0, f_sound_clear},
837 {"sound_playevent", 1, 2, 0, f_sound_playevent},
838 {"sound_playfile", 1, 2, 0, f_sound_playfile},
839 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200840#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200841 {"soundfold", 1, 1, 0, f_soundfold},
842 {"spellbadword", 0, 1, 0, f_spellbadword},
843 {"spellsuggest", 1, 3, 0, f_spellsuggest},
844 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200845#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200846 {"sqrt", 1, 1, 0, f_sqrt},
847 {"str2float", 1, 1, 0, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200849 {"str2list", 1, 2, FEARG_1, f_str2list},
850 {"str2nr", 1, 2, 0, f_str2nr},
851 {"strcharpart", 2, 3, 0, f_strcharpart},
852 {"strchars", 1, 2, 0, f_strchars},
853 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200854#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200855 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200857 {"strgetchar", 2, 2, 0, f_strgetchar},
858 {"stridx", 2, 3, 0, f_stridx},
859 {"string", 1, 1, FEARG_1, f_string},
860 {"strlen", 1, 1, FEARG_1, f_strlen},
861 {"strpart", 2, 3, 0, f_strpart},
862 {"strridx", 2, 3, 0, f_strridx},
863 {"strtrans", 1, 1, FEARG_1, f_strtrans},
864 {"strwidth", 1, 1, FEARG_1, f_strwidth},
865 {"submatch", 1, 2, 0, f_submatch},
866 {"substitute", 4, 4, FEARG_1, f_substitute},
867 {"swapinfo", 1, 1, 0, f_swapinfo},
868 {"swapname", 1, 1, 0, f_swapname},
869 {"synID", 3, 3, 0, f_synID},
870 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
871 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
872 {"synconcealed", 2, 2, 0, f_synconcealed},
873 {"synstack", 2, 2, 0, f_synstack},
874 {"system", 1, 2, FEARG_1, f_system},
875 {"systemlist", 1, 2, FEARG_1, f_systemlist},
876 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
877 {"tabpagenr", 0, 1, 0, f_tabpagenr},
878 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
879 {"tagfiles", 0, 0, 0, f_tagfiles},
880 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200881#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200882 {"tan", 1, 1, 0, f_tan},
883 {"tanh", 1, 1, 0, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200884#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200885 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200886#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200887 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
888 {"term_dumpload", 1, 2, 0, f_term_dumpload},
889 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
890 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200891# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200892 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200893# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200894 {"term_getattr", 2, 2, 0, f_term_getattr},
895 {"term_getcursor", 1, 1, 0, f_term_getcursor},
896 {"term_getjob", 1, 1, 0, f_term_getjob},
897 {"term_getline", 2, 2, 0, f_term_getline},
898 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
899 {"term_getsize", 1, 1, 0, f_term_getsize},
900 {"term_getstatus", 1, 1, 0, f_term_getstatus},
901 {"term_gettitle", 1, 1, 0, f_term_gettitle},
902 {"term_gettty", 1, 2, 0, f_term_gettty},
903 {"term_list", 0, 0, 0, f_term_list},
904 {"term_scrape", 2, 2, 0, f_term_scrape},
905 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200906# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200907 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200908# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200909 {"term_setkill", 2, 2, 0, f_term_setkill},
910 {"term_setrestore", 2, 2, 0, f_term_setrestore},
911 {"term_setsize", 3, 3, 0, f_term_setsize},
912 {"term_start", 1, 2, 0, f_term_start},
913 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200914#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200915 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
916 {"test_autochdir", 0, 0, 0, f_test_autochdir},
917 {"test_feedinput", 1, 1, 0, f_test_feedinput},
918 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
919 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
920 {"test_getvalue", 1, 1, 0, f_test_getvalue},
921 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
922 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200924 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200926 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200927#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200928 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200930 {"test_null_list", 0, 0, 0, f_test_null_list},
931 {"test_null_partial", 0, 0, 0, f_test_null_partial},
932 {"test_null_string", 0, 0, 0, f_test_null_string},
933 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
934 {"test_override", 2, 2, 0, f_test_override},
935 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200936#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200937 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200938#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200939#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200940 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200941#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200942 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200944 {"timer_info", 0, 1, 0, f_timer_info},
945 {"timer_pause", 2, 2, 0, f_timer_pause},
946 {"timer_start", 2, 3, 0, f_timer_start},
947 {"timer_stop", 1, 1, 0, f_timer_stop},
948 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200950 {"tolower", 1, 1, 0, f_tolower},
951 {"toupper", 1, 1, 0, f_toupper},
952 {"tr", 3, 3, 0, f_tr},
953 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200954#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200955 {"trunc", 1, 1, 0, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200957 {"type", 1, 1, FEARG_1, f_type},
958 {"undofile", 1, 1, 0, f_undofile},
959 {"undotree", 0, 0, 0, f_undotree},
960 {"uniq", 1, 3, FEARG_1, f_uniq},
961 {"values", 1, 1, FEARG_1, f_values},
962 {"virtcol", 1, 1, 0, f_virtcol},
963 {"visualmode", 0, 1, 0, f_visualmode},
964 {"wildmenumode", 0, 0, 0, f_wildmenumode},
965 {"win_execute", 2, 3, 0, f_win_execute},
966 {"win_findbuf", 1, 1, 0, f_win_findbuf},
967 {"win_getid", 0, 2, 0, f_win_getid},
968 {"win_gotoid", 1, 1, 0, f_win_gotoid},
969 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
970 {"win_id2win", 1, 1, 0, f_win_id2win},
971 {"win_screenpos", 1, 1, 0, f_win_screenpos},
972 {"winbufnr", 1, 1, 0, f_winbufnr},
973 {"wincol", 0, 0, 0, f_wincol},
974 {"winheight", 1, 1, 0, f_winheight},
975 {"winlayout", 0, 1, 0, f_winlayout},
976 {"winline", 0, 0, 0, f_winline},
977 {"winnr", 0, 1, 0, f_winnr},
978 {"winrestcmd", 0, 0, 0, f_winrestcmd},
979 {"winrestview", 1, 1, 0, f_winrestview},
980 {"winsaveview", 0, 0, 0, f_winsaveview},
981 {"winwidth", 1, 1, 0, f_winwidth},
982 {"wordcount", 0, 0, 0, f_wordcount},
983 {"writefile", 2, 3, 0, f_writefile},
984 {"xor", 2, 2, 0, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200985};
986
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200987#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
988
989/*
990 * Function given to ExpandGeneric() to obtain the list of internal
991 * or user defined function names.
992 */
993 char_u *
994get_function_name(expand_T *xp, int idx)
995{
996 static int intidx = -1;
997 char_u *name;
998
999 if (idx == 0)
1000 intidx = -1;
1001 if (intidx < 0)
1002 {
1003 name = get_user_func_name(xp, idx);
1004 if (name != NULL)
1005 return name;
1006 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001007 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001008 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001009 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001010 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001011 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012 STRCAT(IObuff, ")");
1013 return IObuff;
1014 }
1015
1016 return NULL;
1017}
1018
1019/*
1020 * Function given to ExpandGeneric() to obtain the list of internal or
1021 * user defined variable or function names.
1022 */
1023 char_u *
1024get_expr_name(expand_T *xp, int idx)
1025{
1026 static int intidx = -1;
1027 char_u *name;
1028
1029 if (idx == 0)
1030 intidx = -1;
1031 if (intidx < 0)
1032 {
1033 name = get_function_name(xp, idx);
1034 if (name != NULL)
1035 return name;
1036 }
1037 return get_user_var_name(xp, ++intidx);
1038}
1039
1040#endif /* FEAT_CMDL_COMPL */
1041
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001042/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001043 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001044 * Return index, or -1 if not found
1045 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001046 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001047find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001048{
1049 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001050 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001051 int cmp;
1052 int x;
1053
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001054 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001055
1056 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001057 while (first <= last)
1058 {
1059 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001060 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001061 if (cmp < 0)
1062 last = x - 1;
1063 else if (cmp > 0)
1064 first = x + 1;
1065 else
1066 return x;
1067 }
1068 return -1;
1069}
1070
1071 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001072has_internal_func(char_u *name)
1073{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001074 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001075}
1076
1077 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001078call_internal_func(
1079 char_u *name,
1080 int argcount,
1081 typval_T *argvars,
1082 typval_T *rettv)
1083{
1084 int i;
1085
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001086 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001087 if (i < 0)
1088 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001089 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001090 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001091 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001092 return ERROR_TOOMANY;
1093 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001094 global_functions[i].f_func(argvars, rettv);
1095 return ERROR_NONE;
1096}
1097
1098/*
1099 * Invoke a method for base->method().
1100 */
1101 int
1102call_internal_method(
1103 char_u *name,
1104 int argcount,
1105 typval_T *argvars,
1106 typval_T *rettv,
1107 typval_T *basetv)
1108{
1109 int i;
1110 int fi;
1111 typval_T argv[MAX_FUNC_ARGS + 1];
1112
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001113 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001114 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001115 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001116 if (global_functions[fi].f_argtype == 0)
1117 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001118 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001119 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001120 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001121 return ERROR_TOOMANY;
1122
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001123 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001124 {
1125 // base value goes last
1126 for (i = 0; i < argcount; ++i)
1127 argv[i] = argvars[i];
1128 argv[argcount] = *basetv;
1129 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001130 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001131 {
1132 // base value goes second
1133 argv[0] = argvars[0];
1134 argv[1] = *basetv;
1135 for (i = 1; i < argcount; ++i)
1136 argv[i + 1] = argvars[i];
1137 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001138 else if (global_functions[fi].f_argtype == FEARG_3)
1139 {
1140 // base value goes third
1141 argv[0] = argvars[0];
1142 argv[1] = argvars[1];
1143 argv[2] = *basetv;
1144 for (i = 2; i < argcount; ++i)
1145 argv[i + 1] = argvars[i];
1146 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001147 else
1148 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001149 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001150 argv[0] = *basetv;
1151 for (i = 0; i < argcount; ++i)
1152 argv[i + 1] = argvars[i];
1153 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001154 argv[argcount + 1].v_type = VAR_UNKNOWN;
1155
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001156 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001157 return ERROR_NONE;
1158}
1159
1160/*
1161 * Return TRUE for a non-zero Number and a non-empty String.
1162 */
1163 static int
1164non_zero_arg(typval_T *argvars)
1165{
1166 return ((argvars[0].v_type == VAR_NUMBER
1167 && argvars[0].vval.v_number != 0)
1168 || (argvars[0].v_type == VAR_SPECIAL
1169 && argvars[0].vval.v_number == VVAL_TRUE)
1170 || (argvars[0].v_type == VAR_STRING
1171 && argvars[0].vval.v_string != NULL
1172 && *argvars[0].vval.v_string != NUL));
1173}
1174
1175/*
1176 * Get the lnum from the first argument.
1177 * Also accepts ".", "$", etc., but that only works for the current buffer.
1178 * Returns -1 on error.
1179 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001180 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001181tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001182{
1183 typval_T rettv;
1184 linenr_T lnum;
1185
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001186 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001187 if (lnum == 0) /* no valid number, try using line() */
1188 {
1189 rettv.v_type = VAR_NUMBER;
1190 f_line(argvars, &rettv);
1191 lnum = (linenr_T)rettv.vval.v_number;
1192 clear_tv(&rettv);
1193 }
1194 return lnum;
1195}
1196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001197/*
1198 * Get the lnum from the first argument.
1199 * Also accepts "$", then "buf" is used.
1200 * Returns 0 on error.
1201 */
1202 static linenr_T
1203tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1204{
1205 if (argvars[0].v_type == VAR_STRING
1206 && argvars[0].vval.v_string != NULL
1207 && argvars[0].vval.v_string[0] == '$'
1208 && buf != NULL)
1209 return buf->b_ml.ml_line_count;
1210 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1211}
1212
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001213#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001214/*
1215 * Get the float value of "argvars[0]" into "f".
1216 * Returns FAIL when the argument is not a Number or Float.
1217 */
1218 static int
1219get_float_arg(typval_T *argvars, float_T *f)
1220{
1221 if (argvars[0].v_type == VAR_FLOAT)
1222 {
1223 *f = argvars[0].vval.v_float;
1224 return OK;
1225 }
1226 if (argvars[0].v_type == VAR_NUMBER)
1227 {
1228 *f = (float_T)argvars[0].vval.v_number;
1229 return OK;
1230 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001231 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001232 return FAIL;
1233}
1234
1235/*
1236 * "abs(expr)" function
1237 */
1238 static void
1239f_abs(typval_T *argvars, typval_T *rettv)
1240{
1241 if (argvars[0].v_type == VAR_FLOAT)
1242 {
1243 rettv->v_type = VAR_FLOAT;
1244 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1245 }
1246 else
1247 {
1248 varnumber_T n;
1249 int error = FALSE;
1250
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001251 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252 if (error)
1253 rettv->vval.v_number = -1;
1254 else if (n > 0)
1255 rettv->vval.v_number = n;
1256 else
1257 rettv->vval.v_number = -n;
1258 }
1259}
1260
1261/*
1262 * "acos()" function
1263 */
1264 static void
1265f_acos(typval_T *argvars, typval_T *rettv)
1266{
1267 float_T f = 0.0;
1268
1269 rettv->v_type = VAR_FLOAT;
1270 if (get_float_arg(argvars, &f) == OK)
1271 rettv->vval.v_float = acos(f);
1272 else
1273 rettv->vval.v_float = 0.0;
1274}
1275#endif
1276
1277/*
1278 * "add(list, item)" function
1279 */
1280 static void
1281f_add(typval_T *argvars, typval_T *rettv)
1282{
1283 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001284 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001285
1286 rettv->vval.v_number = 1; /* Default: Failed */
1287 if (argvars[0].v_type == VAR_LIST)
1288 {
1289 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001290 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001291 (char_u *)N_("add() argument"), TRUE)
1292 && list_append_tv(l, &argvars[1]) == OK)
1293 copy_tv(&argvars[0], rettv);
1294 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001295 else if (argvars[0].v_type == VAR_BLOB)
1296 {
1297 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001298 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001299 (char_u *)N_("add() argument"), TRUE))
1300 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001301 int error = FALSE;
1302 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1303
1304 if (!error)
1305 {
1306 ga_append(&b->bv_ga, (int)n);
1307 copy_tv(&argvars[0], rettv);
1308 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001309 }
1310 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001311 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001312 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313}
1314
1315/*
1316 * "and(expr, expr)" function
1317 */
1318 static void
1319f_and(typval_T *argvars, typval_T *rettv)
1320{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001321 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1322 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001323}
1324
1325/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001326 * If there is a window for "curbuf", make it the current window.
1327 */
1328 static void
1329find_win_for_curbuf(void)
1330{
1331 wininfo_T *wip;
1332
1333 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1334 {
1335 if (wip->wi_win != NULL)
1336 {
1337 curwin = wip->wi_win;
1338 break;
1339 }
1340 }
1341}
1342
1343/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001344 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001345 */
1346 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001347set_buffer_lines(
1348 buf_T *buf,
1349 linenr_T lnum_arg,
1350 int append,
1351 typval_T *lines,
1352 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353{
Bram Moolenaarca851592018-06-06 21:04:07 +02001354 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1355 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001356 list_T *l = NULL;
1357 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001359 linenr_T append_lnum;
1360 buf_T *curbuf_save = NULL;
1361 win_T *curwin_save = NULL;
1362 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001363
Bram Moolenaarca851592018-06-06 21:04:07 +02001364 /* When using the current buffer ml_mfp will be set if needed. Useful when
1365 * setline() is used on startup. For other buffers the buffer must be
1366 * loaded. */
1367 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001368 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001369 rettv->vval.v_number = 1; /* FAIL */
1370 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001371 }
1372
Bram Moolenaarca851592018-06-06 21:04:07 +02001373 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001374 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001375 curbuf_save = curbuf;
1376 curwin_save = curwin;
1377 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001378 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001379 }
1380
1381 if (append)
1382 // appendbufline() uses the line number below which we insert
1383 append_lnum = lnum - 1;
1384 else
1385 // setbufline() uses the line number above which we insert, we only
1386 // append if it's below the last line
1387 append_lnum = curbuf->b_ml.ml_line_count;
1388
1389 if (lines->v_type == VAR_LIST)
1390 {
1391 l = lines->vval.v_list;
1392 li = l->lv_first;
1393 }
1394 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001395 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001396
1397 /* default result is zero == OK */
1398 for (;;)
1399 {
1400 if (l != NULL)
1401 {
1402 /* list argument, get next string */
1403 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001404 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001405 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001406 li = li->li_next;
1407 }
1408
Bram Moolenaarca851592018-06-06 21:04:07 +02001409 rettv->vval.v_number = 1; /* FAIL */
1410 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1411 break;
1412
1413 /* When coming here from Insert mode, sync undo, so that this can be
1414 * undone separately from what was previously inserted. */
1415 if (u_sync_once == 2)
1416 {
1417 u_sync_once = 1; /* notify that u_sync() was called */
1418 u_sync(TRUE);
1419 }
1420
1421 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1422 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001423 // Existing line, replace it.
1424 // Removes any existing text properties.
1425 if (u_savesub(lnum) == OK && ml_replace_len(
1426 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001427 {
1428 changed_bytes(lnum, 0);
1429 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1430 check_cursor_col();
1431 rettv->vval.v_number = 0; /* OK */
1432 }
1433 }
1434 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1435 {
1436 /* append the line */
1437 ++added;
1438 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1439 rettv->vval.v_number = 0; /* OK */
1440 }
1441
1442 if (l == NULL) /* only one string argument */
1443 break;
1444 ++lnum;
1445 }
1446
1447 if (added > 0)
1448 {
1449 win_T *wp;
1450 tabpage_T *tp;
1451
1452 appended_lines_mark(append_lnum, added);
1453 FOR_ALL_TAB_WINDOWS(tp, wp)
1454 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1455 wp->w_cursor.lnum += added;
1456 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001457 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001458 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001459
1460 if (!is_curbuf)
1461 {
1462 curbuf = curbuf_save;
1463 curwin = curwin_save;
1464 }
1465}
1466
1467/*
1468 * "append(lnum, string/list)" function
1469 */
1470 static void
1471f_append(typval_T *argvars, typval_T *rettv)
1472{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001473 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001474
1475 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1476}
1477
1478/*
1479 * "appendbufline(buf, lnum, string/list)" function
1480 */
1481 static void
1482f_appendbufline(typval_T *argvars, typval_T *rettv)
1483{
1484 linenr_T lnum;
1485 buf_T *buf;
1486
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001487 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001488 if (buf == NULL)
1489 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001490 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001491 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001492 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001493 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1494 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495}
1496
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497#ifdef FEAT_FLOAT
1498/*
1499 * "asin()" function
1500 */
1501 static void
1502f_asin(typval_T *argvars, typval_T *rettv)
1503{
1504 float_T f = 0.0;
1505
1506 rettv->v_type = VAR_FLOAT;
1507 if (get_float_arg(argvars, &f) == OK)
1508 rettv->vval.v_float = asin(f);
1509 else
1510 rettv->vval.v_float = 0.0;
1511}
1512
1513/*
1514 * "atan()" function
1515 */
1516 static void
1517f_atan(typval_T *argvars, typval_T *rettv)
1518{
1519 float_T f = 0.0;
1520
1521 rettv->v_type = VAR_FLOAT;
1522 if (get_float_arg(argvars, &f) == OK)
1523 rettv->vval.v_float = atan(f);
1524 else
1525 rettv->vval.v_float = 0.0;
1526}
1527
1528/*
1529 * "atan2()" function
1530 */
1531 static void
1532f_atan2(typval_T *argvars, typval_T *rettv)
1533{
1534 float_T fx = 0.0, fy = 0.0;
1535
1536 rettv->v_type = VAR_FLOAT;
1537 if (get_float_arg(argvars, &fx) == OK
1538 && get_float_arg(&argvars[1], &fy) == OK)
1539 rettv->vval.v_float = atan2(fx, fy);
1540 else
1541 rettv->vval.v_float = 0.0;
1542}
1543#endif
1544
1545/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001546 * "balloon_show()" function
1547 */
1548#ifdef FEAT_BEVAL
1549 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001550f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1551{
1552 rettv->v_type = VAR_STRING;
1553 if (balloonEval != NULL)
1554 {
1555 if (balloonEval->msg == NULL)
1556 rettv->vval.v_string = NULL;
1557 else
1558 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1559 }
1560}
1561
1562 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001563f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1564{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001565 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001566 {
1567 if (argvars[0].v_type == VAR_LIST
1568# ifdef FEAT_GUI
1569 && !gui.in_use
1570# endif
1571 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001572 {
1573 list_T *l = argvars[0].vval.v_list;
1574
1575 // empty list removes the balloon
1576 post_balloon(balloonEval, NULL,
1577 l == NULL || l->lv_len == 0 ? NULL : l);
1578 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001579 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001580 {
1581 char_u *mesg = tv_get_string_chk(&argvars[0]);
1582
1583 if (mesg != NULL)
1584 // empty string removes the balloon
1585 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1586 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001587 }
1588}
1589
Bram Moolenaar669a8282017-11-19 20:13:05 +01001590# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001591 static void
1592f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1593{
1594 if (rettv_list_alloc(rettv) == OK)
1595 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001596 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001597
1598 if (msg != NULL)
1599 {
1600 pumitem_T *array;
1601 int size = split_message(msg, &array);
1602 int i;
1603
1604 /* Skip the first and last item, they are always empty. */
1605 for (i = 1; i < size - 1; ++i)
1606 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001607 while (size > 0)
1608 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001609 vim_free(array);
1610 }
1611 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001612}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001613# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001614#endif
1615
1616/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001617 * "browse(save, title, initdir, default)" function
1618 */
1619 static void
1620f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1621{
1622#ifdef FEAT_BROWSE
1623 int save;
1624 char_u *title;
1625 char_u *initdir;
1626 char_u *defname;
1627 char_u buf[NUMBUFLEN];
1628 char_u buf2[NUMBUFLEN];
1629 int error = FALSE;
1630
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001631 save = (int)tv_get_number_chk(&argvars[0], &error);
1632 title = tv_get_string_chk(&argvars[1]);
1633 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1634 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635
1636 if (error || title == NULL || initdir == NULL || defname == NULL)
1637 rettv->vval.v_string = NULL;
1638 else
1639 rettv->vval.v_string =
1640 do_browse(save ? BROWSE_SAVE : 0,
1641 title, defname, NULL, initdir, NULL, curbuf);
1642#else
1643 rettv->vval.v_string = NULL;
1644#endif
1645 rettv->v_type = VAR_STRING;
1646}
1647
1648/*
1649 * "browsedir(title, initdir)" function
1650 */
1651 static void
1652f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1653{
1654#ifdef FEAT_BROWSE
1655 char_u *title;
1656 char_u *initdir;
1657 char_u buf[NUMBUFLEN];
1658
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001659 title = tv_get_string_chk(&argvars[0]);
1660 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661
1662 if (title == NULL || initdir == NULL)
1663 rettv->vval.v_string = NULL;
1664 else
1665 rettv->vval.v_string = do_browse(BROWSE_DIR,
1666 title, NULL, NULL, initdir, NULL, curbuf);
1667#else
1668 rettv->vval.v_string = NULL;
1669#endif
1670 rettv->v_type = VAR_STRING;
1671}
1672
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673/*
1674 * Find a buffer by number or exact name.
1675 */
1676 static buf_T *
1677find_buffer(typval_T *avar)
1678{
1679 buf_T *buf = NULL;
1680
1681 if (avar->v_type == VAR_NUMBER)
1682 buf = buflist_findnr((int)avar->vval.v_number);
1683 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1684 {
1685 buf = buflist_findname_exp(avar->vval.v_string);
1686 if (buf == NULL)
1687 {
1688 /* No full path name match, try a match with a URL or a "nofile"
1689 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001690 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691 if (buf->b_fname != NULL
1692 && (path_with_url(buf->b_fname)
1693#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001694 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695#endif
1696 )
1697 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1698 break;
1699 }
1700 }
1701 return buf;
1702}
1703
1704/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001705 * "bufadd(expr)" function
1706 */
1707 static void
1708f_bufadd(typval_T *argvars, typval_T *rettv)
1709{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001710 char_u *name = tv_get_string(&argvars[0]);
1711
1712 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001713}
1714
1715/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 * "bufexists(expr)" function
1717 */
1718 static void
1719f_bufexists(typval_T *argvars, typval_T *rettv)
1720{
1721 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1722}
1723
1724/*
1725 * "buflisted(expr)" function
1726 */
1727 static void
1728f_buflisted(typval_T *argvars, typval_T *rettv)
1729{
1730 buf_T *buf;
1731
1732 buf = find_buffer(&argvars[0]);
1733 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1734}
1735
1736/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001737 * "bufload(expr)" function
1738 */
1739 static void
1740f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1741{
1742 buf_T *buf = get_buf_arg(&argvars[0]);
1743
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001744 if (buf != NULL)
1745 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001746}
1747
1748/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001749 * "bufloaded(expr)" function
1750 */
1751 static void
1752f_bufloaded(typval_T *argvars, typval_T *rettv)
1753{
1754 buf_T *buf;
1755
1756 buf = find_buffer(&argvars[0]);
1757 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1758}
1759
1760 buf_T *
1761buflist_find_by_name(char_u *name, int curtab_only)
1762{
1763 int save_magic;
1764 char_u *save_cpo;
1765 buf_T *buf;
1766
1767 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1768 save_magic = p_magic;
1769 p_magic = TRUE;
1770 save_cpo = p_cpo;
1771 p_cpo = (char_u *)"";
1772
1773 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1774 TRUE, FALSE, curtab_only));
1775
1776 p_magic = save_magic;
1777 p_cpo = save_cpo;
1778 return buf;
1779}
1780
1781/*
1782 * Get buffer by number or pattern.
1783 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001784 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001785tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001786{
1787 char_u *name = tv->vval.v_string;
1788 buf_T *buf;
1789
1790 if (tv->v_type == VAR_NUMBER)
1791 return buflist_findnr((int)tv->vval.v_number);
1792 if (tv->v_type != VAR_STRING)
1793 return NULL;
1794 if (name == NULL || *name == NUL)
1795 return curbuf;
1796 if (name[0] == '$' && name[1] == NUL)
1797 return lastbuf;
1798
1799 buf = buflist_find_by_name(name, curtab_only);
1800
1801 /* If not found, try expanding the name, like done for bufexists(). */
1802 if (buf == NULL)
1803 buf = find_buffer(tv);
1804
1805 return buf;
1806}
1807
1808/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001809 * Get the buffer from "arg" and give an error and return NULL if it is not
1810 * valid.
1811 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001812 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001813get_buf_arg(typval_T *arg)
1814{
1815 buf_T *buf;
1816
1817 ++emsg_off;
1818 buf = tv_get_buf(arg, FALSE);
1819 --emsg_off;
1820 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001821 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001822 return buf;
1823}
1824
1825/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001826 * "bufname(expr)" function
1827 */
1828 static void
1829f_bufname(typval_T *argvars, typval_T *rettv)
1830{
1831 buf_T *buf;
1832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001833 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001835 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001836 rettv->v_type = VAR_STRING;
1837 if (buf != NULL && buf->b_fname != NULL)
1838 rettv->vval.v_string = vim_strsave(buf->b_fname);
1839 else
1840 rettv->vval.v_string = NULL;
1841 --emsg_off;
1842}
1843
1844/*
1845 * "bufnr(expr)" function
1846 */
1847 static void
1848f_bufnr(typval_T *argvars, typval_T *rettv)
1849{
1850 buf_T *buf;
1851 int error = FALSE;
1852 char_u *name;
1853
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001854 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001855 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001856 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001857 --emsg_off;
1858
1859 /* If the buffer isn't found and the second argument is not zero create a
1860 * new buffer. */
1861 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
4704#if defined(FEAT_CMDL_COMPL)
4705/*
4706 * "getcompletion()" function
4707 */
4708 static void
4709f_getcompletion(typval_T *argvars, typval_T *rettv)
4710{
4711 char_u *pat;
4712 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004713 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004714 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4715 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004716
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004717 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004718 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004719
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004720 if (p_wic)
4721 options |= WILD_ICASE;
4722
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004723 /* For filtered results, 'wildignore' is used */
4724 if (!filtered)
4725 options |= WILD_KEEP_ALL;
4726
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004727 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004728 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004730 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004731 if (xpc.xp_context == EXPAND_NOTHING)
4732 {
4733 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004734 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004736 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 return;
4738 }
4739
4740# if defined(FEAT_MENU)
4741 if (xpc.xp_context == EXPAND_MENUS)
4742 {
4743 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4744 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4745 }
4746# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004747#ifdef FEAT_CSCOPE
4748 if (xpc.xp_context == EXPAND_CSCOPE)
4749 {
4750 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4751 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4752 }
4753#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004754#ifdef FEAT_SIGNS
4755 if (xpc.xp_context == EXPAND_SIGN)
4756 {
4757 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4758 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4759 }
4760#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004761
4762 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4763 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4764 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004765 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766
4767 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4768
4769 for (i = 0; i < xpc.xp_numfiles; i++)
4770 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4771 }
4772 vim_free(pat);
4773 ExpandCleanup(&xpc);
4774}
4775#endif
4776
4777/*
4778 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004779 *
4780 * Return the current working directory of a window in a tab page.
4781 * First optional argument 'winnr' is the window number or -1 and the second
4782 * optional argument 'tabnr' is the tab page number.
4783 *
4784 * If no arguments are supplied, then return the directory of the current
4785 * window.
4786 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4787 * the specified window.
4788 * If 'winnr' is 0 then return the directory of the current window.
4789 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4790 * directory of the specified tab page. Otherwise return the directory of the
4791 * specified window in the specified tab page.
4792 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004793 */
4794 static void
4795f_getcwd(typval_T *argvars, typval_T *rettv)
4796{
4797 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004798 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004799 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004800 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004801
4802 rettv->v_type = VAR_STRING;
4803 rettv->vval.v_string = NULL;
4804
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004805 if (argvars[0].v_type == VAR_NUMBER
4806 && argvars[0].vval.v_number == -1
4807 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004808 global = TRUE;
4809 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004810 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004811
4812 if (wp != NULL && wp->w_localdir != NULL)
4813 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004814 else if (tp != NULL && tp->tp_localdir != NULL)
4815 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4816 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004817 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004818 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004819 rettv->vval.v_string = vim_strsave(globaldir);
4820 else
4821 {
4822 cwd = alloc(MAXPATHL);
4823 if (cwd != NULL)
4824 {
4825 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4826 rettv->vval.v_string = vim_strsave(cwd);
4827 vim_free(cwd);
4828 }
4829 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004830 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004831#ifdef BACKSLASH_IN_FILENAME
4832 if (rettv->vval.v_string != NULL)
4833 slash_adjust(rettv->vval.v_string);
4834#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004835}
4836
4837/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004838 * "getenv()" function
4839 */
4840 static void
4841f_getenv(typval_T *argvars, typval_T *rettv)
4842{
4843 int mustfree = FALSE;
4844 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4845
4846 if (p == NULL)
4847 {
4848 rettv->v_type = VAR_SPECIAL;
4849 rettv->vval.v_number = VVAL_NULL;
4850 return;
4851 }
4852 if (!mustfree)
4853 p = vim_strsave(p);
4854 rettv->vval.v_string = p;
4855 rettv->v_type = VAR_STRING;
4856}
4857
4858/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 * "getfontname()" function
4860 */
4861 static void
4862f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4863{
4864 rettv->v_type = VAR_STRING;
4865 rettv->vval.v_string = NULL;
4866#ifdef FEAT_GUI
4867 if (gui.in_use)
4868 {
4869 GuiFont font;
4870 char_u *name = NULL;
4871
4872 if (argvars[0].v_type == VAR_UNKNOWN)
4873 {
4874 /* Get the "Normal" font. Either the name saved by
4875 * hl_set_font_name() or from the font ID. */
4876 font = gui.norm_font;
4877 name = hl_get_font_name();
4878 }
4879 else
4880 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004881 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004882 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4883 return;
4884 font = gui_mch_get_font(name, FALSE);
4885 if (font == NOFONT)
4886 return; /* Invalid font name, return empty string. */
4887 }
4888 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4889 if (argvars[0].v_type != VAR_UNKNOWN)
4890 gui_mch_free_font(font);
4891 }
4892#endif
4893}
4894
4895/*
4896 * "getfperm({fname})" function
4897 */
4898 static void
4899f_getfperm(typval_T *argvars, typval_T *rettv)
4900{
4901 char_u *fname;
4902 stat_T st;
4903 char_u *perm = NULL;
4904 char_u flags[] = "rwx";
4905 int i;
4906
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004907 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908
4909 rettv->v_type = VAR_STRING;
4910 if (mch_stat((char *)fname, &st) >= 0)
4911 {
4912 perm = vim_strsave((char_u *)"---------");
4913 if (perm != NULL)
4914 {
4915 for (i = 0; i < 9; i++)
4916 {
4917 if (st.st_mode & (1 << (8 - i)))
4918 perm[i] = flags[i % 3];
4919 }
4920 }
4921 }
4922 rettv->vval.v_string = perm;
4923}
4924
4925/*
4926 * "getfsize({fname})" function
4927 */
4928 static void
4929f_getfsize(typval_T *argvars, typval_T *rettv)
4930{
4931 char_u *fname;
4932 stat_T st;
4933
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004934 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935
4936 rettv->v_type = VAR_NUMBER;
4937
4938 if (mch_stat((char *)fname, &st) >= 0)
4939 {
4940 if (mch_isdir(fname))
4941 rettv->vval.v_number = 0;
4942 else
4943 {
4944 rettv->vval.v_number = (varnumber_T)st.st_size;
4945
4946 /* non-perfect check for overflow */
4947 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4948 rettv->vval.v_number = -2;
4949 }
4950 }
4951 else
4952 rettv->vval.v_number = -1;
4953}
4954
4955/*
4956 * "getftime({fname})" function
4957 */
4958 static void
4959f_getftime(typval_T *argvars, typval_T *rettv)
4960{
4961 char_u *fname;
4962 stat_T st;
4963
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004964 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965
4966 if (mch_stat((char *)fname, &st) >= 0)
4967 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4968 else
4969 rettv->vval.v_number = -1;
4970}
4971
4972/*
4973 * "getftype({fname})" function
4974 */
4975 static void
4976f_getftype(typval_T *argvars, typval_T *rettv)
4977{
4978 char_u *fname;
4979 stat_T st;
4980 char_u *type = NULL;
4981 char *t;
4982
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004983 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984
4985 rettv->v_type = VAR_STRING;
4986 if (mch_lstat((char *)fname, &st) >= 0)
4987 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004988 if (S_ISREG(st.st_mode))
4989 t = "file";
4990 else if (S_ISDIR(st.st_mode))
4991 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004992 else if (S_ISLNK(st.st_mode))
4993 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004994 else if (S_ISBLK(st.st_mode))
4995 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004996 else if (S_ISCHR(st.st_mode))
4997 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004998 else if (S_ISFIFO(st.st_mode))
4999 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005001 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005002 else
5003 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005004 type = vim_strsave((char_u *)t);
5005 }
5006 rettv->vval.v_string = type;
5007}
5008
5009/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005010 * "getjumplist()" function
5011 */
5012 static void
5013f_getjumplist(typval_T *argvars, typval_T *rettv)
5014{
5015#ifdef FEAT_JUMPLIST
5016 win_T *wp;
5017 int i;
5018 list_T *l;
5019 dict_T *d;
5020#endif
5021
5022 if (rettv_list_alloc(rettv) != OK)
5023 return;
5024
5025#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005026 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005027 if (wp == NULL)
5028 return;
5029
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005030 cleanup_jumplist(wp, TRUE);
5031
Bram Moolenaar4f505882018-02-10 21:06:32 +01005032 l = list_alloc();
5033 if (l == NULL)
5034 return;
5035
5036 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5037 return;
5038 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5039
5040 for (i = 0; i < wp->w_jumplistlen; ++i)
5041 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005042 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5043 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005044 if ((d = dict_alloc()) == NULL)
5045 return;
5046 if (list_append_dict(l, d) == FAIL)
5047 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005048 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5049 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005050 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005051 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005052 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005053 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005054 }
5055#endif
5056}
5057
5058/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005059 * "getline(lnum, [end])" function
5060 */
5061 static void
5062f_getline(typval_T *argvars, typval_T *rettv)
5063{
5064 linenr_T lnum;
5065 linenr_T end;
5066 int retlist;
5067
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005068 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005069 if (argvars[1].v_type == VAR_UNKNOWN)
5070 {
5071 end = 0;
5072 retlist = FALSE;
5073 }
5074 else
5075 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005076 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 retlist = TRUE;
5078 }
5079
5080 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5081}
5082
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005083#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005084 static void
5085get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5086{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005087 if (what_arg->v_type == VAR_UNKNOWN)
5088 {
5089 if (rettv_list_alloc(rettv) == OK)
5090 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005091 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005092 }
5093 else
5094 {
5095 if (rettv_dict_alloc(rettv) == OK)
5096 if (is_qf || (wp != NULL))
5097 {
5098 if (what_arg->v_type == VAR_DICT)
5099 {
5100 dict_T *d = what_arg->vval.v_dict;
5101
5102 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005103 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005104 }
5105 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005106 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005107 }
5108 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005109}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005110#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005111
5112/*
5113 * "getloclist()" function
5114 */
5115 static void
5116f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5117{
5118#ifdef FEAT_QUICKFIX
5119 win_T *wp;
5120
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005121 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005122 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5123#endif
5124}
5125
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005126/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127 * "getpid()" function
5128 */
5129 static void
5130f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5131{
5132 rettv->vval.v_number = mch_get_pid();
5133}
5134
5135 static void
5136getpos_both(
5137 typval_T *argvars,
5138 typval_T *rettv,
5139 int getcurpos)
5140{
5141 pos_T *fp;
5142 list_T *l;
5143 int fnum = -1;
5144
5145 if (rettv_list_alloc(rettv) == OK)
5146 {
5147 l = rettv->vval.v_list;
5148 if (getcurpos)
5149 fp = &curwin->w_cursor;
5150 else
5151 fp = var2fpos(&argvars[0], TRUE, &fnum);
5152 if (fnum != -1)
5153 list_append_number(l, (varnumber_T)fnum);
5154 else
5155 list_append_number(l, (varnumber_T)0);
5156 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5157 : (varnumber_T)0);
5158 list_append_number(l, (fp != NULL)
5159 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5160 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005161 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005162 (varnumber_T)0);
5163 if (getcurpos)
5164 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005165 int save_set_curswant = curwin->w_set_curswant;
5166 colnr_T save_curswant = curwin->w_curswant;
5167 colnr_T save_virtcol = curwin->w_virtcol;
5168
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005169 update_curswant();
5170 list_append_number(l, curwin->w_curswant == MAXCOL ?
5171 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005172
5173 // Do not change "curswant", as it is unexpected that a get
5174 // function has a side effect.
5175 if (save_set_curswant)
5176 {
5177 curwin->w_set_curswant = save_set_curswant;
5178 curwin->w_curswant = save_curswant;
5179 curwin->w_virtcol = save_virtcol;
5180 curwin->w_valid &= ~VALID_VIRTCOL;
5181 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005182 }
5183 }
5184 else
5185 rettv->vval.v_number = FALSE;
5186}
5187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005188/*
5189 * "getcurpos()" function
5190 */
5191 static void
5192f_getcurpos(typval_T *argvars, typval_T *rettv)
5193{
5194 getpos_both(argvars, rettv, TRUE);
5195}
5196
5197/*
5198 * "getpos(string)" function
5199 */
5200 static void
5201f_getpos(typval_T *argvars, typval_T *rettv)
5202{
5203 getpos_both(argvars, rettv, FALSE);
5204}
5205
5206/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005207 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005208 */
5209 static void
5210f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5211{
5212#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005213 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005214#endif
5215}
5216
5217/*
5218 * "getreg()" function
5219 */
5220 static void
5221f_getreg(typval_T *argvars, typval_T *rettv)
5222{
5223 char_u *strregname;
5224 int regname;
5225 int arg2 = FALSE;
5226 int return_list = FALSE;
5227 int error = FALSE;
5228
5229 if (argvars[0].v_type != VAR_UNKNOWN)
5230 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005231 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005232 error = strregname == NULL;
5233 if (argvars[1].v_type != VAR_UNKNOWN)
5234 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005235 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005236 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005237 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005238 }
5239 }
5240 else
5241 strregname = get_vim_var_str(VV_REG);
5242
5243 if (error)
5244 return;
5245
5246 regname = (strregname == NULL ? '"' : *strregname);
5247 if (regname == 0)
5248 regname = '"';
5249
5250 if (return_list)
5251 {
5252 rettv->v_type = VAR_LIST;
5253 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5254 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5255 if (rettv->vval.v_list == NULL)
5256 (void)rettv_list_alloc(rettv);
5257 else
5258 ++rettv->vval.v_list->lv_refcount;
5259 }
5260 else
5261 {
5262 rettv->v_type = VAR_STRING;
5263 rettv->vval.v_string = get_reg_contents(regname,
5264 arg2 ? GREG_EXPR_SRC : 0);
5265 }
5266}
5267
5268/*
5269 * "getregtype()" function
5270 */
5271 static void
5272f_getregtype(typval_T *argvars, typval_T *rettv)
5273{
5274 char_u *strregname;
5275 int regname;
5276 char_u buf[NUMBUFLEN + 2];
5277 long reglen = 0;
5278
5279 if (argvars[0].v_type != VAR_UNKNOWN)
5280 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005281 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005282 if (strregname == NULL) /* type error; errmsg already given */
5283 {
5284 rettv->v_type = VAR_STRING;
5285 rettv->vval.v_string = NULL;
5286 return;
5287 }
5288 }
5289 else
5290 /* Default to v:register */
5291 strregname = get_vim_var_str(VV_REG);
5292
5293 regname = (strregname == NULL ? '"' : *strregname);
5294 if (regname == 0)
5295 regname = '"';
5296
5297 buf[0] = NUL;
5298 buf[1] = NUL;
5299 switch (get_reg_type(regname, &reglen))
5300 {
5301 case MLINE: buf[0] = 'V'; break;
5302 case MCHAR: buf[0] = 'v'; break;
5303 case MBLOCK:
5304 buf[0] = Ctrl_V;
5305 sprintf((char *)buf + 1, "%ld", reglen + 1);
5306 break;
5307 }
5308 rettv->v_type = VAR_STRING;
5309 rettv->vval.v_string = vim_strsave(buf);
5310}
5311
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005312/*
5313 * Returns information (variables, options, etc.) about a tab page
5314 * as a dictionary.
5315 */
5316 static dict_T *
5317get_tabpage_info(tabpage_T *tp, int tp_idx)
5318{
5319 win_T *wp;
5320 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005321 list_T *l;
5322
5323 dict = dict_alloc();
5324 if (dict == NULL)
5325 return NULL;
5326
Bram Moolenaare0be1672018-07-08 16:50:37 +02005327 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005328
5329 l = list_alloc();
5330 if (l != NULL)
5331 {
5332 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005333 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005334 list_append_number(l, (varnumber_T)wp->w_id);
5335 dict_add_list(dict, "windows", l);
5336 }
5337
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005338 /* Make a reference to tabpage variables */
5339 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005340
5341 return dict;
5342}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005343
5344/*
5345 * "gettabinfo()" function
5346 */
5347 static void
5348f_gettabinfo(typval_T *argvars, typval_T *rettv)
5349{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005350 tabpage_T *tp, *tparg = NULL;
5351 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005352 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005353
5354 if (rettv_list_alloc(rettv) != OK)
5355 return;
5356
5357 if (argvars[0].v_type != VAR_UNKNOWN)
5358 {
5359 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005360 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005361 if (tparg == NULL)
5362 return;
5363 }
5364
5365 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005366 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005367 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005368 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005369 if (tparg != NULL && tp != tparg)
5370 continue;
5371 d = get_tabpage_info(tp, tpnr);
5372 if (d != NULL)
5373 list_append_dict(rettv->vval.v_list, d);
5374 if (tparg != NULL)
5375 return;
5376 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005377}
5378
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379/*
5380 * "gettabvar()" function
5381 */
5382 static void
5383f_gettabvar(typval_T *argvars, typval_T *rettv)
5384{
5385 win_T *oldcurwin;
5386 tabpage_T *tp, *oldtabpage;
5387 dictitem_T *v;
5388 char_u *varname;
5389 int done = FALSE;
5390
5391 rettv->v_type = VAR_STRING;
5392 rettv->vval.v_string = NULL;
5393
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005394 varname = tv_get_string_chk(&argvars[1]);
5395 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005396 if (tp != NULL && varname != NULL)
5397 {
5398 /* Set tp to be our tabpage, temporarily. Also set the window to the
5399 * first window in the tabpage, otherwise the window is not valid. */
5400 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005401 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5402 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005403 {
5404 /* look up the variable */
5405 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5406 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5407 if (v != NULL)
5408 {
5409 copy_tv(&v->di_tv, rettv);
5410 done = TRUE;
5411 }
5412 }
5413
5414 /* restore previous notion of curwin */
5415 restore_win(oldcurwin, oldtabpage, TRUE);
5416 }
5417
5418 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5419 copy_tv(&argvars[2], rettv);
5420}
5421
5422/*
5423 * "gettabwinvar()" function
5424 */
5425 static void
5426f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5427{
5428 getwinvar(argvars, rettv, 1);
5429}
5430
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005431/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005432 * "gettagstack()" function
5433 */
5434 static void
5435f_gettagstack(typval_T *argvars, typval_T *rettv)
5436{
5437 win_T *wp = curwin; // default is current window
5438
5439 if (rettv_dict_alloc(rettv) != OK)
5440 return;
5441
5442 if (argvars[0].v_type != VAR_UNKNOWN)
5443 {
5444 wp = find_win_by_nr_or_id(&argvars[0]);
5445 if (wp == NULL)
5446 return;
5447 }
5448
5449 get_tagstack(wp, rettv->vval.v_dict);
5450}
5451
5452/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005453 * Returns information about a window as a dictionary.
5454 */
5455 static dict_T *
5456get_win_info(win_T *wp, short tpnr, short winnr)
5457{
5458 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005459
5460 dict = dict_alloc();
5461 if (dict == NULL)
5462 return NULL;
5463
Bram Moolenaare0be1672018-07-08 16:50:37 +02005464 dict_add_number(dict, "tabnr", tpnr);
5465 dict_add_number(dict, "winnr", winnr);
5466 dict_add_number(dict, "winid", wp->w_id);
5467 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005468 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005469 dict_add_number(dict, "topline", wp->w_topline);
5470 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005471#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005472 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005473#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005474 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005475 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005476 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005477
Bram Moolenaar69905d12017-08-13 18:14:47 +02005478#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005479 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005480#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005481#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005482 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5483 dict_add_number(dict, "loclist",
5484 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005485#endif
5486
Bram Moolenaar30567352016-08-27 21:25:44 +02005487 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005488 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005489
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005490 return dict;
5491}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005492
5493/*
5494 * "getwininfo()" function
5495 */
5496 static void
5497f_getwininfo(typval_T *argvars, typval_T *rettv)
5498{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005499 tabpage_T *tp;
5500 win_T *wp = NULL, *wparg = NULL;
5501 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005502 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005503
5504 if (rettv_list_alloc(rettv) != OK)
5505 return;
5506
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005507 if (argvars[0].v_type != VAR_UNKNOWN)
5508 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005509 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005510 if (wparg == NULL)
5511 return;
5512 }
5513
5514 /* Collect information about either all the windows across all the tab
5515 * pages or one particular window.
5516 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005517 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005518 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005519 tabnr++;
5520 winnr = 0;
5521 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005522 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005523 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005524 if (wparg != NULL && wp != wparg)
5525 continue;
5526 d = get_win_info(wp, tabnr, winnr);
5527 if (d != NULL)
5528 list_append_dict(rettv->vval.v_list, d);
5529 if (wparg != NULL)
5530 /* found information about a specific window */
5531 return;
5532 }
5533 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005534}
5535
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005536/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005537 * "win_execute()" function
5538 */
5539 static void
5540f_win_execute(typval_T *argvars, typval_T *rettv)
5541{
5542 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005543 tabpage_T *tp;
5544 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005545 win_T *save_curwin;
5546 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005547
Bram Moolenaar820680b2019-08-09 14:56:22 +02005548 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005549 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005550 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005551 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005552 check_cursor();
5553 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005554 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005555 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005556 }
5557}
5558
5559/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005560 * "win_findbuf()" function
5561 */
5562 static void
5563f_win_findbuf(typval_T *argvars, typval_T *rettv)
5564{
5565 if (rettv_list_alloc(rettv) != FAIL)
5566 win_findbuf(argvars, rettv->vval.v_list);
5567}
5568
5569/*
5570 * "win_getid()" function
5571 */
5572 static void
5573f_win_getid(typval_T *argvars, typval_T *rettv)
5574{
5575 rettv->vval.v_number = win_getid(argvars);
5576}
5577
5578/*
5579 * "win_gotoid()" function
5580 */
5581 static void
5582f_win_gotoid(typval_T *argvars, typval_T *rettv)
5583{
5584 rettv->vval.v_number = win_gotoid(argvars);
5585}
5586
5587/*
5588 * "win_id2tabwin()" function
5589 */
5590 static void
5591f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5592{
5593 if (rettv_list_alloc(rettv) != FAIL)
5594 win_id2tabwin(argvars, rettv->vval.v_list);
5595}
5596
5597/*
5598 * "win_id2win()" function
5599 */
5600 static void
5601f_win_id2win(typval_T *argvars, typval_T *rettv)
5602{
5603 rettv->vval.v_number = win_id2win(argvars);
5604}
5605
5606/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005607 * "win_screenpos()" function
5608 */
5609 static void
5610f_win_screenpos(typval_T *argvars, typval_T *rettv)
5611{
5612 win_T *wp;
5613
5614 if (rettv_list_alloc(rettv) == FAIL)
5615 return;
5616
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005617 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005618 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5619 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5620}
5621
5622/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005623 * "getwinpos({timeout})" function
5624 */
5625 static void
5626f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5627{
5628 int x = -1;
5629 int y = -1;
5630
5631 if (rettv_list_alloc(rettv) == FAIL)
5632 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005633#if defined(FEAT_GUI) \
5634 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5635 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005636 {
5637 varnumber_T timeout = 100;
5638
5639 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005640 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005641
5642 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005643 }
5644#endif
5645 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5646 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5647}
5648
5649
5650/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005651 * "getwinposx()" function
5652 */
5653 static void
5654f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5655{
5656 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005657#if defined(FEAT_GUI) \
5658 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5659 || defined(MSWIN)
5660
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005661 {
5662 int x, y;
5663
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005664 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005665 rettv->vval.v_number = x;
5666 }
5667#endif
5668}
5669
5670/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671 * "getwinposy()" function
5672 */
5673 static void
5674f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5675{
5676 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005677#if defined(FEAT_GUI) \
5678 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5679 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005680 {
5681 int x, y;
5682
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005683 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005684 rettv->vval.v_number = y;
5685 }
5686#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005687}
5688
5689/*
5690 * "getwinvar()" function
5691 */
5692 static void
5693f_getwinvar(typval_T *argvars, typval_T *rettv)
5694{
5695 getwinvar(argvars, rettv, 0);
5696}
5697
5698/*
5699 * "glob()" function
5700 */
5701 static void
5702f_glob(typval_T *argvars, typval_T *rettv)
5703{
5704 int options = WILD_SILENT|WILD_USE_NL;
5705 expand_T xpc;
5706 int error = FALSE;
5707
5708 /* When the optional second argument is non-zero, don't remove matches
5709 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5710 rettv->v_type = VAR_STRING;
5711 if (argvars[1].v_type != VAR_UNKNOWN)
5712 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005713 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005714 options |= WILD_KEEP_ALL;
5715 if (argvars[2].v_type != VAR_UNKNOWN)
5716 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005717 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005718 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005719 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005720 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005721 options |= WILD_ALLLINKS;
5722 }
5723 }
5724 if (!error)
5725 {
5726 ExpandInit(&xpc);
5727 xpc.xp_context = EXPAND_FILES;
5728 if (p_wic)
5729 options += WILD_ICASE;
5730 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005731 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005732 NULL, options, WILD_ALL);
5733 else if (rettv_list_alloc(rettv) != FAIL)
5734 {
5735 int i;
5736
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005737 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005738 NULL, options, WILD_ALL_KEEP);
5739 for (i = 0; i < xpc.xp_numfiles; i++)
5740 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5741
5742 ExpandCleanup(&xpc);
5743 }
5744 }
5745 else
5746 rettv->vval.v_string = NULL;
5747}
5748
5749/*
5750 * "globpath()" function
5751 */
5752 static void
5753f_globpath(typval_T *argvars, typval_T *rettv)
5754{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005755 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005756 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005757 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005758 int error = FALSE;
5759 garray_T ga;
5760 int i;
5761
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005762 // When the optional second argument is non-zero, don't remove matches
5763 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005764 rettv->v_type = VAR_STRING;
5765 if (argvars[2].v_type != VAR_UNKNOWN)
5766 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005767 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005768 flags |= WILD_KEEP_ALL;
5769 if (argvars[3].v_type != VAR_UNKNOWN)
5770 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005771 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005772 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005773 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005774 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005775 flags |= WILD_ALLLINKS;
5776 }
5777 }
5778 if (file != NULL && !error)
5779 {
5780 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005781 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782 if (rettv->v_type == VAR_STRING)
5783 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5784 else if (rettv_list_alloc(rettv) != FAIL)
5785 for (i = 0; i < ga.ga_len; ++i)
5786 list_append_string(rettv->vval.v_list,
5787 ((char_u **)(ga.ga_data))[i], -1);
5788 ga_clear_strings(&ga);
5789 }
5790 else
5791 rettv->vval.v_string = NULL;
5792}
5793
5794/*
5795 * "glob2regpat()" function
5796 */
5797 static void
5798f_glob2regpat(typval_T *argvars, typval_T *rettv)
5799{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005800 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801
5802 rettv->v_type = VAR_STRING;
5803 rettv->vval.v_string = (pat == NULL)
5804 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5805}
5806
5807/* for VIM_VERSION_ defines */
5808#include "version.h"
5809
5810/*
5811 * "has()" function
5812 */
5813 static void
5814f_has(typval_T *argvars, typval_T *rettv)
5815{
5816 int i;
5817 char_u *name;
5818 int n = FALSE;
5819 static char *(has_list[]) =
5820 {
5821#ifdef AMIGA
5822 "amiga",
5823# ifdef FEAT_ARP
5824 "arp",
5825# endif
5826#endif
5827#ifdef __BEOS__
5828 "beos",
5829#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005830#if defined(BSD) && !defined(MACOS_X)
5831 "bsd",
5832#endif
5833#ifdef hpux
5834 "hpux",
5835#endif
5836#ifdef __linux__
5837 "linux",
5838#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005839#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005840 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5841 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005842# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005843 "macunix", /* Mac OS X, with the darwin feature */
5844 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005845# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005846#endif
5847#ifdef __QNX__
5848 "qnx",
5849#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005850#ifdef SUN_SYSTEM
5851 "sun",
5852#else
5853 "moon",
5854#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005855#ifdef UNIX
5856 "unix",
5857#endif
5858#ifdef VMS
5859 "vms",
5860#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005861#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005862 "win32",
5863#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005864#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005865 "win32unix",
5866#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005867#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 "win64",
5869#endif
5870#ifdef EBCDIC
5871 "ebcdic",
5872#endif
5873#ifndef CASE_INSENSITIVE_FILENAME
5874 "fname_case",
5875#endif
5876#ifdef HAVE_ACL
5877 "acl",
5878#endif
5879#ifdef FEAT_ARABIC
5880 "arabic",
5881#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005882 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005883#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005884 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005885#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005886#ifdef FEAT_AUTOSERVERNAME
5887 "autoservername",
5888#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005889#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005890 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01005891# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005892 "balloon_multiline",
5893# endif
5894#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005895#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005896 "balloon_eval_term",
5897#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005898#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5899 "builtin_terms",
5900# ifdef ALL_BUILTIN_TCAPS
5901 "all_builtin_terms",
5902# endif
5903#endif
5904#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01005905 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005906 || defined(FEAT_GUI_MOTIF))
5907 "browsefilter",
5908#endif
5909#ifdef FEAT_BYTEOFF
5910 "byte_offset",
5911#endif
5912#ifdef FEAT_JOB_CHANNEL
5913 "channel",
5914#endif
5915#ifdef FEAT_CINDENT
5916 "cindent",
5917#endif
5918#ifdef FEAT_CLIENTSERVER
5919 "clientserver",
5920#endif
5921#ifdef FEAT_CLIPBOARD
5922 "clipboard",
5923#endif
5924#ifdef FEAT_CMDL_COMPL
5925 "cmdline_compl",
5926#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005927 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005928#ifdef FEAT_COMMENTS
5929 "comments",
5930#endif
5931#ifdef FEAT_CONCEAL
5932 "conceal",
5933#endif
5934#ifdef FEAT_CRYPT
5935 "cryptv",
5936 "crypt-blowfish",
5937 "crypt-blowfish2",
5938#endif
5939#ifdef FEAT_CSCOPE
5940 "cscope",
5941#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005942 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005943#ifdef CURSOR_SHAPE
5944 "cursorshape",
5945#endif
5946#ifdef DEBUG
5947 "debug",
5948#endif
5949#ifdef FEAT_CON_DIALOG
5950 "dialog_con",
5951#endif
5952#ifdef FEAT_GUI_DIALOG
5953 "dialog_gui",
5954#endif
5955#ifdef FEAT_DIFF
5956 "diff",
5957#endif
5958#ifdef FEAT_DIGRAPHS
5959 "digraphs",
5960#endif
5961#ifdef FEAT_DIRECTX
5962 "directx",
5963#endif
5964#ifdef FEAT_DND
5965 "dnd",
5966#endif
5967#ifdef FEAT_EMACS_TAGS
5968 "emacs_tags",
5969#endif
5970 "eval", /* always present, of course! */
5971 "ex_extra", /* graduated feature */
5972#ifdef FEAT_SEARCH_EXTRA
5973 "extra_search",
5974#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975#ifdef FEAT_SEARCHPATH
5976 "file_in_path",
5977#endif
5978#ifdef FEAT_FILTERPIPE
5979 "filterpipe",
5980#endif
5981#ifdef FEAT_FIND_ID
5982 "find_in_path",
5983#endif
5984#ifdef FEAT_FLOAT
5985 "float",
5986#endif
5987#ifdef FEAT_FOLDING
5988 "folding",
5989#endif
5990#ifdef FEAT_FOOTER
5991 "footer",
5992#endif
5993#if !defined(USE_SYSTEM) && defined(UNIX)
5994 "fork",
5995#endif
5996#ifdef FEAT_GETTEXT
5997 "gettext",
5998#endif
5999#ifdef FEAT_GUI
6000 "gui",
6001#endif
6002#ifdef FEAT_GUI_ATHENA
6003# ifdef FEAT_GUI_NEXTAW
6004 "gui_neXtaw",
6005# else
6006 "gui_athena",
6007# endif
6008#endif
6009#ifdef FEAT_GUI_GTK
6010 "gui_gtk",
6011# ifdef USE_GTK3
6012 "gui_gtk3",
6013# else
6014 "gui_gtk2",
6015# endif
6016#endif
6017#ifdef FEAT_GUI_GNOME
6018 "gui_gnome",
6019#endif
6020#ifdef FEAT_GUI_MAC
6021 "gui_mac",
6022#endif
6023#ifdef FEAT_GUI_MOTIF
6024 "gui_motif",
6025#endif
6026#ifdef FEAT_GUI_PHOTON
6027 "gui_photon",
6028#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006029#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030 "gui_win32",
6031#endif
6032#ifdef FEAT_HANGULIN
6033 "hangul_input",
6034#endif
6035#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6036 "iconv",
6037#endif
6038#ifdef FEAT_INS_EXPAND
6039 "insert_expand",
6040#endif
6041#ifdef FEAT_JOB_CHANNEL
6042 "job",
6043#endif
6044#ifdef FEAT_JUMPLIST
6045 "jumplist",
6046#endif
6047#ifdef FEAT_KEYMAP
6048 "keymap",
6049#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006050 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006051#ifdef FEAT_LANGMAP
6052 "langmap",
6053#endif
6054#ifdef FEAT_LIBCALL
6055 "libcall",
6056#endif
6057#ifdef FEAT_LINEBREAK
6058 "linebreak",
6059#endif
6060#ifdef FEAT_LISP
6061 "lispindent",
6062#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006064 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065#ifdef FEAT_LUA
6066# ifndef DYNAMIC_LUA
6067 "lua",
6068# endif
6069#endif
6070#ifdef FEAT_MENU
6071 "menu",
6072#endif
6073#ifdef FEAT_SESSION
6074 "mksession",
6075#endif
6076#ifdef FEAT_MODIFY_FNAME
6077 "modify_fname",
6078#endif
6079#ifdef FEAT_MOUSE
6080 "mouse",
6081#endif
6082#ifdef FEAT_MOUSESHAPE
6083 "mouseshape",
6084#endif
6085#if defined(UNIX) || defined(VMS)
6086# ifdef FEAT_MOUSE_DEC
6087 "mouse_dec",
6088# endif
6089# ifdef FEAT_MOUSE_GPM
6090 "mouse_gpm",
6091# endif
6092# ifdef FEAT_MOUSE_JSB
6093 "mouse_jsbterm",
6094# endif
6095# ifdef FEAT_MOUSE_NET
6096 "mouse_netterm",
6097# endif
6098# ifdef FEAT_MOUSE_PTERM
6099 "mouse_pterm",
6100# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006101# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006102 "mouse_sgr",
6103# endif
6104# ifdef FEAT_SYSMOUSE
6105 "mouse_sysmouse",
6106# endif
6107# ifdef FEAT_MOUSE_URXVT
6108 "mouse_urxvt",
6109# endif
6110# ifdef FEAT_MOUSE_XTERM
6111 "mouse_xterm",
6112# endif
6113#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006114 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006115#ifdef FEAT_MBYTE_IME
6116 "multi_byte_ime",
6117#endif
6118#ifdef FEAT_MULTI_LANG
6119 "multi_lang",
6120#endif
6121#ifdef FEAT_MZSCHEME
6122#ifndef DYNAMIC_MZSCHEME
6123 "mzscheme",
6124#endif
6125#endif
6126#ifdef FEAT_NUM64
6127 "num64",
6128#endif
6129#ifdef FEAT_OLE
6130 "ole",
6131#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006132#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006133 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006134#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006135#ifdef FEAT_PATH_EXTRA
6136 "path_extra",
6137#endif
6138#ifdef FEAT_PERL
6139#ifndef DYNAMIC_PERL
6140 "perl",
6141#endif
6142#endif
6143#ifdef FEAT_PERSISTENT_UNDO
6144 "persistent_undo",
6145#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006146#if defined(FEAT_PYTHON)
6147 "python_compiled",
6148# if defined(DYNAMIC_PYTHON)
6149 "python_dynamic",
6150# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006151 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006152 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006153# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006154#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006155#if defined(FEAT_PYTHON3)
6156 "python3_compiled",
6157# if defined(DYNAMIC_PYTHON3)
6158 "python3_dynamic",
6159# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006161 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006162# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006163#endif
6164#ifdef FEAT_POSTSCRIPT
6165 "postscript",
6166#endif
6167#ifdef FEAT_PRINTER
6168 "printer",
6169#endif
6170#ifdef FEAT_PROFILE
6171 "profile",
6172#endif
6173#ifdef FEAT_RELTIME
6174 "reltime",
6175#endif
6176#ifdef FEAT_QUICKFIX
6177 "quickfix",
6178#endif
6179#ifdef FEAT_RIGHTLEFT
6180 "rightleft",
6181#endif
6182#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6183 "ruby",
6184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186#ifdef FEAT_CMDL_INFO
6187 "showcmd",
6188 "cmdline_info",
6189#endif
6190#ifdef FEAT_SIGNS
6191 "signs",
6192#endif
6193#ifdef FEAT_SMARTINDENT
6194 "smartindent",
6195#endif
6196#ifdef STARTUPTIME
6197 "startuptime",
6198#endif
6199#ifdef FEAT_STL_OPT
6200 "statusline",
6201#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006202#ifdef FEAT_NETBEANS_INTG
6203 "netbeans_intg",
6204#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006205#ifdef FEAT_SOUND
6206 "sound",
6207#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006208#ifdef FEAT_SPELL
6209 "spell",
6210#endif
6211#ifdef FEAT_SYN_HL
6212 "syntax",
6213#endif
6214#if defined(USE_SYSTEM) || !defined(UNIX)
6215 "system",
6216#endif
6217#ifdef FEAT_TAG_BINS
6218 "tag_binary",
6219#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006220#ifdef FEAT_TCL
6221# ifndef DYNAMIC_TCL
6222 "tcl",
6223# endif
6224#endif
6225#ifdef FEAT_TERMGUICOLORS
6226 "termguicolors",
6227#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006228#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006229 "terminal",
6230#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006231#ifdef TERMINFO
6232 "terminfo",
6233#endif
6234#ifdef FEAT_TERMRESPONSE
6235 "termresponse",
6236#endif
6237#ifdef FEAT_TEXTOBJ
6238 "textobjects",
6239#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006240#ifdef FEAT_TEXT_PROP
6241 "textprop",
6242#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006243#ifdef HAVE_TGETENT
6244 "tgetent",
6245#endif
6246#ifdef FEAT_TIMERS
6247 "timers",
6248#endif
6249#ifdef FEAT_TITLE
6250 "title",
6251#endif
6252#ifdef FEAT_TOOLBAR
6253 "toolbar",
6254#endif
6255#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6256 "unnamedplus",
6257#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006258 "user-commands", /* was accidentally included in 5.4 */
6259 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006260#ifdef FEAT_VARTABS
6261 "vartabs",
6262#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006263 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264#ifdef FEAT_VIMINFO
6265 "viminfo",
6266#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006267 "vimscript-1",
6268 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006269 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006271 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006273 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006274#ifdef FEAT_VTP
6275 "vtp",
6276#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006277#ifdef FEAT_WILDIGN
6278 "wildignore",
6279#endif
6280#ifdef FEAT_WILDMENU
6281 "wildmenu",
6282#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006284#ifdef FEAT_WAK
6285 "winaltkeys",
6286#endif
6287#ifdef FEAT_WRITEBACKUP
6288 "writebackup",
6289#endif
6290#ifdef FEAT_XIM
6291 "xim",
6292#endif
6293#ifdef FEAT_XFONTSET
6294 "xfontset",
6295#endif
6296#ifdef FEAT_XPM_W32
6297 "xpm",
6298 "xpm_w32", /* for backward compatibility */
6299#else
6300# if defined(HAVE_XPM)
6301 "xpm",
6302# endif
6303#endif
6304#ifdef USE_XSMP
6305 "xsmp",
6306#endif
6307#ifdef USE_XSMP_INTERACT
6308 "xsmp_interact",
6309#endif
6310#ifdef FEAT_XCLIPBOARD
6311 "xterm_clipboard",
6312#endif
6313#ifdef FEAT_XTERM_SAVE
6314 "xterm_save",
6315#endif
6316#if defined(UNIX) && defined(FEAT_X11)
6317 "X11",
6318#endif
6319 NULL
6320 };
6321
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006322 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323 for (i = 0; has_list[i] != NULL; ++i)
6324 if (STRICMP(name, has_list[i]) == 0)
6325 {
6326 n = TRUE;
6327 break;
6328 }
6329
6330 if (n == FALSE)
6331 {
6332 if (STRNICMP(name, "patch", 5) == 0)
6333 {
6334 if (name[5] == '-'
6335 && STRLEN(name) >= 11
6336 && vim_isdigit(name[6])
6337 && vim_isdigit(name[8])
6338 && vim_isdigit(name[10]))
6339 {
6340 int major = atoi((char *)name + 6);
6341 int minor = atoi((char *)name + 8);
6342
6343 /* Expect "patch-9.9.01234". */
6344 n = (major < VIM_VERSION_MAJOR
6345 || (major == VIM_VERSION_MAJOR
6346 && (minor < VIM_VERSION_MINOR
6347 || (minor == VIM_VERSION_MINOR
6348 && has_patch(atoi((char *)name + 10))))));
6349 }
6350 else
6351 n = has_patch(atoi((char *)name + 5));
6352 }
6353 else if (STRICMP(name, "vim_starting") == 0)
6354 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006355 else if (STRICMP(name, "ttyin") == 0)
6356 n = mch_input_isatty();
6357 else if (STRICMP(name, "ttyout") == 0)
6358 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006359 else if (STRICMP(name, "multi_byte_encoding") == 0)
6360 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006361#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006362 else if (STRICMP(name, "balloon_multiline") == 0)
6363 n = multiline_balloon_available();
6364#endif
6365#ifdef DYNAMIC_TCL
6366 else if (STRICMP(name, "tcl") == 0)
6367 n = tcl_enabled(FALSE);
6368#endif
6369#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6370 else if (STRICMP(name, "iconv") == 0)
6371 n = iconv_enabled(FALSE);
6372#endif
6373#ifdef DYNAMIC_LUA
6374 else if (STRICMP(name, "lua") == 0)
6375 n = lua_enabled(FALSE);
6376#endif
6377#ifdef DYNAMIC_MZSCHEME
6378 else if (STRICMP(name, "mzscheme") == 0)
6379 n = mzscheme_enabled(FALSE);
6380#endif
6381#ifdef DYNAMIC_RUBY
6382 else if (STRICMP(name, "ruby") == 0)
6383 n = ruby_enabled(FALSE);
6384#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385#ifdef DYNAMIC_PYTHON
6386 else if (STRICMP(name, "python") == 0)
6387 n = python_enabled(FALSE);
6388#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006389#ifdef DYNAMIC_PYTHON3
6390 else if (STRICMP(name, "python3") == 0)
6391 n = python3_enabled(FALSE);
6392#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006393#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6394 else if (STRICMP(name, "pythonx") == 0)
6395 {
6396# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6397 if (p_pyx == 0)
6398 n = python3_enabled(FALSE) || python_enabled(FALSE);
6399 else if (p_pyx == 3)
6400 n = python3_enabled(FALSE);
6401 else if (p_pyx == 2)
6402 n = python_enabled(FALSE);
6403# elif defined(DYNAMIC_PYTHON)
6404 n = python_enabled(FALSE);
6405# elif defined(DYNAMIC_PYTHON3)
6406 n = python3_enabled(FALSE);
6407# endif
6408 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006409#endif
6410#ifdef DYNAMIC_PERL
6411 else if (STRICMP(name, "perl") == 0)
6412 n = perl_enabled(FALSE);
6413#endif
6414#ifdef FEAT_GUI
6415 else if (STRICMP(name, "gui_running") == 0)
6416 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417# ifdef FEAT_BROWSE
6418 else if (STRICMP(name, "browse") == 0)
6419 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6420# endif
6421#endif
6422#ifdef FEAT_SYN_HL
6423 else if (STRICMP(name, "syntax_items") == 0)
6424 n = syntax_present(curwin);
6425#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006426#ifdef FEAT_VTP
6427 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006428 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006429#endif
6430#ifdef FEAT_NETBEANS_INTG
6431 else if (STRICMP(name, "netbeans_enabled") == 0)
6432 n = netbeans_active();
6433#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006434#ifdef FEAT_MOUSE_GPM
6435 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6436 n = gpm_enabled();
6437#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006438#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006439 else if (STRICMP(name, "terminal") == 0)
6440 n = terminal_enabled();
6441#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006442#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006443 else if (STRICMP(name, "conpty") == 0)
6444 n = use_conpty();
6445#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006446#ifdef FEAT_CLIPBOARD
6447 else if (STRICMP(name, "clipboard_working") == 0)
6448 n = clip_star.available;
6449#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006450 }
6451
6452 rettv->vval.v_number = n;
6453}
6454
6455/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006456 * "haslocaldir()" function
6457 */
6458 static void
6459f_haslocaldir(typval_T *argvars, typval_T *rettv)
6460{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006461 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 win_T *wp = NULL;
6463
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006464 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6465
6466 // Check for window-local and tab-local directories
6467 if (wp != NULL && wp->w_localdir != NULL)
6468 rettv->vval.v_number = 1;
6469 else if (tp != NULL && tp->tp_localdir != NULL)
6470 rettv->vval.v_number = 2;
6471 else
6472 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473}
6474
6475/*
6476 * "hasmapto()" function
6477 */
6478 static void
6479f_hasmapto(typval_T *argvars, typval_T *rettv)
6480{
6481 char_u *name;
6482 char_u *mode;
6483 char_u buf[NUMBUFLEN];
6484 int abbr = FALSE;
6485
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006486 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487 if (argvars[1].v_type == VAR_UNKNOWN)
6488 mode = (char_u *)"nvo";
6489 else
6490 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006491 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006492 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006493 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006494 }
6495
6496 if (map_to_exists(name, mode, abbr))
6497 rettv->vval.v_number = TRUE;
6498 else
6499 rettv->vval.v_number = FALSE;
6500}
6501
6502/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503 * "highlightID(name)" function
6504 */
6505 static void
6506f_hlID(typval_T *argvars, typval_T *rettv)
6507{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006508 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006509}
6510
6511/*
6512 * "highlight_exists()" function
6513 */
6514 static void
6515f_hlexists(typval_T *argvars, typval_T *rettv)
6516{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006517 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006518}
6519
6520/*
6521 * "hostname()" function
6522 */
6523 static void
6524f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6525{
6526 char_u hostname[256];
6527
6528 mch_get_host_name(hostname, 256);
6529 rettv->v_type = VAR_STRING;
6530 rettv->vval.v_string = vim_strsave(hostname);
6531}
6532
6533/*
6534 * iconv() function
6535 */
6536 static void
6537f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6538{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 char_u buf1[NUMBUFLEN];
6540 char_u buf2[NUMBUFLEN];
6541 char_u *from, *to, *str;
6542 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006543
6544 rettv->v_type = VAR_STRING;
6545 rettv->vval.v_string = NULL;
6546
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006547 str = tv_get_string(&argvars[0]);
6548 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6549 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 vimconv.vc_type = CONV_NONE;
6551 convert_setup(&vimconv, from, to);
6552
6553 /* If the encodings are equal, no conversion needed. */
6554 if (vimconv.vc_type == CONV_NONE)
6555 rettv->vval.v_string = vim_strsave(str);
6556 else
6557 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6558
6559 convert_setup(&vimconv, NULL, NULL);
6560 vim_free(from);
6561 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562}
6563
6564/*
6565 * "indent()" function
6566 */
6567 static void
6568f_indent(typval_T *argvars, typval_T *rettv)
6569{
6570 linenr_T lnum;
6571
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006572 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006573 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6574 rettv->vval.v_number = get_indent_lnum(lnum);
6575 else
6576 rettv->vval.v_number = -1;
6577}
6578
6579/*
6580 * "index()" function
6581 */
6582 static void
6583f_index(typval_T *argvars, typval_T *rettv)
6584{
6585 list_T *l;
6586 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006587 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 long idx = 0;
6589 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006590 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006591
6592 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006593 if (argvars[0].v_type == VAR_BLOB)
6594 {
6595 typval_T tv;
6596 int start = 0;
6597
6598 if (argvars[2].v_type != VAR_UNKNOWN)
6599 {
6600 start = tv_get_number_chk(&argvars[2], &error);
6601 if (error)
6602 return;
6603 }
6604 b = argvars[0].vval.v_blob;
6605 if (b == NULL)
6606 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006607 if (start < 0)
6608 {
6609 start = blob_len(b) + start;
6610 if (start < 0)
6611 start = 0;
6612 }
6613
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006614 for (idx = start; idx < blob_len(b); ++idx)
6615 {
6616 tv.v_type = VAR_NUMBER;
6617 tv.vval.v_number = blob_get(b, idx);
6618 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6619 {
6620 rettv->vval.v_number = idx;
6621 return;
6622 }
6623 }
6624 return;
6625 }
6626 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006627 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006628 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006629 return;
6630 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006631
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006632 l = argvars[0].vval.v_list;
6633 if (l != NULL)
6634 {
6635 item = l->lv_first;
6636 if (argvars[2].v_type != VAR_UNKNOWN)
6637 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006638 /* Start at specified item. Use the cached index that list_find()
6639 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006640 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 idx = l->lv_idx;
6642 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006643 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006644 if (error)
6645 item = NULL;
6646 }
6647
6648 for ( ; item != NULL; item = item->li_next, ++idx)
6649 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6650 {
6651 rettv->vval.v_number = idx;
6652 break;
6653 }
6654 }
6655}
6656
6657static int inputsecret_flag = 0;
6658
6659/*
6660 * "input()" function
6661 * Also handles inputsecret() when inputsecret is set.
6662 */
6663 static void
6664f_input(typval_T *argvars, typval_T *rettv)
6665{
6666 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6667}
6668
6669/*
6670 * "inputdialog()" function
6671 */
6672 static void
6673f_inputdialog(typval_T *argvars, typval_T *rettv)
6674{
6675#if defined(FEAT_GUI_TEXTDIALOG)
6676 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6677 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6678 {
6679 char_u *message;
6680 char_u buf[NUMBUFLEN];
6681 char_u *defstr = (char_u *)"";
6682
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006683 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006684 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006685 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6687 else
6688 IObuff[0] = NUL;
6689 if (message != NULL && defstr != NULL
6690 && do_dialog(VIM_QUESTION, NULL, message,
6691 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6692 rettv->vval.v_string = vim_strsave(IObuff);
6693 else
6694 {
6695 if (message != NULL && defstr != NULL
6696 && argvars[1].v_type != VAR_UNKNOWN
6697 && argvars[2].v_type != VAR_UNKNOWN)
6698 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006699 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700 else
6701 rettv->vval.v_string = NULL;
6702 }
6703 rettv->v_type = VAR_STRING;
6704 }
6705 else
6706#endif
6707 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6708}
6709
6710/*
6711 * "inputlist()" function
6712 */
6713 static void
6714f_inputlist(typval_T *argvars, typval_T *rettv)
6715{
6716 listitem_T *li;
6717 int selected;
6718 int mouse_used;
6719
6720#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006721 /* While starting up, there is no place to enter text. When running tests
6722 * with --not-a-term we assume feedkeys() will be used. */
6723 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006724 return;
6725#endif
6726 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6727 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006728 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006729 return;
6730 }
6731
6732 msg_start();
6733 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6734 lines_left = Rows; /* avoid more prompt */
6735 msg_scroll = TRUE;
6736 msg_clr_eos();
6737
6738 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6739 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006740 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741 msg_putchar('\n');
6742 }
6743
6744 /* Ask for choice. */
6745 selected = prompt_for_number(&mouse_used);
6746 if (mouse_used)
6747 selected -= lines_left;
6748
6749 rettv->vval.v_number = selected;
6750}
6751
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006752static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6753
6754/*
6755 * "inputrestore()" function
6756 */
6757 static void
6758f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6759{
6760 if (ga_userinput.ga_len > 0)
6761 {
6762 --ga_userinput.ga_len;
6763 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6764 + ga_userinput.ga_len);
6765 /* default return is zero == OK */
6766 }
6767 else if (p_verbose > 1)
6768 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006769 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770 rettv->vval.v_number = 1; /* Failed */
6771 }
6772}
6773
6774/*
6775 * "inputsave()" function
6776 */
6777 static void
6778f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6779{
6780 /* Add an entry to the stack of typeahead storage. */
6781 if (ga_grow(&ga_userinput, 1) == OK)
6782 {
6783 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6784 + ga_userinput.ga_len);
6785 ++ga_userinput.ga_len;
6786 /* default return is zero == OK */
6787 }
6788 else
6789 rettv->vval.v_number = 1; /* Failed */
6790}
6791
6792/*
6793 * "inputsecret()" function
6794 */
6795 static void
6796f_inputsecret(typval_T *argvars, typval_T *rettv)
6797{
6798 ++cmdline_star;
6799 ++inputsecret_flag;
6800 f_input(argvars, rettv);
6801 --cmdline_star;
6802 --inputsecret_flag;
6803}
6804
6805/*
6806 * "insert()" function
6807 */
6808 static void
6809f_insert(typval_T *argvars, typval_T *rettv)
6810{
6811 long before = 0;
6812 listitem_T *item;
6813 list_T *l;
6814 int error = FALSE;
6815
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006816 if (argvars[0].v_type == VAR_BLOB)
6817 {
6818 int val, len;
6819 char_u *p;
6820
6821 len = blob_len(argvars[0].vval.v_blob);
6822 if (argvars[2].v_type != VAR_UNKNOWN)
6823 {
6824 before = (long)tv_get_number_chk(&argvars[2], &error);
6825 if (error)
6826 return; // type error; errmsg already given
6827 if (before < 0 || before > len)
6828 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006829 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006830 return;
6831 }
6832 }
6833 val = tv_get_number_chk(&argvars[1], &error);
6834 if (error)
6835 return;
6836 if (val < 0 || val > 255)
6837 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006838 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006839 return;
6840 }
6841
6842 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6843 return;
6844 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6845 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6846 *(p + before) = val;
6847 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6848
6849 copy_tv(&argvars[0], rettv);
6850 }
6851 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006852 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006853 else if ((l = argvars[0].vval.v_list) != NULL
6854 && !var_check_lock(l->lv_lock,
6855 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006856 {
6857 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006858 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006859 if (error)
6860 return; /* type error; errmsg already given */
6861
6862 if (before == l->lv_len)
6863 item = NULL;
6864 else
6865 {
6866 item = list_find(l, before);
6867 if (item == NULL)
6868 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006869 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870 l = NULL;
6871 }
6872 }
6873 if (l != NULL)
6874 {
6875 list_insert_tv(l, &argvars[1], item);
6876 copy_tv(&argvars[0], rettv);
6877 }
6878 }
6879}
6880
6881/*
6882 * "invert(expr)" function
6883 */
6884 static void
6885f_invert(typval_T *argvars, typval_T *rettv)
6886{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006887 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006888}
6889
6890/*
6891 * "isdirectory()" function
6892 */
6893 static void
6894f_isdirectory(typval_T *argvars, typval_T *rettv)
6895{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006896 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006897}
6898
6899/*
6900 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6901 * or it refers to a List or Dictionary that is locked.
6902 */
6903 static int
6904tv_islocked(typval_T *tv)
6905{
6906 return (tv->v_lock & VAR_LOCKED)
6907 || (tv->v_type == VAR_LIST
6908 && tv->vval.v_list != NULL
6909 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6910 || (tv->v_type == VAR_DICT
6911 && tv->vval.v_dict != NULL
6912 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6913}
6914
6915/*
6916 * "islocked()" function
6917 */
6918 static void
6919f_islocked(typval_T *argvars, typval_T *rettv)
6920{
6921 lval_T lv;
6922 char_u *end;
6923 dictitem_T *di;
6924
6925 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006926 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006927 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006928 if (end != NULL && lv.ll_name != NULL)
6929 {
6930 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006931 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006932 else
6933 {
6934 if (lv.ll_tv == NULL)
6935 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006936 di = find_var(lv.ll_name, NULL, TRUE);
6937 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006938 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006939 /* Consider a variable locked when:
6940 * 1. the variable itself is locked
6941 * 2. the value of the variable is locked.
6942 * 3. the List or Dict value is locked.
6943 */
6944 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6945 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006946 }
6947 }
6948 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006949 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006951 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006952 else if (lv.ll_list != NULL)
6953 /* List item. */
6954 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6955 else
6956 /* Dictionary item. */
6957 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6958 }
6959 }
6960
6961 clear_lval(&lv);
6962}
6963
6964#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6965/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006966 * "isinf()" function
6967 */
6968 static void
6969f_isinf(typval_T *argvars, typval_T *rettv)
6970{
6971 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6972 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6973}
6974
6975/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006976 * "isnan()" function
6977 */
6978 static void
6979f_isnan(typval_T *argvars, typval_T *rettv)
6980{
6981 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6982 && isnan(argvars[0].vval.v_float);
6983}
6984#endif
6985
6986/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006987 * "last_buffer_nr()" function.
6988 */
6989 static void
6990f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6991{
6992 int n = 0;
6993 buf_T *buf;
6994
Bram Moolenaar29323592016-07-24 22:04:11 +02006995 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006996 if (n < buf->b_fnum)
6997 n = buf->b_fnum;
6998
6999 rettv->vval.v_number = n;
7000}
7001
7002/*
7003 * "len()" function
7004 */
7005 static void
7006f_len(typval_T *argvars, typval_T *rettv)
7007{
7008 switch (argvars[0].v_type)
7009 {
7010 case VAR_STRING:
7011 case VAR_NUMBER:
7012 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007013 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007014 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007015 case VAR_BLOB:
7016 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7017 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007018 case VAR_LIST:
7019 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7020 break;
7021 case VAR_DICT:
7022 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7023 break;
7024 case VAR_UNKNOWN:
7025 case VAR_SPECIAL:
7026 case VAR_FLOAT:
7027 case VAR_FUNC:
7028 case VAR_PARTIAL:
7029 case VAR_JOB:
7030 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007031 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007032 break;
7033 }
7034}
7035
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007037libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038{
7039#ifdef FEAT_LIBCALL
7040 char_u *string_in;
7041 char_u **string_result;
7042 int nr_result;
7043#endif
7044
7045 rettv->v_type = type;
7046 if (type != VAR_NUMBER)
7047 rettv->vval.v_string = NULL;
7048
7049 if (check_restricted() || check_secure())
7050 return;
7051
7052#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007053 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007054 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7055 {
7056 string_in = NULL;
7057 if (argvars[2].v_type == VAR_STRING)
7058 string_in = argvars[2].vval.v_string;
7059 if (type == VAR_NUMBER)
7060 string_result = NULL;
7061 else
7062 string_result = &rettv->vval.v_string;
7063 if (mch_libcall(argvars[0].vval.v_string,
7064 argvars[1].vval.v_string,
7065 string_in,
7066 argvars[2].vval.v_number,
7067 string_result,
7068 &nr_result) == OK
7069 && type == VAR_NUMBER)
7070 rettv->vval.v_number = nr_result;
7071 }
7072#endif
7073}
7074
7075/*
7076 * "libcall()" function
7077 */
7078 static void
7079f_libcall(typval_T *argvars, typval_T *rettv)
7080{
7081 libcall_common(argvars, rettv, VAR_STRING);
7082}
7083
7084/*
7085 * "libcallnr()" function
7086 */
7087 static void
7088f_libcallnr(typval_T *argvars, typval_T *rettv)
7089{
7090 libcall_common(argvars, rettv, VAR_NUMBER);
7091}
7092
7093/*
7094 * "line(string)" function
7095 */
7096 static void
7097f_line(typval_T *argvars, typval_T *rettv)
7098{
7099 linenr_T lnum = 0;
7100 pos_T *fp;
7101 int fnum;
7102
7103 fp = var2fpos(&argvars[0], TRUE, &fnum);
7104 if (fp != NULL)
7105 lnum = fp->lnum;
7106 rettv->vval.v_number = lnum;
7107}
7108
7109/*
7110 * "line2byte(lnum)" function
7111 */
7112 static void
7113f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7114{
7115#ifndef FEAT_BYTEOFF
7116 rettv->vval.v_number = -1;
7117#else
7118 linenr_T lnum;
7119
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007120 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007121 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7122 rettv->vval.v_number = -1;
7123 else
7124 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7125 if (rettv->vval.v_number >= 0)
7126 ++rettv->vval.v_number;
7127#endif
7128}
7129
7130/*
7131 * "lispindent(lnum)" function
7132 */
7133 static void
7134f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7135{
7136#ifdef FEAT_LISP
7137 pos_T pos;
7138 linenr_T lnum;
7139
7140 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007141 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7143 {
7144 curwin->w_cursor.lnum = lnum;
7145 rettv->vval.v_number = get_lisp_indent();
7146 curwin->w_cursor = pos;
7147 }
7148 else
7149#endif
7150 rettv->vval.v_number = -1;
7151}
7152
7153/*
7154 * "localtime()" function
7155 */
7156 static void
7157f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7158{
7159 rettv->vval.v_number = (varnumber_T)time(NULL);
7160}
7161
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007162#ifdef FEAT_FLOAT
7163/*
7164 * "log()" function
7165 */
7166 static void
7167f_log(typval_T *argvars, typval_T *rettv)
7168{
7169 float_T f = 0.0;
7170
7171 rettv->v_type = VAR_FLOAT;
7172 if (get_float_arg(argvars, &f) == OK)
7173 rettv->vval.v_float = log(f);
7174 else
7175 rettv->vval.v_float = 0.0;
7176}
7177
7178/*
7179 * "log10()" function
7180 */
7181 static void
7182f_log10(typval_T *argvars, typval_T *rettv)
7183{
7184 float_T f = 0.0;
7185
7186 rettv->v_type = VAR_FLOAT;
7187 if (get_float_arg(argvars, &f) == OK)
7188 rettv->vval.v_float = log10(f);
7189 else
7190 rettv->vval.v_float = 0.0;
7191}
7192#endif
7193
7194#ifdef FEAT_LUA
7195/*
7196 * "luaeval()" function
7197 */
7198 static void
7199f_luaeval(typval_T *argvars, typval_T *rettv)
7200{
7201 char_u *str;
7202 char_u buf[NUMBUFLEN];
7203
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007204 if (check_restricted() || check_secure())
7205 return;
7206
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007207 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208 do_luaeval(str, argvars + 1, rettv);
7209}
7210#endif
7211
7212/*
7213 * "map()" function
7214 */
7215 static void
7216f_map(typval_T *argvars, typval_T *rettv)
7217{
7218 filter_map(argvars, rettv, TRUE);
7219}
7220
7221/*
7222 * "maparg()" function
7223 */
7224 static void
7225f_maparg(typval_T *argvars, typval_T *rettv)
7226{
7227 get_maparg(argvars, rettv, TRUE);
7228}
7229
7230/*
7231 * "mapcheck()" function
7232 */
7233 static void
7234f_mapcheck(typval_T *argvars, typval_T *rettv)
7235{
7236 get_maparg(argvars, rettv, FALSE);
7237}
7238
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007239typedef enum
7240{
7241 MATCH_END, /* matchend() */
7242 MATCH_MATCH, /* match() */
7243 MATCH_STR, /* matchstr() */
7244 MATCH_LIST, /* matchlist() */
7245 MATCH_POS /* matchstrpos() */
7246} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247
7248 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007249find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250{
7251 char_u *str = NULL;
7252 long len = 0;
7253 char_u *expr = NULL;
7254 char_u *pat;
7255 regmatch_T regmatch;
7256 char_u patbuf[NUMBUFLEN];
7257 char_u strbuf[NUMBUFLEN];
7258 char_u *save_cpo;
7259 long start = 0;
7260 long nth = 1;
7261 colnr_T startcol = 0;
7262 int match = 0;
7263 list_T *l = NULL;
7264 listitem_T *li = NULL;
7265 long idx = 0;
7266 char_u *tofree = NULL;
7267
7268 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7269 save_cpo = p_cpo;
7270 p_cpo = (char_u *)"";
7271
7272 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007273 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007275 /* type MATCH_LIST: return empty list when there are no matches.
7276 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007277 if (rettv_list_alloc(rettv) == FAIL)
7278 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007279 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007280 && (list_append_string(rettv->vval.v_list,
7281 (char_u *)"", 0) == FAIL
7282 || list_append_number(rettv->vval.v_list,
7283 (varnumber_T)-1) == FAIL
7284 || list_append_number(rettv->vval.v_list,
7285 (varnumber_T)-1) == FAIL
7286 || list_append_number(rettv->vval.v_list,
7287 (varnumber_T)-1) == FAIL))
7288 {
7289 list_free(rettv->vval.v_list);
7290 rettv->vval.v_list = NULL;
7291 goto theend;
7292 }
7293 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007294 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007295 {
7296 rettv->v_type = VAR_STRING;
7297 rettv->vval.v_string = NULL;
7298 }
7299
7300 if (argvars[0].v_type == VAR_LIST)
7301 {
7302 if ((l = argvars[0].vval.v_list) == NULL)
7303 goto theend;
7304 li = l->lv_first;
7305 }
7306 else
7307 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007308 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007309 len = (long)STRLEN(str);
7310 }
7311
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007312 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007313 if (pat == NULL)
7314 goto theend;
7315
7316 if (argvars[2].v_type != VAR_UNKNOWN)
7317 {
7318 int error = FALSE;
7319
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007320 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007321 if (error)
7322 goto theend;
7323 if (l != NULL)
7324 {
7325 li = list_find(l, start);
7326 if (li == NULL)
7327 goto theend;
7328 idx = l->lv_idx; /* use the cached index */
7329 }
7330 else
7331 {
7332 if (start < 0)
7333 start = 0;
7334 if (start > len)
7335 goto theend;
7336 /* When "count" argument is there ignore matches before "start",
7337 * otherwise skip part of the string. Differs when pattern is "^"
7338 * or "\<". */
7339 if (argvars[3].v_type != VAR_UNKNOWN)
7340 startcol = start;
7341 else
7342 {
7343 str += start;
7344 len -= start;
7345 }
7346 }
7347
7348 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007349 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350 if (error)
7351 goto theend;
7352 }
7353
7354 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7355 if (regmatch.regprog != NULL)
7356 {
7357 regmatch.rm_ic = p_ic;
7358
7359 for (;;)
7360 {
7361 if (l != NULL)
7362 {
7363 if (li == NULL)
7364 {
7365 match = FALSE;
7366 break;
7367 }
7368 vim_free(tofree);
7369 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7370 if (str == NULL)
7371 break;
7372 }
7373
7374 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7375
7376 if (match && --nth <= 0)
7377 break;
7378 if (l == NULL && !match)
7379 break;
7380
7381 /* Advance to just after the match. */
7382 if (l != NULL)
7383 {
7384 li = li->li_next;
7385 ++idx;
7386 }
7387 else
7388 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389 startcol = (colnr_T)(regmatch.startp[0]
7390 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007391 if (startcol > (colnr_T)len
7392 || str + startcol <= regmatch.startp[0])
7393 {
7394 match = FALSE;
7395 break;
7396 }
7397 }
7398 }
7399
7400 if (match)
7401 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007402 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403 {
7404 listitem_T *li1 = rettv->vval.v_list->lv_first;
7405 listitem_T *li2 = li1->li_next;
7406 listitem_T *li3 = li2->li_next;
7407 listitem_T *li4 = li3->li_next;
7408
7409 vim_free(li1->li_tv.vval.v_string);
7410 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7411 (int)(regmatch.endp[0] - regmatch.startp[0]));
7412 li3->li_tv.vval.v_number =
7413 (varnumber_T)(regmatch.startp[0] - expr);
7414 li4->li_tv.vval.v_number =
7415 (varnumber_T)(regmatch.endp[0] - expr);
7416 if (l != NULL)
7417 li2->li_tv.vval.v_number = (varnumber_T)idx;
7418 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007419 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007420 {
7421 int i;
7422
7423 /* return list with matched string and submatches */
7424 for (i = 0; i < NSUBEXP; ++i)
7425 {
7426 if (regmatch.endp[i] == NULL)
7427 {
7428 if (list_append_string(rettv->vval.v_list,
7429 (char_u *)"", 0) == FAIL)
7430 break;
7431 }
7432 else if (list_append_string(rettv->vval.v_list,
7433 regmatch.startp[i],
7434 (int)(regmatch.endp[i] - regmatch.startp[i]))
7435 == FAIL)
7436 break;
7437 }
7438 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007439 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 {
7441 /* return matched string */
7442 if (l != NULL)
7443 copy_tv(&li->li_tv, rettv);
7444 else
7445 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7446 (int)(regmatch.endp[0] - regmatch.startp[0]));
7447 }
7448 else if (l != NULL)
7449 rettv->vval.v_number = idx;
7450 else
7451 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007452 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453 rettv->vval.v_number =
7454 (varnumber_T)(regmatch.startp[0] - str);
7455 else
7456 rettv->vval.v_number =
7457 (varnumber_T)(regmatch.endp[0] - str);
7458 rettv->vval.v_number += (varnumber_T)(str - expr);
7459 }
7460 }
7461 vim_regfree(regmatch.regprog);
7462 }
7463
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007464theend:
7465 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007466 /* matchstrpos() without a list: drop the second item. */
7467 listitem_remove(rettv->vval.v_list,
7468 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007469 vim_free(tofree);
7470 p_cpo = save_cpo;
7471}
7472
7473/*
7474 * "match()" function
7475 */
7476 static void
7477f_match(typval_T *argvars, typval_T *rettv)
7478{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007479 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007480}
7481
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007482/*
7483 * "matchend()" function
7484 */
7485 static void
7486f_matchend(typval_T *argvars, typval_T *rettv)
7487{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007488 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007489}
7490
7491/*
7492 * "matchlist()" function
7493 */
7494 static void
7495f_matchlist(typval_T *argvars, typval_T *rettv)
7496{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007497 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498}
7499
7500/*
7501 * "matchstr()" function
7502 */
7503 static void
7504f_matchstr(typval_T *argvars, typval_T *rettv)
7505{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007506 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507}
7508
7509/*
7510 * "matchstrpos()" function
7511 */
7512 static void
7513f_matchstrpos(typval_T *argvars, typval_T *rettv)
7514{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007515 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516}
7517
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 static void
7519max_min(typval_T *argvars, typval_T *rettv, int domax)
7520{
7521 varnumber_T n = 0;
7522 varnumber_T i;
7523 int error = FALSE;
7524
7525 if (argvars[0].v_type == VAR_LIST)
7526 {
7527 list_T *l;
7528 listitem_T *li;
7529
7530 l = argvars[0].vval.v_list;
7531 if (l != NULL)
7532 {
7533 li = l->lv_first;
7534 if (li != NULL)
7535 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007536 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537 for (;;)
7538 {
7539 li = li->li_next;
7540 if (li == NULL)
7541 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007542 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007543 if (domax ? i > n : i < n)
7544 n = i;
7545 }
7546 }
7547 }
7548 }
7549 else if (argvars[0].v_type == VAR_DICT)
7550 {
7551 dict_T *d;
7552 int first = TRUE;
7553 hashitem_T *hi;
7554 int todo;
7555
7556 d = argvars[0].vval.v_dict;
7557 if (d != NULL)
7558 {
7559 todo = (int)d->dv_hashtab.ht_used;
7560 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7561 {
7562 if (!HASHITEM_EMPTY(hi))
7563 {
7564 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007565 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007566 if (first)
7567 {
7568 n = i;
7569 first = FALSE;
7570 }
7571 else if (domax ? i > n : i < n)
7572 n = i;
7573 }
7574 }
7575 }
7576 }
7577 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007578 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007579 rettv->vval.v_number = error ? 0 : n;
7580}
7581
7582/*
7583 * "max()" function
7584 */
7585 static void
7586f_max(typval_T *argvars, typval_T *rettv)
7587{
7588 max_min(argvars, rettv, TRUE);
7589}
7590
7591/*
7592 * "min()" function
7593 */
7594 static void
7595f_min(typval_T *argvars, typval_T *rettv)
7596{
7597 max_min(argvars, rettv, FALSE);
7598}
7599
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600/*
7601 * Create the directory in which "dir" is located, and higher levels when
7602 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007603 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007604 */
7605 static int
7606mkdir_recurse(char_u *dir, int prot)
7607{
7608 char_u *p;
7609 char_u *updir;
7610 int r = FAIL;
7611
7612 /* Get end of directory name in "dir".
7613 * We're done when it's "/" or "c:/". */
7614 p = gettail_sep(dir);
7615 if (p <= get_past_head(dir))
7616 return OK;
7617
7618 /* If the directory exists we're done. Otherwise: create it.*/
7619 updir = vim_strnsave(dir, (int)(p - dir));
7620 if (updir == NULL)
7621 return FAIL;
7622 if (mch_isdir(updir))
7623 r = OK;
7624 else if (mkdir_recurse(updir, prot) == OK)
7625 r = vim_mkdir_emsg(updir, prot);
7626 vim_free(updir);
7627 return r;
7628}
7629
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630/*
7631 * "mkdir()" function
7632 */
7633 static void
7634f_mkdir(typval_T *argvars, typval_T *rettv)
7635{
7636 char_u *dir;
7637 char_u buf[NUMBUFLEN];
7638 int prot = 0755;
7639
7640 rettv->vval.v_number = FAIL;
7641 if (check_restricted() || check_secure())
7642 return;
7643
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007644 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007645 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007646 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007648 if (*gettail(dir) == NUL)
7649 /* remove trailing slashes */
7650 *gettail_sep(dir) = NUL;
7651
7652 if (argvars[1].v_type != VAR_UNKNOWN)
7653 {
7654 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007656 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007657 if (prot == -1)
7658 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007660 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007661 {
7662 if (mch_isdir(dir))
7663 {
7664 /* With the "p" flag it's OK if the dir already exists. */
7665 rettv->vval.v_number = OK;
7666 return;
7667 }
7668 mkdir_recurse(dir, prot);
7669 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007671 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007673
7674/*
7675 * "mode()" function
7676 */
7677 static void
7678f_mode(typval_T *argvars, typval_T *rettv)
7679{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007680 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007681
Bram Moolenaar612cc382018-07-29 15:34:26 +02007682 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007683
7684 if (time_for_testing == 93784)
7685 {
7686 /* Testing the two-character code. */
7687 buf[0] = 'x';
7688 buf[1] = '!';
7689 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007690#ifdef FEAT_TERMINAL
7691 else if (term_use_loop())
7692 buf[0] = 't';
7693#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007694 else if (VIsual_active)
7695 {
7696 if (VIsual_select)
7697 buf[0] = VIsual_mode + 's' - 'v';
7698 else
7699 buf[0] = VIsual_mode;
7700 }
7701 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7702 || State == CONFIRM)
7703 {
7704 buf[0] = 'r';
7705 if (State == ASKMORE)
7706 buf[1] = 'm';
7707 else if (State == CONFIRM)
7708 buf[1] = '?';
7709 }
7710 else if (State == EXTERNCMD)
7711 buf[0] = '!';
7712 else if (State & INSERT)
7713 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714 if (State & VREPLACE_FLAG)
7715 {
7716 buf[0] = 'R';
7717 buf[1] = 'v';
7718 }
7719 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007720 {
7721 if (State & REPLACE_FLAG)
7722 buf[0] = 'R';
7723 else
7724 buf[0] = 'i';
7725#ifdef FEAT_INS_EXPAND
7726 if (ins_compl_active())
7727 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007728 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007729 buf[1] = 'x';
7730#endif
7731 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007732 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007733 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007734 {
7735 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007736 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007737 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007738 else if (exmode_active == EXMODE_NORMAL)
7739 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007740 }
7741 else
7742 {
7743 buf[0] = 'n';
7744 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007745 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007747 // to be able to detect force-linewise/blockwise/characterwise operations
7748 buf[2] = motion_force;
7749 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007750 else if (restart_edit == 'I' || restart_edit == 'R'
7751 || restart_edit == 'V')
7752 {
7753 buf[1] = 'i';
7754 buf[2] = restart_edit;
7755 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756 }
7757
7758 /* Clear out the minor mode when the argument is not a non-zero number or
7759 * non-empty string. */
7760 if (!non_zero_arg(&argvars[0]))
7761 buf[1] = NUL;
7762
7763 rettv->vval.v_string = vim_strsave(buf);
7764 rettv->v_type = VAR_STRING;
7765}
7766
7767#if defined(FEAT_MZSCHEME) || defined(PROTO)
7768/*
7769 * "mzeval()" function
7770 */
7771 static void
7772f_mzeval(typval_T *argvars, typval_T *rettv)
7773{
7774 char_u *str;
7775 char_u buf[NUMBUFLEN];
7776
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007777 if (check_restricted() || check_secure())
7778 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007779 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780 do_mzeval(str, rettv);
7781}
7782
7783 void
7784mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7785{
7786 typval_T argvars[3];
7787
7788 argvars[0].v_type = VAR_STRING;
7789 argvars[0].vval.v_string = name;
7790 copy_tv(args, &argvars[1]);
7791 argvars[2].v_type = VAR_UNKNOWN;
7792 f_call(argvars, rettv);
7793 clear_tv(&argvars[1]);
7794}
7795#endif
7796
7797/*
7798 * "nextnonblank()" function
7799 */
7800 static void
7801f_nextnonblank(typval_T *argvars, typval_T *rettv)
7802{
7803 linenr_T lnum;
7804
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007805 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007806 {
7807 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7808 {
7809 lnum = 0;
7810 break;
7811 }
7812 if (*skipwhite(ml_get(lnum)) != NUL)
7813 break;
7814 }
7815 rettv->vval.v_number = lnum;
7816}
7817
7818/*
7819 * "nr2char()" function
7820 */
7821 static void
7822f_nr2char(typval_T *argvars, typval_T *rettv)
7823{
7824 char_u buf[NUMBUFLEN];
7825
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 if (has_mbyte)
7827 {
7828 int utf8 = 0;
7829
7830 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007831 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007833 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007834 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007835 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007836 }
7837 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007838 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007839 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 buf[1] = NUL;
7841 }
7842 rettv->v_type = VAR_STRING;
7843 rettv->vval.v_string = vim_strsave(buf);
7844}
7845
7846/*
7847 * "or(expr, expr)" function
7848 */
7849 static void
7850f_or(typval_T *argvars, typval_T *rettv)
7851{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007852 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7853 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854}
7855
7856/*
7857 * "pathshorten()" function
7858 */
7859 static void
7860f_pathshorten(typval_T *argvars, typval_T *rettv)
7861{
7862 char_u *p;
7863
7864 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007865 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 if (p == NULL)
7867 rettv->vval.v_string = NULL;
7868 else
7869 {
7870 p = vim_strsave(p);
7871 rettv->vval.v_string = p;
7872 if (p != NULL)
7873 shorten_dir(p);
7874 }
7875}
7876
7877#ifdef FEAT_PERL
7878/*
7879 * "perleval()" function
7880 */
7881 static void
7882f_perleval(typval_T *argvars, typval_T *rettv)
7883{
7884 char_u *str;
7885 char_u buf[NUMBUFLEN];
7886
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007887 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007888 do_perleval(str, rettv);
7889}
7890#endif
7891
7892#ifdef FEAT_FLOAT
7893/*
7894 * "pow()" function
7895 */
7896 static void
7897f_pow(typval_T *argvars, typval_T *rettv)
7898{
7899 float_T fx = 0.0, fy = 0.0;
7900
7901 rettv->v_type = VAR_FLOAT;
7902 if (get_float_arg(argvars, &fx) == OK
7903 && get_float_arg(&argvars[1], &fy) == OK)
7904 rettv->vval.v_float = pow(fx, fy);
7905 else
7906 rettv->vval.v_float = 0.0;
7907}
7908#endif
7909
7910/*
7911 * "prevnonblank()" function
7912 */
7913 static void
7914f_prevnonblank(typval_T *argvars, typval_T *rettv)
7915{
7916 linenr_T lnum;
7917
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007918 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007919 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7920 lnum = 0;
7921 else
7922 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7923 --lnum;
7924 rettv->vval.v_number = lnum;
7925}
7926
7927/* This dummy va_list is here because:
7928 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7929 * - locally in the function results in a "used before set" warning
7930 * - using va_start() to initialize it gives "function with fixed args" error */
7931static va_list ap;
7932
7933/*
7934 * "printf()" function
7935 */
7936 static void
7937f_printf(typval_T *argvars, typval_T *rettv)
7938{
7939 char_u buf[NUMBUFLEN];
7940 int len;
7941 char_u *s;
7942 int saved_did_emsg = did_emsg;
7943 char *fmt;
7944
7945 rettv->v_type = VAR_STRING;
7946 rettv->vval.v_string = NULL;
7947
7948 /* Get the required length, allocate the buffer and do it for real. */
7949 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007950 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007951 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007952 if (!did_emsg)
7953 {
7954 s = alloc(len + 1);
7955 if (s != NULL)
7956 {
7957 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007958 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7959 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960 }
7961 }
7962 did_emsg |= saved_did_emsg;
7963}
7964
7965/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007966 * "pum_getpos()" function
7967 */
7968 static void
7969f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7970{
7971 if (rettv_dict_alloc(rettv) != OK)
7972 return;
7973#ifdef FEAT_INS_EXPAND
7974 pum_set_event_info(rettv->vval.v_dict);
7975#endif
7976}
7977
7978/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979 * "pumvisible()" function
7980 */
7981 static void
7982f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7983{
7984#ifdef FEAT_INS_EXPAND
7985 if (pum_visible())
7986 rettv->vval.v_number = 1;
7987#endif
7988}
7989
7990#ifdef FEAT_PYTHON3
7991/*
7992 * "py3eval()" function
7993 */
7994 static void
7995f_py3eval(typval_T *argvars, typval_T *rettv)
7996{
7997 char_u *str;
7998 char_u buf[NUMBUFLEN];
7999
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008000 if (check_restricted() || check_secure())
8001 return;
8002
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008003 if (p_pyx == 0)
8004 p_pyx = 3;
8005
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008006 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007 do_py3eval(str, rettv);
8008}
8009#endif
8010
8011#ifdef FEAT_PYTHON
8012/*
8013 * "pyeval()" function
8014 */
8015 static void
8016f_pyeval(typval_T *argvars, typval_T *rettv)
8017{
8018 char_u *str;
8019 char_u buf[NUMBUFLEN];
8020
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008021 if (check_restricted() || check_secure())
8022 return;
8023
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008024 if (p_pyx == 0)
8025 p_pyx = 2;
8026
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008027 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008028 do_pyeval(str, rettv);
8029}
8030#endif
8031
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008032#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8033/*
8034 * "pyxeval()" function
8035 */
8036 static void
8037f_pyxeval(typval_T *argvars, typval_T *rettv)
8038{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008039 if (check_restricted() || check_secure())
8040 return;
8041
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008042# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8043 init_pyxversion();
8044 if (p_pyx == 2)
8045 f_pyeval(argvars, rettv);
8046 else
8047 f_py3eval(argvars, rettv);
8048# elif defined(FEAT_PYTHON)
8049 f_pyeval(argvars, rettv);
8050# elif defined(FEAT_PYTHON3)
8051 f_py3eval(argvars, rettv);
8052# endif
8053}
8054#endif
8055
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008056/*
8057 * "range()" function
8058 */
8059 static void
8060f_range(typval_T *argvars, typval_T *rettv)
8061{
8062 varnumber_T start;
8063 varnumber_T end;
8064 varnumber_T stride = 1;
8065 varnumber_T i;
8066 int error = FALSE;
8067
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008068 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069 if (argvars[1].v_type == VAR_UNKNOWN)
8070 {
8071 end = start - 1;
8072 start = 0;
8073 }
8074 else
8075 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008076 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008077 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008078 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 }
8080
8081 if (error)
8082 return; /* type error; errmsg already given */
8083 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008084 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008085 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008086 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087 else
8088 {
8089 if (rettv_list_alloc(rettv) == OK)
8090 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8091 if (list_append_number(rettv->vval.v_list,
8092 (varnumber_T)i) == FAIL)
8093 break;
8094 }
8095}
8096
8097/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008098 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008099 */
8100 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008101readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008102{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008103 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008104 typval_T save_val;
8105 typval_T rettv;
8106 typval_T argv[2];
8107 int retval = 0;
8108 int error = FALSE;
8109
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008110 if (expr->v_type == VAR_UNKNOWN)
8111 return 1;
8112
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008113 prepare_vimvar(VV_VAL, &save_val);
8114 set_vim_var_string(VV_VAL, name, -1);
8115 argv[0].v_type = VAR_STRING;
8116 argv[0].vval.v_string = name;
8117
8118 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8119 goto theend;
8120
8121 retval = tv_get_number_chk(&rettv, &error);
8122 if (error)
8123 retval = -1;
8124 clear_tv(&rettv);
8125
8126theend:
8127 set_vim_var_string(VV_VAL, NULL, 0);
8128 restore_vimvar(VV_VAL, &save_val);
8129 return retval;
8130}
8131
8132/*
8133 * "readdir()" function
8134 */
8135 static void
8136f_readdir(typval_T *argvars, typval_T *rettv)
8137{
8138 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008139 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008140 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008141 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008142 garray_T ga;
8143 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008144
8145 if (rettv_list_alloc(rettv) == FAIL)
8146 return;
8147 path = tv_get_string(&argvars[0]);
8148 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008149
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008150 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8151 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008152 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008153 for (i = 0; i < ga.ga_len; i++)
8154 {
8155 p = ((char_u **)ga.ga_data)[i];
8156 list_append_string(rettv->vval.v_list, p, -1);
8157 }
8158 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008159 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008160}
8161
8162/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 * "readfile()" function
8164 */
8165 static void
8166f_readfile(typval_T *argvars, typval_T *rettv)
8167{
8168 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008169 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008170 int failed = FALSE;
8171 char_u *fname;
8172 FILE *fd;
8173 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8174 int io_size = sizeof(buf);
8175 int readlen; /* size of last fread() */
8176 char_u *prev = NULL; /* previously read bytes, if any */
8177 long prevlen = 0; /* length of data in prev */
8178 long prevsize = 0; /* size of prev buffer */
8179 long maxline = MAXLNUM;
8180 long cnt = 0;
8181 char_u *p; /* position in buf */
8182 char_u *start; /* start of current line */
8183
8184 if (argvars[1].v_type != VAR_UNKNOWN)
8185 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008186 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008187 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008188 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8189 blob = TRUE;
8190
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008191 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008192 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008193 }
8194
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008195 if (blob)
8196 {
8197 if (rettv_blob_alloc(rettv) == FAIL)
8198 return;
8199 }
8200 else
8201 {
8202 if (rettv_list_alloc(rettv) == FAIL)
8203 return;
8204 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205
8206 /* Always open the file in binary mode, library functions have a mind of
8207 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008208 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8210 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008211 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008212 return;
8213 }
8214
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008215 if (blob)
8216 {
8217 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8218 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008219 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008220 blob_free(rettv->vval.v_blob);
8221 }
8222 fclose(fd);
8223 return;
8224 }
8225
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226 while (cnt < maxline || maxline < 0)
8227 {
8228 readlen = (int)fread(buf, 1, io_size, fd);
8229
8230 /* This for loop processes what was read, but is also entered at end
8231 * of file so that either:
8232 * - an incomplete line gets written
8233 * - a "binary" file gets an empty line at the end if it ends in a
8234 * newline. */
8235 for (p = buf, start = buf;
8236 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8237 ++p)
8238 {
8239 if (*p == '\n' || readlen <= 0)
8240 {
8241 listitem_T *li;
8242 char_u *s = NULL;
8243 long_u len = p - start;
8244
8245 /* Finished a line. Remove CRs before NL. */
8246 if (readlen > 0 && !binary)
8247 {
8248 while (len > 0 && start[len - 1] == '\r')
8249 --len;
8250 /* removal may cross back to the "prev" string */
8251 if (len == 0)
8252 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8253 --prevlen;
8254 }
8255 if (prevlen == 0)
8256 s = vim_strnsave(start, (int)len);
8257 else
8258 {
8259 /* Change "prev" buffer to be the right size. This way
8260 * the bytes are only copied once, and very long lines are
8261 * allocated only once. */
8262 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8263 {
8264 mch_memmove(s + prevlen, start, len);
8265 s[prevlen + len] = NUL;
8266 prev = NULL; /* the list will own the string */
8267 prevlen = prevsize = 0;
8268 }
8269 }
8270 if (s == NULL)
8271 {
8272 do_outofmem_msg((long_u) prevlen + len + 1);
8273 failed = TRUE;
8274 break;
8275 }
8276
8277 if ((li = listitem_alloc()) == NULL)
8278 {
8279 vim_free(s);
8280 failed = TRUE;
8281 break;
8282 }
8283 li->li_tv.v_type = VAR_STRING;
8284 li->li_tv.v_lock = 0;
8285 li->li_tv.vval.v_string = s;
8286 list_append(rettv->vval.v_list, li);
8287
8288 start = p + 1; /* step over newline */
8289 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8290 break;
8291 }
8292 else if (*p == NUL)
8293 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008294 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8295 * when finding the BF and check the previous two bytes. */
8296 else if (*p == 0xbf && enc_utf8 && !binary)
8297 {
8298 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8299 * + 1, these may be in the "prev" string. */
8300 char_u back1 = p >= buf + 1 ? p[-1]
8301 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8302 char_u back2 = p >= buf + 2 ? p[-2]
8303 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8304 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8305
8306 if (back2 == 0xef && back1 == 0xbb)
8307 {
8308 char_u *dest = p - 2;
8309
8310 /* Usually a BOM is at the beginning of a file, and so at
8311 * the beginning of a line; then we can just step over it.
8312 */
8313 if (start == dest)
8314 start = p + 1;
8315 else
8316 {
8317 /* have to shuffle buf to close gap */
8318 int adjust_prevlen = 0;
8319
8320 if (dest < buf)
8321 {
8322 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8323 dest = buf;
8324 }
8325 if (readlen > p - buf + 1)
8326 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8327 readlen -= 3 - adjust_prevlen;
8328 prevlen -= adjust_prevlen;
8329 p = dest - 1;
8330 }
8331 }
8332 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008333 } /* for */
8334
8335 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8336 break;
8337 if (start < p)
8338 {
8339 /* There's part of a line in buf, store it in "prev". */
8340 if (p - start + prevlen >= prevsize)
8341 {
8342 /* need bigger "prev" buffer */
8343 char_u *newprev;
8344
8345 /* A common use case is ordinary text files and "prev" gets a
8346 * fragment of a line, so the first allocation is made
8347 * small, to avoid repeatedly 'allocing' large and
8348 * 'reallocing' small. */
8349 if (prevsize == 0)
8350 prevsize = (long)(p - start);
8351 else
8352 {
8353 long grow50pc = (prevsize * 3) / 2;
8354 long growmin = (long)((p - start) * 2 + prevlen);
8355 prevsize = grow50pc > growmin ? grow50pc : growmin;
8356 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008357 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008358 if (newprev == NULL)
8359 {
8360 do_outofmem_msg((long_u)prevsize);
8361 failed = TRUE;
8362 break;
8363 }
8364 prev = newprev;
8365 }
8366 /* Add the line part to end of "prev". */
8367 mch_memmove(prev + prevlen, start, p - start);
8368 prevlen += (long)(p - start);
8369 }
8370 } /* while */
8371
8372 /*
8373 * For a negative line count use only the lines at the end of the file,
8374 * free the rest.
8375 */
8376 if (!failed && maxline < 0)
8377 while (cnt > -maxline)
8378 {
8379 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8380 --cnt;
8381 }
8382
8383 if (failed)
8384 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008385 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008387 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 }
8389
8390 vim_free(prev);
8391 fclose(fd);
8392}
8393
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008394 static void
8395return_register(int regname, typval_T *rettv)
8396{
8397 char_u buf[2] = {0, 0};
8398
8399 buf[0] = (char_u)regname;
8400 rettv->v_type = VAR_STRING;
8401 rettv->vval.v_string = vim_strsave(buf);
8402}
8403
8404/*
8405 * "reg_executing()" function
8406 */
8407 static void
8408f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8409{
8410 return_register(reg_executing, rettv);
8411}
8412
8413/*
8414 * "reg_recording()" function
8415 */
8416 static void
8417f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8418{
8419 return_register(reg_recording, rettv);
8420}
8421
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008422#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008423/*
8424 * Convert a List to proftime_T.
8425 * Return FAIL when there is something wrong.
8426 */
8427 static int
8428list2proftime(typval_T *arg, proftime_T *tm)
8429{
8430 long n1, n2;
8431 int error = FALSE;
8432
8433 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8434 || arg->vval.v_list->lv_len != 2)
8435 return FAIL;
8436 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8437 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008438# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008439 tm->HighPart = n1;
8440 tm->LowPart = n2;
8441# else
8442 tm->tv_sec = n1;
8443 tm->tv_usec = n2;
8444# endif
8445 return error ? FAIL : OK;
8446}
8447#endif /* FEAT_RELTIME */
8448
8449/*
8450 * "reltime()" function
8451 */
8452 static void
8453f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8454{
8455#ifdef FEAT_RELTIME
8456 proftime_T res;
8457 proftime_T start;
8458
8459 if (argvars[0].v_type == VAR_UNKNOWN)
8460 {
8461 /* No arguments: get current time. */
8462 profile_start(&res);
8463 }
8464 else if (argvars[1].v_type == VAR_UNKNOWN)
8465 {
8466 if (list2proftime(&argvars[0], &res) == FAIL)
8467 return;
8468 profile_end(&res);
8469 }
8470 else
8471 {
8472 /* Two arguments: compute the difference. */
8473 if (list2proftime(&argvars[0], &start) == FAIL
8474 || list2proftime(&argvars[1], &res) == FAIL)
8475 return;
8476 profile_sub(&res, &start);
8477 }
8478
8479 if (rettv_list_alloc(rettv) == OK)
8480 {
8481 long n1, n2;
8482
Bram Moolenaar4f974752019-02-17 17:44:42 +01008483# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008484 n1 = res.HighPart;
8485 n2 = res.LowPart;
8486# else
8487 n1 = res.tv_sec;
8488 n2 = res.tv_usec;
8489# endif
8490 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8491 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8492 }
8493#endif
8494}
8495
8496#ifdef FEAT_FLOAT
8497/*
8498 * "reltimefloat()" function
8499 */
8500 static void
8501f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8502{
8503# ifdef FEAT_RELTIME
8504 proftime_T tm;
8505# endif
8506
8507 rettv->v_type = VAR_FLOAT;
8508 rettv->vval.v_float = 0;
8509# ifdef FEAT_RELTIME
8510 if (list2proftime(&argvars[0], &tm) == OK)
8511 rettv->vval.v_float = profile_float(&tm);
8512# endif
8513}
8514#endif
8515
8516/*
8517 * "reltimestr()" function
8518 */
8519 static void
8520f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8521{
8522#ifdef FEAT_RELTIME
8523 proftime_T tm;
8524#endif
8525
8526 rettv->v_type = VAR_STRING;
8527 rettv->vval.v_string = NULL;
8528#ifdef FEAT_RELTIME
8529 if (list2proftime(&argvars[0], &tm) == OK)
8530 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8531#endif
8532}
8533
8534#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008535 static void
8536make_connection(void)
8537{
8538 if (X_DISPLAY == NULL
8539# ifdef FEAT_GUI
8540 && !gui.in_use
8541# endif
8542 )
8543 {
8544 x_force_connect = TRUE;
8545 setup_term_clip();
8546 x_force_connect = FALSE;
8547 }
8548}
8549
8550 static int
8551check_connection(void)
8552{
8553 make_connection();
8554 if (X_DISPLAY == NULL)
8555 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008556 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008557 return FAIL;
8558 }
8559 return OK;
8560}
8561#endif
8562
8563#ifdef FEAT_CLIENTSERVER
8564 static void
8565remote_common(typval_T *argvars, typval_T *rettv, int expr)
8566{
8567 char_u *server_name;
8568 char_u *keys;
8569 char_u *r = NULL;
8570 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008571 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008572# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008573 HWND w;
8574# else
8575 Window w;
8576# endif
8577
8578 if (check_restricted() || check_secure())
8579 return;
8580
8581# ifdef FEAT_X11
8582 if (check_connection() == FAIL)
8583 return;
8584# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008585 if (argvars[2].v_type != VAR_UNKNOWN
8586 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008587 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008588
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008589 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008590 if (server_name == NULL)
8591 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008592 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008593# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008594 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008596 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8597 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008598# endif
8599 {
8600 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008601 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008602 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008603 vim_free(r);
8604 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008605 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008606 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 return;
8608 }
8609
8610 rettv->vval.v_string = r;
8611
8612 if (argvars[2].v_type != VAR_UNKNOWN)
8613 {
8614 dictitem_T v;
8615 char_u str[30];
8616 char_u *idvar;
8617
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008618 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008619 if (idvar != NULL && *idvar != NUL)
8620 {
8621 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8622 v.di_tv.v_type = VAR_STRING;
8623 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008624 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008625 vim_free(v.di_tv.vval.v_string);
8626 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008627 }
8628}
8629#endif
8630
8631/*
8632 * "remote_expr()" function
8633 */
8634 static void
8635f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8636{
8637 rettv->v_type = VAR_STRING;
8638 rettv->vval.v_string = NULL;
8639#ifdef FEAT_CLIENTSERVER
8640 remote_common(argvars, rettv, TRUE);
8641#endif
8642}
8643
8644/*
8645 * "remote_foreground()" function
8646 */
8647 static void
8648f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8649{
8650#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008651# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008652 /* On Win32 it's done in this application. */
8653 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008654 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008655
8656 if (server_name != NULL)
8657 serverForeground(server_name);
8658 }
8659# else
8660 /* Send a foreground() expression to the server. */
8661 argvars[1].v_type = VAR_STRING;
8662 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8663 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008664 rettv->v_type = VAR_STRING;
8665 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008666 remote_common(argvars, rettv, TRUE);
8667 vim_free(argvars[1].vval.v_string);
8668# endif
8669#endif
8670}
8671
8672 static void
8673f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8674{
8675#ifdef FEAT_CLIENTSERVER
8676 dictitem_T v;
8677 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008678# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008679 long_u n = 0;
8680# endif
8681 char_u *serverid;
8682
8683 if (check_restricted() || check_secure())
8684 {
8685 rettv->vval.v_number = -1;
8686 return;
8687 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008688 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689 if (serverid == NULL)
8690 {
8691 rettv->vval.v_number = -1;
8692 return; /* type error; errmsg already given */
8693 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008694# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008695 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8696 if (n == 0)
8697 rettv->vval.v_number = -1;
8698 else
8699 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008700 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008701 rettv->vval.v_number = (s != NULL);
8702 }
8703# else
8704 if (check_connection() == FAIL)
8705 return;
8706
8707 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8708 serverStrToWin(serverid), &s);
8709# endif
8710
8711 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8712 {
8713 char_u *retvar;
8714
8715 v.di_tv.v_type = VAR_STRING;
8716 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008717 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008718 if (retvar != NULL)
8719 set_var(retvar, &v.di_tv, FALSE);
8720 vim_free(v.di_tv.vval.v_string);
8721 }
8722#else
8723 rettv->vval.v_number = -1;
8724#endif
8725}
8726
8727 static void
8728f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8729{
8730 char_u *r = NULL;
8731
8732#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008733 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008734
8735 if (serverid != NULL && !check_restricted() && !check_secure())
8736 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008737 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008738# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008739 /* The server's HWND is encoded in the 'id' parameter */
8740 long_u n = 0;
8741# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008742
8743 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008744 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008745
Bram Moolenaar4f974752019-02-17 17:44:42 +01008746# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008747 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8748 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008749 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008750 if (r == NULL)
8751# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008752 if (check_connection() == FAIL
8753 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8754 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008755# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008756 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008757 }
8758#endif
8759 rettv->v_type = VAR_STRING;
8760 rettv->vval.v_string = r;
8761}
8762
8763/*
8764 * "remote_send()" function
8765 */
8766 static void
8767f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8768{
8769 rettv->v_type = VAR_STRING;
8770 rettv->vval.v_string = NULL;
8771#ifdef FEAT_CLIENTSERVER
8772 remote_common(argvars, rettv, FALSE);
8773#endif
8774}
8775
8776/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008777 * "remote_startserver()" function
8778 */
8779 static void
8780f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8781{
8782#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008783 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008784
8785 if (server == NULL)
8786 return; /* type error; errmsg already given */
8787 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008788 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008789 else
8790 {
8791# ifdef FEAT_X11
8792 if (check_connection() == OK)
8793 serverRegisterName(X_DISPLAY, server);
8794# else
8795 serverSetName(server);
8796# endif
8797 }
8798#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008799 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008800#endif
8801}
8802
8803/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008804 * "remove()" function
8805 */
8806 static void
8807f_remove(typval_T *argvars, typval_T *rettv)
8808{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008809 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8810
8811 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008812 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008813 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008814 blob_remove(argvars, rettv);
8815 else if (argvars[0].v_type == VAR_LIST)
8816 list_remove(argvars, rettv, arg_errmsg);
8817 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008818 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008819}
8820
8821/*
8822 * "rename({from}, {to})" function
8823 */
8824 static void
8825f_rename(typval_T *argvars, typval_T *rettv)
8826{
8827 char_u buf[NUMBUFLEN];
8828
8829 if (check_restricted() || check_secure())
8830 rettv->vval.v_number = -1;
8831 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008832 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8833 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008834}
8835
8836/*
8837 * "repeat()" function
8838 */
8839 static void
8840f_repeat(typval_T *argvars, typval_T *rettv)
8841{
8842 char_u *p;
8843 int n;
8844 int slen;
8845 int len;
8846 char_u *r;
8847 int i;
8848
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008849 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008850 if (argvars[0].v_type == VAR_LIST)
8851 {
8852 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8853 while (n-- > 0)
8854 if (list_extend(rettv->vval.v_list,
8855 argvars[0].vval.v_list, NULL) == FAIL)
8856 break;
8857 }
8858 else
8859 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008860 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008861 rettv->v_type = VAR_STRING;
8862 rettv->vval.v_string = NULL;
8863
8864 slen = (int)STRLEN(p);
8865 len = slen * n;
8866 if (len <= 0)
8867 return;
8868
8869 r = alloc(len + 1);
8870 if (r != NULL)
8871 {
8872 for (i = 0; i < n; i++)
8873 mch_memmove(r + i * slen, p, (size_t)slen);
8874 r[len] = NUL;
8875 }
8876
8877 rettv->vval.v_string = r;
8878 }
8879}
8880
8881/*
8882 * "resolve()" function
8883 */
8884 static void
8885f_resolve(typval_T *argvars, typval_T *rettv)
8886{
8887 char_u *p;
8888#ifdef HAVE_READLINK
8889 char_u *buf = NULL;
8890#endif
8891
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008892 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008893#ifdef FEAT_SHORTCUT
8894 {
8895 char_u *v = NULL;
8896
Bram Moolenaardce1e892019-02-10 23:18:53 +01008897 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008898 if (v != NULL)
8899 rettv->vval.v_string = v;
8900 else
8901 rettv->vval.v_string = vim_strsave(p);
8902 }
8903#else
8904# ifdef HAVE_READLINK
8905 {
8906 char_u *cpy;
8907 int len;
8908 char_u *remain = NULL;
8909 char_u *q;
8910 int is_relative_to_current = FALSE;
8911 int has_trailing_pathsep = FALSE;
8912 int limit = 100;
8913
8914 p = vim_strsave(p);
8915
8916 if (p[0] == '.' && (vim_ispathsep(p[1])
8917 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8918 is_relative_to_current = TRUE;
8919
8920 len = STRLEN(p);
8921 if (len > 0 && after_pathsep(p, p + len))
8922 {
8923 has_trailing_pathsep = TRUE;
8924 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8925 }
8926
8927 q = getnextcomp(p);
8928 if (*q != NUL)
8929 {
8930 /* Separate the first path component in "p", and keep the
8931 * remainder (beginning with the path separator). */
8932 remain = vim_strsave(q - 1);
8933 q[-1] = NUL;
8934 }
8935
8936 buf = alloc(MAXPATHL + 1);
8937 if (buf == NULL)
8938 goto fail;
8939
8940 for (;;)
8941 {
8942 for (;;)
8943 {
8944 len = readlink((char *)p, (char *)buf, MAXPATHL);
8945 if (len <= 0)
8946 break;
8947 buf[len] = NUL;
8948
8949 if (limit-- == 0)
8950 {
8951 vim_free(p);
8952 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008953 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008954 rettv->vval.v_string = NULL;
8955 goto fail;
8956 }
8957
8958 /* Ensure that the result will have a trailing path separator
8959 * if the argument has one. */
8960 if (remain == NULL && has_trailing_pathsep)
8961 add_pathsep(buf);
8962
8963 /* Separate the first path component in the link value and
8964 * concatenate the remainders. */
8965 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8966 if (*q != NUL)
8967 {
8968 if (remain == NULL)
8969 remain = vim_strsave(q - 1);
8970 else
8971 {
8972 cpy = concat_str(q - 1, remain);
8973 if (cpy != NULL)
8974 {
8975 vim_free(remain);
8976 remain = cpy;
8977 }
8978 }
8979 q[-1] = NUL;
8980 }
8981
8982 q = gettail(p);
8983 if (q > p && *q == NUL)
8984 {
8985 /* Ignore trailing path separator. */
8986 q[-1] = NUL;
8987 q = gettail(p);
8988 }
8989 if (q > p && !mch_isFullName(buf))
8990 {
8991 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02008992 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008993 if (cpy != NULL)
8994 {
8995 STRCPY(cpy, p);
8996 STRCPY(gettail(cpy), buf);
8997 vim_free(p);
8998 p = cpy;
8999 }
9000 }
9001 else
9002 {
9003 vim_free(p);
9004 p = vim_strsave(buf);
9005 }
9006 }
9007
9008 if (remain == NULL)
9009 break;
9010
9011 /* Append the first path component of "remain" to "p". */
9012 q = getnextcomp(remain + 1);
9013 len = q - remain - (*q != NUL);
9014 cpy = vim_strnsave(p, STRLEN(p) + len);
9015 if (cpy != NULL)
9016 {
9017 STRNCAT(cpy, remain, len);
9018 vim_free(p);
9019 p = cpy;
9020 }
9021 /* Shorten "remain". */
9022 if (*q != NUL)
9023 STRMOVE(remain, q - 1);
9024 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009025 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 }
9027
9028 /* If the result is a relative path name, make it explicitly relative to
9029 * the current directory if and only if the argument had this form. */
9030 if (!vim_ispathsep(*p))
9031 {
9032 if (is_relative_to_current
9033 && *p != NUL
9034 && !(p[0] == '.'
9035 && (p[1] == NUL
9036 || vim_ispathsep(p[1])
9037 || (p[1] == '.'
9038 && (p[2] == NUL
9039 || vim_ispathsep(p[2]))))))
9040 {
9041 /* Prepend "./". */
9042 cpy = concat_str((char_u *)"./", p);
9043 if (cpy != NULL)
9044 {
9045 vim_free(p);
9046 p = cpy;
9047 }
9048 }
9049 else if (!is_relative_to_current)
9050 {
9051 /* Strip leading "./". */
9052 q = p;
9053 while (q[0] == '.' && vim_ispathsep(q[1]))
9054 q += 2;
9055 if (q > p)
9056 STRMOVE(p, p + 2);
9057 }
9058 }
9059
9060 /* Ensure that the result will have no trailing path separator
9061 * if the argument had none. But keep "/" or "//". */
9062 if (!has_trailing_pathsep)
9063 {
9064 q = p + STRLEN(p);
9065 if (after_pathsep(p, q))
9066 *gettail_sep(p) = NUL;
9067 }
9068
9069 rettv->vval.v_string = p;
9070 }
9071# else
9072 rettv->vval.v_string = vim_strsave(p);
9073# endif
9074#endif
9075
9076 simplify_filename(rettv->vval.v_string);
9077
9078#ifdef HAVE_READLINK
9079fail:
9080 vim_free(buf);
9081#endif
9082 rettv->v_type = VAR_STRING;
9083}
9084
9085/*
9086 * "reverse({list})" function
9087 */
9088 static void
9089f_reverse(typval_T *argvars, typval_T *rettv)
9090{
9091 list_T *l;
9092 listitem_T *li, *ni;
9093
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009094 if (argvars[0].v_type == VAR_BLOB)
9095 {
9096 blob_T *b = argvars[0].vval.v_blob;
9097 int i, len = blob_len(b);
9098
9099 for (i = 0; i < len / 2; i++)
9100 {
9101 int tmp = blob_get(b, i);
9102
9103 blob_set(b, i, blob_get(b, len - i - 1));
9104 blob_set(b, len - i - 1, tmp);
9105 }
9106 rettv_blob_set(rettv, b);
9107 return;
9108 }
9109
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009110 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009111 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009112 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009113 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009114 (char_u *)N_("reverse() argument"), TRUE))
9115 {
9116 li = l->lv_last;
9117 l->lv_first = l->lv_last = NULL;
9118 l->lv_len = 0;
9119 while (li != NULL)
9120 {
9121 ni = li->li_prev;
9122 list_append(l, li);
9123 li = ni;
9124 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009125 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009126 l->lv_idx = l->lv_len - l->lv_idx - 1;
9127 }
9128}
9129
9130#define SP_NOMOVE 0x01 /* don't move cursor */
9131#define SP_REPEAT 0x02 /* repeat to find outer pair */
9132#define SP_RETCOUNT 0x04 /* return matchcount */
9133#define SP_SETPCMARK 0x08 /* set previous context mark */
9134#define SP_START 0x10 /* accept match at start position */
9135#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9136#define SP_END 0x40 /* leave cursor at end of match */
9137#define SP_COLUMN 0x80 /* start at cursor column */
9138
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009139/*
9140 * Get flags for a search function.
9141 * Possibly sets "p_ws".
9142 * Returns BACKWARD, FORWARD or zero (for an error).
9143 */
9144 static int
9145get_search_arg(typval_T *varp, int *flagsp)
9146{
9147 int dir = FORWARD;
9148 char_u *flags;
9149 char_u nbuf[NUMBUFLEN];
9150 int mask;
9151
9152 if (varp->v_type != VAR_UNKNOWN)
9153 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009154 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009155 if (flags == NULL)
9156 return 0; /* type error; errmsg already given */
9157 while (*flags != NUL)
9158 {
9159 switch (*flags)
9160 {
9161 case 'b': dir = BACKWARD; break;
9162 case 'w': p_ws = TRUE; break;
9163 case 'W': p_ws = FALSE; break;
9164 default: mask = 0;
9165 if (flagsp != NULL)
9166 switch (*flags)
9167 {
9168 case 'c': mask = SP_START; break;
9169 case 'e': mask = SP_END; break;
9170 case 'm': mask = SP_RETCOUNT; break;
9171 case 'n': mask = SP_NOMOVE; break;
9172 case 'p': mask = SP_SUBPAT; break;
9173 case 'r': mask = SP_REPEAT; break;
9174 case 's': mask = SP_SETPCMARK; break;
9175 case 'z': mask = SP_COLUMN; break;
9176 }
9177 if (mask == 0)
9178 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009179 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009180 dir = 0;
9181 }
9182 else
9183 *flagsp |= mask;
9184 }
9185 if (dir == 0)
9186 break;
9187 ++flags;
9188 }
9189 }
9190 return dir;
9191}
9192
9193/*
9194 * Shared by search() and searchpos() functions.
9195 */
9196 static int
9197search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9198{
9199 int flags;
9200 char_u *pat;
9201 pos_T pos;
9202 pos_T save_cursor;
9203 int save_p_ws = p_ws;
9204 int dir;
9205 int retval = 0; /* default: FAIL */
9206 long lnum_stop = 0;
9207 proftime_T tm;
9208#ifdef FEAT_RELTIME
9209 long time_limit = 0;
9210#endif
9211 int options = SEARCH_KEEP;
9212 int subpatnum;
9213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009214 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009215 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9216 if (dir == 0)
9217 goto theend;
9218 flags = *flagsp;
9219 if (flags & SP_START)
9220 options |= SEARCH_START;
9221 if (flags & SP_END)
9222 options |= SEARCH_END;
9223 if (flags & SP_COLUMN)
9224 options |= SEARCH_COL;
9225
9226 /* Optional arguments: line number to stop searching and timeout. */
9227 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9228 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009229 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009230 if (lnum_stop < 0)
9231 goto theend;
9232#ifdef FEAT_RELTIME
9233 if (argvars[3].v_type != VAR_UNKNOWN)
9234 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009235 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009236 if (time_limit < 0)
9237 goto theend;
9238 }
9239#endif
9240 }
9241
9242#ifdef FEAT_RELTIME
9243 /* Set the time limit, if there is one. */
9244 profile_setlimit(time_limit, &tm);
9245#endif
9246
9247 /*
9248 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9249 * Check to make sure only those flags are set.
9250 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9251 * flags cannot be set. Check for that condition also.
9252 */
9253 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9254 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9255 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009256 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009257 goto theend;
9258 }
9259
9260 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009261 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009262 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009263 if (subpatnum != FAIL)
9264 {
9265 if (flags & SP_SUBPAT)
9266 retval = subpatnum;
9267 else
9268 retval = pos.lnum;
9269 if (flags & SP_SETPCMARK)
9270 setpcmark();
9271 curwin->w_cursor = pos;
9272 if (match_pos != NULL)
9273 {
9274 /* Store the match cursor position */
9275 match_pos->lnum = pos.lnum;
9276 match_pos->col = pos.col + 1;
9277 }
9278 /* "/$" will put the cursor after the end of the line, may need to
9279 * correct that here */
9280 check_cursor();
9281 }
9282
9283 /* If 'n' flag is used: restore cursor position. */
9284 if (flags & SP_NOMOVE)
9285 curwin->w_cursor = save_cursor;
9286 else
9287 curwin->w_set_curswant = TRUE;
9288theend:
9289 p_ws = save_p_ws;
9290
9291 return retval;
9292}
9293
9294#ifdef FEAT_FLOAT
9295
9296/*
9297 * round() is not in C90, use ceil() or floor() instead.
9298 */
9299 float_T
9300vim_round(float_T f)
9301{
9302 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9303}
9304
9305/*
9306 * "round({float})" function
9307 */
9308 static void
9309f_round(typval_T *argvars, typval_T *rettv)
9310{
9311 float_T f = 0.0;
9312
9313 rettv->v_type = VAR_FLOAT;
9314 if (get_float_arg(argvars, &f) == OK)
9315 rettv->vval.v_float = vim_round(f);
9316 else
9317 rettv->vval.v_float = 0.0;
9318}
9319#endif
9320
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009321#ifdef FEAT_RUBY
9322/*
9323 * "rubyeval()" function
9324 */
9325 static void
9326f_rubyeval(typval_T *argvars, typval_T *rettv)
9327{
9328 char_u *str;
9329 char_u buf[NUMBUFLEN];
9330
9331 str = tv_get_string_buf(&argvars[0], buf);
9332 do_rubyeval(str, rettv);
9333}
9334#endif
9335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009336/*
9337 * "screenattr()" function
9338 */
9339 static void
9340f_screenattr(typval_T *argvars, typval_T *rettv)
9341{
9342 int row;
9343 int col;
9344 int c;
9345
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009346 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9347 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009348 if (row < 0 || row >= screen_Rows
9349 || col < 0 || col >= screen_Columns)
9350 c = -1;
9351 else
9352 c = ScreenAttrs[LineOffset[row] + col];
9353 rettv->vval.v_number = c;
9354}
9355
9356/*
9357 * "screenchar()" function
9358 */
9359 static void
9360f_screenchar(typval_T *argvars, typval_T *rettv)
9361{
9362 int row;
9363 int col;
9364 int off;
9365 int c;
9366
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009367 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9368 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009369 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009370 c = -1;
9371 else
9372 {
9373 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009374 if (enc_utf8 && ScreenLinesUC[off] != 0)
9375 c = ScreenLinesUC[off];
9376 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009377 c = ScreenLines[off];
9378 }
9379 rettv->vval.v_number = c;
9380}
9381
9382/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009383 * "screenchars()" function
9384 */
9385 static void
9386f_screenchars(typval_T *argvars, typval_T *rettv)
9387{
9388 int row;
9389 int col;
9390 int off;
9391 int c;
9392 int i;
9393
9394 if (rettv_list_alloc(rettv) == FAIL)
9395 return;
9396 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9397 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9398 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9399 return;
9400
9401 off = LineOffset[row] + col;
9402 if (enc_utf8 && ScreenLinesUC[off] != 0)
9403 c = ScreenLinesUC[off];
9404 else
9405 c = ScreenLines[off];
9406 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9407
9408 if (enc_utf8)
9409
9410 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9411 list_append_number(rettv->vval.v_list,
9412 (varnumber_T)ScreenLinesC[i][off]);
9413}
9414
9415/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009416 * "screencol()" function
9417 *
9418 * First column is 1 to be consistent with virtcol().
9419 */
9420 static void
9421f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9422{
9423 rettv->vval.v_number = screen_screencol() + 1;
9424}
9425
9426/*
9427 * "screenrow()" function
9428 */
9429 static void
9430f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9431{
9432 rettv->vval.v_number = screen_screenrow() + 1;
9433}
9434
9435/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009436 * "screenstring()" function
9437 */
9438 static void
9439f_screenstring(typval_T *argvars, typval_T *rettv)
9440{
9441 int row;
9442 int col;
9443 int off;
9444 int c;
9445 int i;
9446 char_u buf[MB_MAXBYTES + 1];
9447 int buflen = 0;
9448
9449 rettv->vval.v_string = NULL;
9450 rettv->v_type = VAR_STRING;
9451
9452 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9453 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9454 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9455 return;
9456
9457 off = LineOffset[row] + col;
9458 if (enc_utf8 && ScreenLinesUC[off] != 0)
9459 c = ScreenLinesUC[off];
9460 else
9461 c = ScreenLines[off];
9462 buflen += mb_char2bytes(c, buf);
9463
9464 if (enc_utf8)
9465 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9466 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9467
9468 buf[buflen] = NUL;
9469 rettv->vval.v_string = vim_strsave(buf);
9470}
9471
9472/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009473 * "search()" function
9474 */
9475 static void
9476f_search(typval_T *argvars, typval_T *rettv)
9477{
9478 int flags = 0;
9479
9480 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9481}
9482
9483/*
9484 * "searchdecl()" function
9485 */
9486 static void
9487f_searchdecl(typval_T *argvars, typval_T *rettv)
9488{
9489 int locally = 1;
9490 int thisblock = 0;
9491 int error = FALSE;
9492 char_u *name;
9493
9494 rettv->vval.v_number = 1; /* default: FAIL */
9495
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009496 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009497 if (argvars[1].v_type != VAR_UNKNOWN)
9498 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009499 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009500 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009501 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009502 }
9503 if (!error && name != NULL)
9504 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9505 locally, thisblock, SEARCH_KEEP) == FAIL;
9506}
9507
9508/*
9509 * Used by searchpair() and searchpairpos()
9510 */
9511 static int
9512searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9513{
9514 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009515 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009516 int save_p_ws = p_ws;
9517 int dir;
9518 int flags = 0;
9519 char_u nbuf1[NUMBUFLEN];
9520 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009521 int retval = 0; /* default: FAIL */
9522 long lnum_stop = 0;
9523 long time_limit = 0;
9524
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009525 /* Get the three pattern arguments: start, middle, end. Will result in an
9526 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009527 spat = tv_get_string_chk(&argvars[0]);
9528 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9529 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009530 if (spat == NULL || mpat == NULL || epat == NULL)
9531 goto theend; /* type error */
9532
9533 /* Handle the optional fourth argument: flags */
9534 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9535 if (dir == 0)
9536 goto theend;
9537
9538 /* Don't accept SP_END or SP_SUBPAT.
9539 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9540 */
9541 if ((flags & (SP_END | SP_SUBPAT)) != 0
9542 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9543 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009544 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009545 goto theend;
9546 }
9547
9548 /* Using 'r' implies 'W', otherwise it doesn't work. */
9549 if (flags & SP_REPEAT)
9550 p_ws = FALSE;
9551
9552 /* Optional fifth argument: skip expression */
9553 if (argvars[3].v_type == VAR_UNKNOWN
9554 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009555 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009556 else
9557 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009558 skip = &argvars[4];
9559 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9560 && skip->v_type != VAR_STRING)
9561 {
9562 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009563 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009564 goto theend;
9565 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009566 if (argvars[5].v_type != VAR_UNKNOWN)
9567 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009568 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009569 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009570 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009571 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009572 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009573 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009574#ifdef FEAT_RELTIME
9575 if (argvars[6].v_type != VAR_UNKNOWN)
9576 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009577 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009578 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009579 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009580 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009581 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009582 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009583 }
9584#endif
9585 }
9586 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009587
9588 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9589 match_pos, lnum_stop, time_limit);
9590
9591theend:
9592 p_ws = save_p_ws;
9593
9594 return retval;
9595}
9596
9597/*
9598 * "searchpair()" function
9599 */
9600 static void
9601f_searchpair(typval_T *argvars, typval_T *rettv)
9602{
9603 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9604}
9605
9606/*
9607 * "searchpairpos()" function
9608 */
9609 static void
9610f_searchpairpos(typval_T *argvars, typval_T *rettv)
9611{
9612 pos_T match_pos;
9613 int lnum = 0;
9614 int col = 0;
9615
9616 if (rettv_list_alloc(rettv) == FAIL)
9617 return;
9618
9619 if (searchpair_cmn(argvars, &match_pos) > 0)
9620 {
9621 lnum = match_pos.lnum;
9622 col = match_pos.col;
9623 }
9624
9625 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9626 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9627}
9628
9629/*
9630 * Search for a start/middle/end thing.
9631 * Used by searchpair(), see its documentation for the details.
9632 * Returns 0 or -1 for no match,
9633 */
9634 long
9635do_searchpair(
9636 char_u *spat, /* start pattern */
9637 char_u *mpat, /* middle pattern */
9638 char_u *epat, /* end pattern */
9639 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009640 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009641 int flags, /* SP_SETPCMARK and other SP_ values */
9642 pos_T *match_pos,
9643 linenr_T lnum_stop, /* stop at this line if not zero */
9644 long time_limit UNUSED) /* stop after this many msec */
9645{
9646 char_u *save_cpo;
9647 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9648 long retval = 0;
9649 pos_T pos;
9650 pos_T firstpos;
9651 pos_T foundpos;
9652 pos_T save_cursor;
9653 pos_T save_pos;
9654 int n;
9655 int r;
9656 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009657 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009658 int err;
9659 int options = SEARCH_KEEP;
9660 proftime_T tm;
9661
9662 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9663 save_cpo = p_cpo;
9664 p_cpo = empty_option;
9665
9666#ifdef FEAT_RELTIME
9667 /* Set the time limit, if there is one. */
9668 profile_setlimit(time_limit, &tm);
9669#endif
9670
9671 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9672 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009673 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9674 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009675 if (pat2 == NULL || pat3 == NULL)
9676 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009677 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009678 if (*mpat == NUL)
9679 STRCPY(pat3, pat2);
9680 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009681 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009682 spat, epat, mpat);
9683 if (flags & SP_START)
9684 options |= SEARCH_START;
9685
Bram Moolenaar48570482017-10-30 21:48:41 +01009686 if (skip != NULL)
9687 {
9688 /* Empty string means to not use the skip expression. */
9689 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9690 use_skip = skip->vval.v_string != NULL
9691 && *skip->vval.v_string != NUL;
9692 }
9693
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009694 save_cursor = curwin->w_cursor;
9695 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009696 CLEAR_POS(&firstpos);
9697 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009698 pat = pat3;
9699 for (;;)
9700 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009701 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009702 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009703 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009704 /* didn't find it or found the first match again: FAIL */
9705 break;
9706
9707 if (firstpos.lnum == 0)
9708 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009709 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009710 {
9711 /* Found the same position again. Can happen with a pattern that
9712 * has "\zs" at the end and searching backwards. Advance one
9713 * character and try again. */
9714 if (dir == BACKWARD)
9715 decl(&pos);
9716 else
9717 incl(&pos);
9718 }
9719 foundpos = pos;
9720
9721 /* clear the start flag to avoid getting stuck here */
9722 options &= ~SEARCH_START;
9723
9724 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009725 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009726 {
9727 save_pos = curwin->w_cursor;
9728 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009729 err = FALSE;
9730 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009731 curwin->w_cursor = save_pos;
9732 if (err)
9733 {
9734 /* Evaluating {skip} caused an error, break here. */
9735 curwin->w_cursor = save_cursor;
9736 retval = -1;
9737 break;
9738 }
9739 if (r)
9740 continue;
9741 }
9742
9743 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9744 {
9745 /* Found end when searching backwards or start when searching
9746 * forward: nested pair. */
9747 ++nest;
9748 pat = pat2; /* nested, don't search for middle */
9749 }
9750 else
9751 {
9752 /* Found end when searching forward or start when searching
9753 * backward: end of (nested) pair; or found middle in outer pair. */
9754 if (--nest == 1)
9755 pat = pat3; /* outer level, search for middle */
9756 }
9757
9758 if (nest == 0)
9759 {
9760 /* Found the match: return matchcount or line number. */
9761 if (flags & SP_RETCOUNT)
9762 ++retval;
9763 else
9764 retval = pos.lnum;
9765 if (flags & SP_SETPCMARK)
9766 setpcmark();
9767 curwin->w_cursor = pos;
9768 if (!(flags & SP_REPEAT))
9769 break;
9770 nest = 1; /* search for next unmatched */
9771 }
9772 }
9773
9774 if (match_pos != NULL)
9775 {
9776 /* Store the match cursor position */
9777 match_pos->lnum = curwin->w_cursor.lnum;
9778 match_pos->col = curwin->w_cursor.col + 1;
9779 }
9780
9781 /* If 'n' flag is used or search failed: restore cursor position. */
9782 if ((flags & SP_NOMOVE) || retval == 0)
9783 curwin->w_cursor = save_cursor;
9784
9785theend:
9786 vim_free(pat2);
9787 vim_free(pat3);
9788 if (p_cpo == empty_option)
9789 p_cpo = save_cpo;
9790 else
9791 /* Darn, evaluating the {skip} expression changed the value. */
9792 free_string_option(save_cpo);
9793
9794 return retval;
9795}
9796
9797/*
9798 * "searchpos()" function
9799 */
9800 static void
9801f_searchpos(typval_T *argvars, typval_T *rettv)
9802{
9803 pos_T match_pos;
9804 int lnum = 0;
9805 int col = 0;
9806 int n;
9807 int flags = 0;
9808
9809 if (rettv_list_alloc(rettv) == FAIL)
9810 return;
9811
9812 n = search_cmn(argvars, &match_pos, &flags);
9813 if (n > 0)
9814 {
9815 lnum = match_pos.lnum;
9816 col = match_pos.col;
9817 }
9818
9819 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9820 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9821 if (flags & SP_SUBPAT)
9822 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9823}
9824
9825 static void
9826f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9827{
9828#ifdef FEAT_CLIENTSERVER
9829 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009830 char_u *server = tv_get_string_chk(&argvars[0]);
9831 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009832
9833 rettv->vval.v_number = -1;
9834 if (server == NULL || reply == NULL)
9835 return;
9836 if (check_restricted() || check_secure())
9837 return;
9838# ifdef FEAT_X11
9839 if (check_connection() == FAIL)
9840 return;
9841# endif
9842
9843 if (serverSendReply(server, reply) < 0)
9844 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009845 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009846 return;
9847 }
9848 rettv->vval.v_number = 0;
9849#else
9850 rettv->vval.v_number = -1;
9851#endif
9852}
9853
9854 static void
9855f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9856{
9857 char_u *r = NULL;
9858
9859#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009860# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009861 r = serverGetVimNames();
9862# else
9863 make_connection();
9864 if (X_DISPLAY != NULL)
9865 r = serverGetVimNames(X_DISPLAY);
9866# endif
9867#endif
9868 rettv->v_type = VAR_STRING;
9869 rettv->vval.v_string = r;
9870}
9871
9872/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009873 * "setbufline()" function
9874 */
9875 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009876f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009877{
9878 linenr_T lnum;
9879 buf_T *buf;
9880
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009881 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009882 if (buf == NULL)
9883 rettv->vval.v_number = 1; /* FAIL */
9884 else
9885 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009886 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009887 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009888 }
9889}
9890
9891/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009892 * "setbufvar()" function
9893 */
9894 static void
9895f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9896{
9897 buf_T *buf;
9898 char_u *varname, *bufvarname;
9899 typval_T *varp;
9900 char_u nbuf[NUMBUFLEN];
9901
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009902 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009903 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009904 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
9905 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009906 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009907 varp = &argvars[2];
9908
9909 if (buf != NULL && varname != NULL && varp != NULL)
9910 {
9911 if (*varname == '&')
9912 {
9913 long numval;
9914 char_u *strval;
9915 int error = FALSE;
9916 aco_save_T aco;
9917
9918 /* set curbuf to be our buf, temporarily */
9919 aucmd_prepbuf(&aco, buf);
9920
9921 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009922 numval = (long)tv_get_number_chk(varp, &error);
9923 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009924 if (!error && strval != NULL)
9925 set_option_value(varname, numval, strval, OPT_LOCAL);
9926
9927 /* reset notion of buffer */
9928 aucmd_restbuf(&aco);
9929 }
9930 else
9931 {
9932 buf_T *save_curbuf = curbuf;
9933
Bram Moolenaar964b3742019-05-24 18:54:09 +02009934 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009935 if (bufvarname != NULL)
9936 {
9937 curbuf = buf;
9938 STRCPY(bufvarname, "b:");
9939 STRCPY(bufvarname + 2, varname);
9940 set_var(bufvarname, varp, TRUE);
9941 vim_free(bufvarname);
9942 curbuf = save_curbuf;
9943 }
9944 }
9945 }
9946}
9947
9948 static void
9949f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9950{
9951 dict_T *d;
9952 dictitem_T *di;
9953 char_u *csearch;
9954
9955 if (argvars[0].v_type != VAR_DICT)
9956 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009957 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009958 return;
9959 }
9960
9961 if ((d = argvars[0].vval.v_dict) != NULL)
9962 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009963 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009964 if (csearch != NULL)
9965 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009966 if (enc_utf8)
9967 {
9968 int pcc[MAX_MCO];
9969 int c = utfc_ptr2char(csearch, pcc);
9970
9971 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9972 }
9973 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009974 set_last_csearch(PTR2CHAR(csearch),
9975 csearch, MB_PTR2LEN(csearch));
9976 }
9977
9978 di = dict_find(d, (char_u *)"forward", -1);
9979 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009980 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009981 ? FORWARD : BACKWARD);
9982
9983 di = dict_find(d, (char_u *)"until", -1);
9984 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009985 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009986 }
9987}
9988
9989/*
9990 * "setcmdpos()" function
9991 */
9992 static void
9993f_setcmdpos(typval_T *argvars, typval_T *rettv)
9994{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009995 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009996
9997 if (pos >= 0)
9998 rettv->vval.v_number = set_cmdline_pos(pos);
9999}
10000
10001/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010002 * "setenv()" function
10003 */
10004 static void
10005f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10006{
10007 char_u namebuf[NUMBUFLEN];
10008 char_u valbuf[NUMBUFLEN];
10009 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10010
10011 if (argvars[1].v_type == VAR_SPECIAL
10012 && argvars[1].vval.v_number == VVAL_NULL)
10013 vim_unsetenv(name);
10014 else
10015 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10016}
10017
10018/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010019 * "setfperm({fname}, {mode})" function
10020 */
10021 static void
10022f_setfperm(typval_T *argvars, typval_T *rettv)
10023{
10024 char_u *fname;
10025 char_u modebuf[NUMBUFLEN];
10026 char_u *mode_str;
10027 int i;
10028 int mask;
10029 int mode = 0;
10030
10031 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010032 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010033 if (fname == NULL)
10034 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010035 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010036 if (mode_str == NULL)
10037 return;
10038 if (STRLEN(mode_str) != 9)
10039 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010040 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010041 return;
10042 }
10043
10044 mask = 1;
10045 for (i = 8; i >= 0; --i)
10046 {
10047 if (mode_str[i] != '-')
10048 mode |= mask;
10049 mask = mask << 1;
10050 }
10051 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10052}
10053
10054/*
10055 * "setline()" function
10056 */
10057 static void
10058f_setline(typval_T *argvars, typval_T *rettv)
10059{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010060 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010061
Bram Moolenaarca851592018-06-06 21:04:07 +020010062 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010063}
10064
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010065/*
10066 * Used by "setqflist()" and "setloclist()" functions
10067 */
10068 static void
10069set_qf_ll_list(
10070 win_T *wp UNUSED,
10071 typval_T *list_arg UNUSED,
10072 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010073 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010074 typval_T *rettv)
10075{
10076#ifdef FEAT_QUICKFIX
10077 static char *e_invact = N_("E927: Invalid action: '%s'");
10078 char_u *act;
10079 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010080 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010081#endif
10082
10083 rettv->vval.v_number = -1;
10084
10085#ifdef FEAT_QUICKFIX
10086 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010087 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010088 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010089 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010090 else
10091 {
10092 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010093 dict_T *d = NULL;
10094 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010095
10096 if (action_arg->v_type == VAR_STRING)
10097 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010098 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010099 if (act == NULL)
10100 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010101 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10102 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010103 action = *act;
10104 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010105 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010106 }
10107 else if (action_arg->v_type == VAR_UNKNOWN)
10108 action = ' ';
10109 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010110 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010111
Bram Moolenaard823fa92016-08-12 16:29:27 +020010112 if (action_arg->v_type != VAR_UNKNOWN
10113 && what_arg->v_type != VAR_UNKNOWN)
10114 {
10115 if (what_arg->v_type == VAR_DICT)
10116 d = what_arg->vval.v_dict;
10117 else
10118 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010119 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010120 valid_dict = FALSE;
10121 }
10122 }
10123
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010124 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010125 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010126 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10127 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010128 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010129 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010130 }
10131#endif
10132}
10133
10134/*
10135 * "setloclist()" function
10136 */
10137 static void
10138f_setloclist(typval_T *argvars, typval_T *rettv)
10139{
10140 win_T *win;
10141
10142 rettv->vval.v_number = -1;
10143
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010144 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010145 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010146 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010147}
10148
10149/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010150 * "setpos()" function
10151 */
10152 static void
10153f_setpos(typval_T *argvars, typval_T *rettv)
10154{
10155 pos_T pos;
10156 int fnum;
10157 char_u *name;
10158 colnr_T curswant = -1;
10159
10160 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010161 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010162 if (name != NULL)
10163 {
10164 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10165 {
10166 if (--pos.col < 0)
10167 pos.col = 0;
10168 if (name[0] == '.' && name[1] == NUL)
10169 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010170 /* set cursor; "fnum" is ignored */
10171 curwin->w_cursor = pos;
10172 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010173 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010174 curwin->w_curswant = curswant - 1;
10175 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010176 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010177 check_cursor();
10178 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010179 }
10180 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10181 {
10182 /* set mark */
10183 if (setmark_pos(name[1], &pos, fnum) == OK)
10184 rettv->vval.v_number = 0;
10185 }
10186 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010187 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010188 }
10189 }
10190}
10191
10192/*
10193 * "setqflist()" function
10194 */
10195 static void
10196f_setqflist(typval_T *argvars, typval_T *rettv)
10197{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010198 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010199}
10200
10201/*
10202 * "setreg()" function
10203 */
10204 static void
10205f_setreg(typval_T *argvars, typval_T *rettv)
10206{
10207 int regname;
10208 char_u *strregname;
10209 char_u *stropt;
10210 char_u *strval;
10211 int append;
10212 char_u yank_type;
10213 long block_len;
10214
10215 block_len = -1;
10216 yank_type = MAUTO;
10217 append = FALSE;
10218
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010219 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010220 rettv->vval.v_number = 1; /* FAIL is default */
10221
10222 if (strregname == NULL)
10223 return; /* type error; errmsg already given */
10224 regname = *strregname;
10225 if (regname == 0 || regname == '@')
10226 regname = '"';
10227
10228 if (argvars[2].v_type != VAR_UNKNOWN)
10229 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010230 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010231 if (stropt == NULL)
10232 return; /* type error */
10233 for (; *stropt != NUL; ++stropt)
10234 switch (*stropt)
10235 {
10236 case 'a': case 'A': /* append */
10237 append = TRUE;
10238 break;
10239 case 'v': case 'c': /* character-wise selection */
10240 yank_type = MCHAR;
10241 break;
10242 case 'V': case 'l': /* line-wise selection */
10243 yank_type = MLINE;
10244 break;
10245 case 'b': case Ctrl_V: /* block-wise selection */
10246 yank_type = MBLOCK;
10247 if (VIM_ISDIGIT(stropt[1]))
10248 {
10249 ++stropt;
10250 block_len = getdigits(&stropt) - 1;
10251 --stropt;
10252 }
10253 break;
10254 }
10255 }
10256
10257 if (argvars[1].v_type == VAR_LIST)
10258 {
10259 char_u **lstval;
10260 char_u **allocval;
10261 char_u buf[NUMBUFLEN];
10262 char_u **curval;
10263 char_u **curallocval;
10264 list_T *ll = argvars[1].vval.v_list;
10265 listitem_T *li;
10266 int len;
10267
10268 /* If the list is NULL handle like an empty list. */
10269 len = ll == NULL ? 0 : ll->lv_len;
10270
10271 /* First half: use for pointers to result lines; second half: use for
10272 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010273 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010274 if (lstval == NULL)
10275 return;
10276 curval = lstval;
10277 allocval = lstval + len + 2;
10278 curallocval = allocval;
10279
10280 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10281 li = li->li_next)
10282 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010283 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010284 if (strval == NULL)
10285 goto free_lstval;
10286 if (strval == buf)
10287 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010288 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010289 * overwrite the string. */
10290 strval = vim_strsave(buf);
10291 if (strval == NULL)
10292 goto free_lstval;
10293 *curallocval++ = strval;
10294 }
10295 *curval++ = strval;
10296 }
10297 *curval++ = NULL;
10298
10299 write_reg_contents_lst(regname, lstval, -1,
10300 append, yank_type, block_len);
10301free_lstval:
10302 while (curallocval > allocval)
10303 vim_free(*--curallocval);
10304 vim_free(lstval);
10305 }
10306 else
10307 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010308 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010309 if (strval == NULL)
10310 return;
10311 write_reg_contents_ex(regname, strval, -1,
10312 append, yank_type, block_len);
10313 }
10314 rettv->vval.v_number = 0;
10315}
10316
10317/*
10318 * "settabvar()" function
10319 */
10320 static void
10321f_settabvar(typval_T *argvars, typval_T *rettv)
10322{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010323 tabpage_T *save_curtab;
10324 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010325 char_u *varname, *tabvarname;
10326 typval_T *varp;
10327
10328 rettv->vval.v_number = 0;
10329
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010330 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010331 return;
10332
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010333 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10334 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010335 varp = &argvars[2];
10336
Bram Moolenaar4033c552017-09-16 20:54:51 +020010337 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010338 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010339 save_curtab = curtab;
10340 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010341
Bram Moolenaar964b3742019-05-24 18:54:09 +020010342 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010343 if (tabvarname != NULL)
10344 {
10345 STRCPY(tabvarname, "t:");
10346 STRCPY(tabvarname + 2, varname);
10347 set_var(tabvarname, varp, TRUE);
10348 vim_free(tabvarname);
10349 }
10350
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010351 /* Restore current tabpage */
10352 if (valid_tabpage(save_curtab))
10353 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010354 }
10355}
10356
10357/*
10358 * "settabwinvar()" function
10359 */
10360 static void
10361f_settabwinvar(typval_T *argvars, typval_T *rettv)
10362{
10363 setwinvar(argvars, rettv, 1);
10364}
10365
10366/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010367 * "settagstack()" function
10368 */
10369 static void
10370f_settagstack(typval_T *argvars, typval_T *rettv)
10371{
10372 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10373 win_T *wp;
10374 dict_T *d;
10375 int action = 'r';
10376
10377 rettv->vval.v_number = -1;
10378
10379 // first argument: window number or id
10380 wp = find_win_by_nr_or_id(&argvars[0]);
10381 if (wp == NULL)
10382 return;
10383
10384 // second argument: dict with items to set in the tag stack
10385 if (argvars[1].v_type != VAR_DICT)
10386 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010387 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010388 return;
10389 }
10390 d = argvars[1].vval.v_dict;
10391 if (d == NULL)
10392 return;
10393
10394 // third argument: action - 'a' for append and 'r' for replace.
10395 // default is to replace the stack.
10396 if (argvars[2].v_type == VAR_UNKNOWN)
10397 action = 'r';
10398 else if (argvars[2].v_type == VAR_STRING)
10399 {
10400 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010401 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010402 if (actstr == NULL)
10403 return;
10404 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10405 action = *actstr;
10406 else
10407 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010408 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010409 return;
10410 }
10411 }
10412 else
10413 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010414 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010415 return;
10416 }
10417
10418 if (set_tagstack(wp, d, action) == OK)
10419 rettv->vval.v_number = 0;
10420}
10421
10422/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010423 * "setwinvar()" function
10424 */
10425 static void
10426f_setwinvar(typval_T *argvars, typval_T *rettv)
10427{
10428 setwinvar(argvars, rettv, 0);
10429}
10430
10431#ifdef FEAT_CRYPT
10432/*
10433 * "sha256({string})" function
10434 */
10435 static void
10436f_sha256(typval_T *argvars, typval_T *rettv)
10437{
10438 char_u *p;
10439
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010440 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010441 rettv->vval.v_string = vim_strsave(
10442 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10443 rettv->v_type = VAR_STRING;
10444}
10445#endif /* FEAT_CRYPT */
10446
10447/*
10448 * "shellescape({string})" function
10449 */
10450 static void
10451f_shellescape(typval_T *argvars, typval_T *rettv)
10452{
Bram Moolenaar20615522017-06-05 18:46:26 +020010453 int do_special = non_zero_arg(&argvars[1]);
10454
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010455 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010456 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010457 rettv->v_type = VAR_STRING;
10458}
10459
10460/*
10461 * shiftwidth() function
10462 */
10463 static void
10464f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10465{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010466 rettv->vval.v_number = 0;
10467
10468 if (argvars[0].v_type != VAR_UNKNOWN)
10469 {
10470 long col;
10471
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010472 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010473 if (col < 0)
10474 return; // type error; errmsg already given
10475#ifdef FEAT_VARTABS
10476 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10477 return;
10478#endif
10479 }
10480
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010481 rettv->vval.v_number = get_sw_value(curbuf);
10482}
10483
10484/*
10485 * "simplify()" function
10486 */
10487 static void
10488f_simplify(typval_T *argvars, typval_T *rettv)
10489{
10490 char_u *p;
10491
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010492 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010493 rettv->vval.v_string = vim_strsave(p);
10494 simplify_filename(rettv->vval.v_string); /* simplify in place */
10495 rettv->v_type = VAR_STRING;
10496}
10497
10498#ifdef FEAT_FLOAT
10499/*
10500 * "sin()" function
10501 */
10502 static void
10503f_sin(typval_T *argvars, typval_T *rettv)
10504{
10505 float_T f = 0.0;
10506
10507 rettv->v_type = VAR_FLOAT;
10508 if (get_float_arg(argvars, &f) == OK)
10509 rettv->vval.v_float = sin(f);
10510 else
10511 rettv->vval.v_float = 0.0;
10512}
10513
10514/*
10515 * "sinh()" function
10516 */
10517 static void
10518f_sinh(typval_T *argvars, typval_T *rettv)
10519{
10520 float_T f = 0.0;
10521
10522 rettv->v_type = VAR_FLOAT;
10523 if (get_float_arg(argvars, &f) == OK)
10524 rettv->vval.v_float = sinh(f);
10525 else
10526 rettv->vval.v_float = 0.0;
10527}
10528#endif
10529
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010530/*
10531 * "soundfold({word})" function
10532 */
10533 static void
10534f_soundfold(typval_T *argvars, typval_T *rettv)
10535{
10536 char_u *s;
10537
10538 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010539 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010540#ifdef FEAT_SPELL
10541 rettv->vval.v_string = eval_soundfold(s);
10542#else
10543 rettv->vval.v_string = vim_strsave(s);
10544#endif
10545}
10546
10547/*
10548 * "spellbadword()" function
10549 */
10550 static void
10551f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10552{
10553 char_u *word = (char_u *)"";
10554 hlf_T attr = HLF_COUNT;
10555 int len = 0;
10556
10557 if (rettv_list_alloc(rettv) == FAIL)
10558 return;
10559
10560#ifdef FEAT_SPELL
10561 if (argvars[0].v_type == VAR_UNKNOWN)
10562 {
10563 /* Find the start and length of the badly spelled word. */
10564 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10565 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010566 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010567 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010568 curwin->w_set_curswant = TRUE;
10569 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010570 }
10571 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10572 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010573 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010574 int capcol = -1;
10575
10576 if (str != NULL)
10577 {
10578 /* Check the argument for spelling. */
10579 while (*str != NUL)
10580 {
10581 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10582 if (attr != HLF_COUNT)
10583 {
10584 word = str;
10585 break;
10586 }
10587 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010588 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010589 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010590 }
10591 }
10592 }
10593#endif
10594
10595 list_append_string(rettv->vval.v_list, word, len);
10596 list_append_string(rettv->vval.v_list, (char_u *)(
10597 attr == HLF_SPB ? "bad" :
10598 attr == HLF_SPR ? "rare" :
10599 attr == HLF_SPL ? "local" :
10600 attr == HLF_SPC ? "caps" :
10601 ""), -1);
10602}
10603
10604/*
10605 * "spellsuggest()" function
10606 */
10607 static void
10608f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10609{
10610#ifdef FEAT_SPELL
10611 char_u *str;
10612 int typeerr = FALSE;
10613 int maxcount;
10614 garray_T ga;
10615 int i;
10616 listitem_T *li;
10617 int need_capital = FALSE;
10618#endif
10619
10620 if (rettv_list_alloc(rettv) == FAIL)
10621 return;
10622
10623#ifdef FEAT_SPELL
10624 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10625 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010626 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010627 if (argvars[1].v_type != VAR_UNKNOWN)
10628 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010629 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010630 if (maxcount <= 0)
10631 return;
10632 if (argvars[2].v_type != VAR_UNKNOWN)
10633 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010634 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010635 if (typeerr)
10636 return;
10637 }
10638 }
10639 else
10640 maxcount = 25;
10641
10642 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10643
10644 for (i = 0; i < ga.ga_len; ++i)
10645 {
10646 str = ((char_u **)ga.ga_data)[i];
10647
10648 li = listitem_alloc();
10649 if (li == NULL)
10650 vim_free(str);
10651 else
10652 {
10653 li->li_tv.v_type = VAR_STRING;
10654 li->li_tv.v_lock = 0;
10655 li->li_tv.vval.v_string = str;
10656 list_append(rettv->vval.v_list, li);
10657 }
10658 }
10659 ga_clear(&ga);
10660 }
10661#endif
10662}
10663
10664 static void
10665f_split(typval_T *argvars, typval_T *rettv)
10666{
10667 char_u *str;
10668 char_u *end;
10669 char_u *pat = NULL;
10670 regmatch_T regmatch;
10671 char_u patbuf[NUMBUFLEN];
10672 char_u *save_cpo;
10673 int match;
10674 colnr_T col = 0;
10675 int keepempty = FALSE;
10676 int typeerr = FALSE;
10677
10678 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10679 save_cpo = p_cpo;
10680 p_cpo = (char_u *)"";
10681
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010682 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010683 if (argvars[1].v_type != VAR_UNKNOWN)
10684 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010685 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010686 if (pat == NULL)
10687 typeerr = TRUE;
10688 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010689 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010690 }
10691 if (pat == NULL || *pat == NUL)
10692 pat = (char_u *)"[\\x01- ]\\+";
10693
10694 if (rettv_list_alloc(rettv) == FAIL)
10695 return;
10696 if (typeerr)
10697 return;
10698
10699 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10700 if (regmatch.regprog != NULL)
10701 {
10702 regmatch.rm_ic = FALSE;
10703 while (*str != NUL || keepempty)
10704 {
10705 if (*str == NUL)
10706 match = FALSE; /* empty item at the end */
10707 else
10708 match = vim_regexec_nl(&regmatch, str, col);
10709 if (match)
10710 end = regmatch.startp[0];
10711 else
10712 end = str + STRLEN(str);
10713 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10714 && *str != NUL && match && end < regmatch.endp[0]))
10715 {
10716 if (list_append_string(rettv->vval.v_list, str,
10717 (int)(end - str)) == FAIL)
10718 break;
10719 }
10720 if (!match)
10721 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010722 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010723 if (regmatch.endp[0] > str)
10724 col = 0;
10725 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010726 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010727 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010728 str = regmatch.endp[0];
10729 }
10730
10731 vim_regfree(regmatch.regprog);
10732 }
10733
10734 p_cpo = save_cpo;
10735}
10736
10737#ifdef FEAT_FLOAT
10738/*
10739 * "sqrt()" function
10740 */
10741 static void
10742f_sqrt(typval_T *argvars, typval_T *rettv)
10743{
10744 float_T f = 0.0;
10745
10746 rettv->v_type = VAR_FLOAT;
10747 if (get_float_arg(argvars, &f) == OK)
10748 rettv->vval.v_float = sqrt(f);
10749 else
10750 rettv->vval.v_float = 0.0;
10751}
10752
10753/*
10754 * "str2float()" function
10755 */
10756 static void
10757f_str2float(typval_T *argvars, typval_T *rettv)
10758{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010759 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010760 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010761
Bram Moolenaar08243d22017-01-10 16:12:29 +010010762 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010763 p = skipwhite(p + 1);
10764 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010765 if (isneg)
10766 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010767 rettv->v_type = VAR_FLOAT;
10768}
10769#endif
10770
10771/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010772 * "str2list()" function
10773 */
10774 static void
10775f_str2list(typval_T *argvars, typval_T *rettv)
10776{
10777 char_u *p;
10778 int utf8 = FALSE;
10779
10780 if (rettv_list_alloc(rettv) == FAIL)
10781 return;
10782
10783 if (argvars[1].v_type != VAR_UNKNOWN)
10784 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10785
10786 p = tv_get_string(&argvars[0]);
10787
10788 if (has_mbyte || utf8)
10789 {
10790 int (*ptr2len)(char_u *);
10791 int (*ptr2char)(char_u *);
10792
10793 if (utf8 || enc_utf8)
10794 {
10795 ptr2len = utf_ptr2len;
10796 ptr2char = utf_ptr2char;
10797 }
10798 else
10799 {
10800 ptr2len = mb_ptr2len;
10801 ptr2char = mb_ptr2char;
10802 }
10803
10804 for ( ; *p != NUL; p += (*ptr2len)(p))
10805 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10806 }
10807 else
10808 for ( ; *p != NUL; ++p)
10809 list_append_number(rettv->vval.v_list, *p);
10810}
10811
10812/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010813 * "str2nr()" function
10814 */
10815 static void
10816f_str2nr(typval_T *argvars, typval_T *rettv)
10817{
10818 int base = 10;
10819 char_u *p;
10820 varnumber_T n;
10821 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010822 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010823
10824 if (argvars[1].v_type != VAR_UNKNOWN)
10825 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010826 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010827 if (base != 2 && base != 8 && base != 10 && base != 16)
10828 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010829 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830 return;
10831 }
10832 }
10833
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010834 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010835 isneg = (*p == '-');
10836 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010837 p = skipwhite(p + 1);
10838 switch (base)
10839 {
10840 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10841 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10842 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10843 default: what = 0;
10844 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010845 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10846 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010847 if (isneg)
10848 rettv->vval.v_number = -n;
10849 else
10850 rettv->vval.v_number = n;
10851
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010852}
10853
10854#ifdef HAVE_STRFTIME
10855/*
10856 * "strftime({format}[, {time}])" function
10857 */
10858 static void
10859f_strftime(typval_T *argvars, typval_T *rettv)
10860{
10861 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010862 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010863 struct tm *curtime;
10864 time_t seconds;
10865 char_u *p;
10866
10867 rettv->v_type = VAR_STRING;
10868
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010869 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010870 if (argvars[1].v_type == VAR_UNKNOWN)
10871 seconds = time(NULL);
10872 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010873 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010874 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010875 /* MSVC returns NULL for an invalid value of seconds. */
10876 if (curtime == NULL)
10877 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10878 else
10879 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010880 vimconv_T conv;
10881 char_u *enc;
10882
10883 conv.vc_type = CONV_NONE;
10884 enc = enc_locale();
10885 convert_setup(&conv, p_enc, enc);
10886 if (conv.vc_type != CONV_NONE)
10887 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010888 if (p != NULL)
10889 (void)strftime((char *)result_buf, sizeof(result_buf),
10890 (char *)p, curtime);
10891 else
10892 result_buf[0] = NUL;
10893
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010894 if (conv.vc_type != CONV_NONE)
10895 vim_free(p);
10896 convert_setup(&conv, enc, p_enc);
10897 if (conv.vc_type != CONV_NONE)
10898 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10899 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010900 rettv->vval.v_string = vim_strsave(result_buf);
10901
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010902 /* Release conversion descriptors */
10903 convert_setup(&conv, NULL, NULL);
10904 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010905 }
10906}
10907#endif
10908
10909/*
10910 * "strgetchar()" function
10911 */
10912 static void
10913f_strgetchar(typval_T *argvars, typval_T *rettv)
10914{
10915 char_u *str;
10916 int len;
10917 int error = FALSE;
10918 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010010919 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010920
10921 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010922 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010923 if (str == NULL)
10924 return;
10925 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010926 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010927 if (error)
10928 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010929
Bram Moolenaar13505972019-01-24 15:04:48 +010010930 while (charidx >= 0 && byteidx < len)
10931 {
10932 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010933 {
Bram Moolenaar13505972019-01-24 15:04:48 +010010934 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10935 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010936 }
Bram Moolenaar13505972019-01-24 15:04:48 +010010937 --charidx;
10938 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010939 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010940}
10941
10942/*
10943 * "stridx()" function
10944 */
10945 static void
10946f_stridx(typval_T *argvars, typval_T *rettv)
10947{
10948 char_u buf[NUMBUFLEN];
10949 char_u *needle;
10950 char_u *haystack;
10951 char_u *save_haystack;
10952 char_u *pos;
10953 int start_idx;
10954
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010955 needle = tv_get_string_chk(&argvars[1]);
10956 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010957 rettv->vval.v_number = -1;
10958 if (needle == NULL || haystack == NULL)
10959 return; /* type error; errmsg already given */
10960
10961 if (argvars[2].v_type != VAR_UNKNOWN)
10962 {
10963 int error = FALSE;
10964
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010965 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010966 if (error || start_idx >= (int)STRLEN(haystack))
10967 return;
10968 if (start_idx >= 0)
10969 haystack += start_idx;
10970 }
10971
10972 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10973 if (pos != NULL)
10974 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10975}
10976
10977/*
10978 * "string()" function
10979 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010010980 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010981f_string(typval_T *argvars, typval_T *rettv)
10982{
10983 char_u *tofree;
10984 char_u numbuf[NUMBUFLEN];
10985
10986 rettv->v_type = VAR_STRING;
10987 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10988 get_copyID());
10989 /* Make a copy if we have a value but it's not in allocated memory. */
10990 if (rettv->vval.v_string != NULL && tofree == NULL)
10991 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10992}
10993
10994/*
10995 * "strlen()" function
10996 */
10997 static void
10998f_strlen(typval_T *argvars, typval_T *rettv)
10999{
11000 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011001 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011002}
11003
11004/*
11005 * "strchars()" function
11006 */
11007 static void
11008f_strchars(typval_T *argvars, typval_T *rettv)
11009{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011010 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011011 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011012 varnumber_T len = 0;
11013 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011014
11015 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011016 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011017 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011018 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011019 else
11020 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011021 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11022 while (*s != NUL)
11023 {
11024 func_mb_ptr2char_adv(&s);
11025 ++len;
11026 }
11027 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011028 }
11029}
11030
11031/*
11032 * "strdisplaywidth()" function
11033 */
11034 static void
11035f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11036{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011037 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038 int col = 0;
11039
11040 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011041 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011042
11043 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11044}
11045
11046/*
11047 * "strwidth()" function
11048 */
11049 static void
11050f_strwidth(typval_T *argvars, typval_T *rettv)
11051{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011052 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011053
Bram Moolenaar13505972019-01-24 15:04:48 +010011054 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011055}
11056
11057/*
11058 * "strcharpart()" function
11059 */
11060 static void
11061f_strcharpart(typval_T *argvars, typval_T *rettv)
11062{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063 char_u *p;
11064 int nchar;
11065 int nbyte = 0;
11066 int charlen;
11067 int len = 0;
11068 int slen;
11069 int error = FALSE;
11070
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011071 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011072 slen = (int)STRLEN(p);
11073
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011074 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011075 if (!error)
11076 {
11077 if (nchar > 0)
11078 while (nchar > 0 && nbyte < slen)
11079 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011080 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011081 --nchar;
11082 }
11083 else
11084 nbyte = nchar;
11085 if (argvars[2].v_type != VAR_UNKNOWN)
11086 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011087 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011088 while (charlen > 0 && nbyte + len < slen)
11089 {
11090 int off = nbyte + len;
11091
11092 if (off < 0)
11093 len += 1;
11094 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011095 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011096 --charlen;
11097 }
11098 }
11099 else
11100 len = slen - nbyte; /* default: all bytes that are available. */
11101 }
11102
11103 /*
11104 * Only return the overlap between the specified part and the actual
11105 * string.
11106 */
11107 if (nbyte < 0)
11108 {
11109 len += nbyte;
11110 nbyte = 0;
11111 }
11112 else if (nbyte > slen)
11113 nbyte = slen;
11114 if (len < 0)
11115 len = 0;
11116 else if (nbyte + len > slen)
11117 len = slen - nbyte;
11118
11119 rettv->v_type = VAR_STRING;
11120 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011121}
11122
11123/*
11124 * "strpart()" function
11125 */
11126 static void
11127f_strpart(typval_T *argvars, typval_T *rettv)
11128{
11129 char_u *p;
11130 int n;
11131 int len;
11132 int slen;
11133 int error = FALSE;
11134
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011135 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011136 slen = (int)STRLEN(p);
11137
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011138 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011139 if (error)
11140 len = 0;
11141 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011142 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011143 else
11144 len = slen - n; /* default len: all bytes that are available. */
11145
11146 /*
11147 * Only return the overlap between the specified part and the actual
11148 * string.
11149 */
11150 if (n < 0)
11151 {
11152 len += n;
11153 n = 0;
11154 }
11155 else if (n > slen)
11156 n = slen;
11157 if (len < 0)
11158 len = 0;
11159 else if (n + len > slen)
11160 len = slen - n;
11161
11162 rettv->v_type = VAR_STRING;
11163 rettv->vval.v_string = vim_strnsave(p + n, len);
11164}
11165
11166/*
11167 * "strridx()" function
11168 */
11169 static void
11170f_strridx(typval_T *argvars, typval_T *rettv)
11171{
11172 char_u buf[NUMBUFLEN];
11173 char_u *needle;
11174 char_u *haystack;
11175 char_u *rest;
11176 char_u *lastmatch = NULL;
11177 int haystack_len, end_idx;
11178
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011179 needle = tv_get_string_chk(&argvars[1]);
11180 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011181
11182 rettv->vval.v_number = -1;
11183 if (needle == NULL || haystack == NULL)
11184 return; /* type error; errmsg already given */
11185
11186 haystack_len = (int)STRLEN(haystack);
11187 if (argvars[2].v_type != VAR_UNKNOWN)
11188 {
11189 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011190 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011191 if (end_idx < 0)
11192 return; /* can never find a match */
11193 }
11194 else
11195 end_idx = haystack_len;
11196
11197 if (*needle == NUL)
11198 {
11199 /* Empty string matches past the end. */
11200 lastmatch = haystack + end_idx;
11201 }
11202 else
11203 {
11204 for (rest = haystack; *rest != '\0'; ++rest)
11205 {
11206 rest = (char_u *)strstr((char *)rest, (char *)needle);
11207 if (rest == NULL || rest > haystack + end_idx)
11208 break;
11209 lastmatch = rest;
11210 }
11211 }
11212
11213 if (lastmatch == NULL)
11214 rettv->vval.v_number = -1;
11215 else
11216 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11217}
11218
11219/*
11220 * "strtrans()" function
11221 */
11222 static void
11223f_strtrans(typval_T *argvars, typval_T *rettv)
11224{
11225 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011226 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011227}
11228
11229/*
11230 * "submatch()" function
11231 */
11232 static void
11233f_submatch(typval_T *argvars, typval_T *rettv)
11234{
11235 int error = FALSE;
11236 int no;
11237 int retList = 0;
11238
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011239 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011240 if (error)
11241 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011242 if (no < 0 || no >= NSUBEXP)
11243 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011244 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011245 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011246 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011247 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011248 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011249 if (error)
11250 return;
11251
11252 if (retList == 0)
11253 {
11254 rettv->v_type = VAR_STRING;
11255 rettv->vval.v_string = reg_submatch(no);
11256 }
11257 else
11258 {
11259 rettv->v_type = VAR_LIST;
11260 rettv->vval.v_list = reg_submatch_list(no);
11261 }
11262}
11263
11264/*
11265 * "substitute()" function
11266 */
11267 static void
11268f_substitute(typval_T *argvars, typval_T *rettv)
11269{
11270 char_u patbuf[NUMBUFLEN];
11271 char_u subbuf[NUMBUFLEN];
11272 char_u flagsbuf[NUMBUFLEN];
11273
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011274 char_u *str = tv_get_string_chk(&argvars[0]);
11275 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011276 char_u *sub = NULL;
11277 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011278 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011279
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011280 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11281 expr = &argvars[2];
11282 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011283 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011284
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011285 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011286 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11287 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011288 rettv->vval.v_string = NULL;
11289 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011290 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011291}
11292
11293/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011294 * "swapinfo(swap_filename)" function
11295 */
11296 static void
11297f_swapinfo(typval_T *argvars, typval_T *rettv)
11298{
11299 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011300 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011301}
11302
11303/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011304 * "swapname(expr)" function
11305 */
11306 static void
11307f_swapname(typval_T *argvars, typval_T *rettv)
11308{
11309 buf_T *buf;
11310
11311 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011312 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011313 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11314 || buf->b_ml.ml_mfp->mf_fname == NULL)
11315 rettv->vval.v_string = NULL;
11316 else
11317 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11318}
11319
11320/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011321 * "synID(lnum, col, trans)" function
11322 */
11323 static void
11324f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11325{
11326 int id = 0;
11327#ifdef FEAT_SYN_HL
11328 linenr_T lnum;
11329 colnr_T col;
11330 int trans;
11331 int transerr = FALSE;
11332
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011333 lnum = tv_get_lnum(argvars); /* -1 on type error */
11334 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11335 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011336
11337 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11338 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11339 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11340#endif
11341
11342 rettv->vval.v_number = id;
11343}
11344
11345/*
11346 * "synIDattr(id, what [, mode])" function
11347 */
11348 static void
11349f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11350{
11351 char_u *p = NULL;
11352#ifdef FEAT_SYN_HL
11353 int id;
11354 char_u *what;
11355 char_u *mode;
11356 char_u modebuf[NUMBUFLEN];
11357 int modec;
11358
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011359 id = (int)tv_get_number(&argvars[0]);
11360 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011361 if (argvars[2].v_type != VAR_UNKNOWN)
11362 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011363 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011364 modec = TOLOWER_ASC(mode[0]);
11365 if (modec != 't' && modec != 'c' && modec != 'g')
11366 modec = 0; /* replace invalid with current */
11367 }
11368 else
11369 {
11370#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11371 if (USE_24BIT)
11372 modec = 'g';
11373 else
11374#endif
11375 if (t_colors > 1)
11376 modec = 'c';
11377 else
11378 modec = 't';
11379 }
11380
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011381 switch (TOLOWER_ASC(what[0]))
11382 {
11383 case 'b':
11384 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11385 p = highlight_color(id, what, modec);
11386 else /* bold */
11387 p = highlight_has_attr(id, HL_BOLD, modec);
11388 break;
11389
11390 case 'f': /* fg[#] or font */
11391 p = highlight_color(id, what, modec);
11392 break;
11393
11394 case 'i':
11395 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11396 p = highlight_has_attr(id, HL_INVERSE, modec);
11397 else /* italic */
11398 p = highlight_has_attr(id, HL_ITALIC, modec);
11399 break;
11400
11401 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011402 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011403 break;
11404
11405 case 'r': /* reverse */
11406 p = highlight_has_attr(id, HL_INVERSE, modec);
11407 break;
11408
11409 case 's':
11410 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11411 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011412 /* strikeout */
11413 else if (TOLOWER_ASC(what[1]) == 't' &&
11414 TOLOWER_ASC(what[2]) == 'r')
11415 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011416 else /* standout */
11417 p = highlight_has_attr(id, HL_STANDOUT, modec);
11418 break;
11419
11420 case 'u':
11421 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11422 /* underline */
11423 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11424 else
11425 /* undercurl */
11426 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11427 break;
11428 }
11429
11430 if (p != NULL)
11431 p = vim_strsave(p);
11432#endif
11433 rettv->v_type = VAR_STRING;
11434 rettv->vval.v_string = p;
11435}
11436
11437/*
11438 * "synIDtrans(id)" function
11439 */
11440 static void
11441f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11442{
11443 int id;
11444
11445#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011446 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011447
11448 if (id > 0)
11449 id = syn_get_final_id(id);
11450 else
11451#endif
11452 id = 0;
11453
11454 rettv->vval.v_number = id;
11455}
11456
11457/*
11458 * "synconcealed(lnum, col)" function
11459 */
11460 static void
11461f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11462{
11463#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11464 linenr_T lnum;
11465 colnr_T col;
11466 int syntax_flags = 0;
11467 int cchar;
11468 int matchid = 0;
11469 char_u str[NUMBUFLEN];
11470#endif
11471
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011472 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011473
11474#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011475 lnum = tv_get_lnum(argvars); /* -1 on type error */
11476 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011477
11478 vim_memset(str, NUL, sizeof(str));
11479
11480 if (rettv_list_alloc(rettv) != FAIL)
11481 {
11482 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11483 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11484 && curwin->w_p_cole > 0)
11485 {
11486 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11487 syntax_flags = get_syntax_info(&matchid);
11488
11489 /* get the conceal character */
11490 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11491 {
11492 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011493 if (cchar == NUL && curwin->w_p_cole == 1)
11494 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011495 if (cchar != NUL)
11496 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011497 if (has_mbyte)
11498 (*mb_char2bytes)(cchar, str);
11499 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011500 str[0] = cchar;
11501 }
11502 }
11503 }
11504
11505 list_append_number(rettv->vval.v_list,
11506 (syntax_flags & HL_CONCEAL) != 0);
11507 /* -1 to auto-determine strlen */
11508 list_append_string(rettv->vval.v_list, str, -1);
11509 list_append_number(rettv->vval.v_list, matchid);
11510 }
11511#endif
11512}
11513
11514/*
11515 * "synstack(lnum, col)" function
11516 */
11517 static void
11518f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11519{
11520#ifdef FEAT_SYN_HL
11521 linenr_T lnum;
11522 colnr_T col;
11523 int i;
11524 int id;
11525#endif
11526
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011527 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011528
11529#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011530 lnum = tv_get_lnum(argvars); /* -1 on type error */
11531 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011532
11533 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11534 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11535 && rettv_list_alloc(rettv) != FAIL)
11536 {
11537 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11538 for (i = 0; ; ++i)
11539 {
11540 id = syn_get_stack_item(i);
11541 if (id < 0)
11542 break;
11543 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11544 break;
11545 }
11546 }
11547#endif
11548}
11549
11550 static void
11551get_cmd_output_as_rettv(
11552 typval_T *argvars,
11553 typval_T *rettv,
11554 int retlist)
11555{
11556 char_u *res = NULL;
11557 char_u *p;
11558 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011559 int err = FALSE;
11560 FILE *fd;
11561 list_T *list = NULL;
11562 int flags = SHELL_SILENT;
11563
11564 rettv->v_type = VAR_STRING;
11565 rettv->vval.v_string = NULL;
11566 if (check_restricted() || check_secure())
11567 goto errret;
11568
11569 if (argvars[1].v_type != VAR_UNKNOWN)
11570 {
11571 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011572 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011573 * command.
11574 */
11575 if ((infile = vim_tempname('i', TRUE)) == NULL)
11576 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011577 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011578 goto errret;
11579 }
11580
11581 fd = mch_fopen((char *)infile, WRITEBIN);
11582 if (fd == NULL)
11583 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011584 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011585 goto errret;
11586 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011587 if (argvars[1].v_type == VAR_NUMBER)
11588 {
11589 linenr_T lnum;
11590 buf_T *buf;
11591
11592 buf = buflist_findnr(argvars[1].vval.v_number);
11593 if (buf == NULL)
11594 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011595 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011596 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011597 goto errret;
11598 }
11599
11600 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11601 {
11602 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11603 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11604 {
11605 err = TRUE;
11606 break;
11607 }
11608 if (putc(NL, fd) == EOF)
11609 {
11610 err = TRUE;
11611 break;
11612 }
11613 }
11614 }
11615 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011616 {
11617 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11618 err = TRUE;
11619 }
11620 else
11621 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011622 size_t len;
11623 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011624
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011625 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011626 if (p == NULL)
11627 {
11628 fclose(fd);
11629 goto errret; /* type error; errmsg already given */
11630 }
11631 len = STRLEN(p);
11632 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11633 err = TRUE;
11634 }
11635 if (fclose(fd) != 0)
11636 err = TRUE;
11637 if (err)
11638 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011639 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011640 goto errret;
11641 }
11642 }
11643
11644 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11645 * echoes typeahead, that messes up the display. */
11646 if (!msg_silent)
11647 flags += SHELL_COOKED;
11648
11649 if (retlist)
11650 {
11651 int len;
11652 listitem_T *li;
11653 char_u *s = NULL;
11654 char_u *start;
11655 char_u *end;
11656 int i;
11657
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011658 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011659 if (res == NULL)
11660 goto errret;
11661
11662 list = list_alloc();
11663 if (list == NULL)
11664 goto errret;
11665
11666 for (i = 0; i < len; ++i)
11667 {
11668 start = res + i;
11669 while (i < len && res[i] != NL)
11670 ++i;
11671 end = res + i;
11672
Bram Moolenaar964b3742019-05-24 18:54:09 +020011673 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011674 if (s == NULL)
11675 goto errret;
11676
11677 for (p = s; start < end; ++p, ++start)
11678 *p = *start == NUL ? NL : *start;
11679 *p = NUL;
11680
11681 li = listitem_alloc();
11682 if (li == NULL)
11683 {
11684 vim_free(s);
11685 goto errret;
11686 }
11687 li->li_tv.v_type = VAR_STRING;
11688 li->li_tv.v_lock = 0;
11689 li->li_tv.vval.v_string = s;
11690 list_append(list, li);
11691 }
11692
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011693 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011694 list = NULL;
11695 }
11696 else
11697 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011698 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011699#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011700 /* translate <CR><NL> into <NL> */
11701 if (res != NULL)
11702 {
11703 char_u *s, *d;
11704
11705 d = res;
11706 for (s = res; *s; ++s)
11707 {
11708 if (s[0] == CAR && s[1] == NL)
11709 ++s;
11710 *d++ = *s;
11711 }
11712 *d = NUL;
11713 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011714#endif
11715 rettv->vval.v_string = res;
11716 res = NULL;
11717 }
11718
11719errret:
11720 if (infile != NULL)
11721 {
11722 mch_remove(infile);
11723 vim_free(infile);
11724 }
11725 if (res != NULL)
11726 vim_free(res);
11727 if (list != NULL)
11728 list_free(list);
11729}
11730
11731/*
11732 * "system()" function
11733 */
11734 static void
11735f_system(typval_T *argvars, typval_T *rettv)
11736{
11737 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11738}
11739
11740/*
11741 * "systemlist()" function
11742 */
11743 static void
11744f_systemlist(typval_T *argvars, typval_T *rettv)
11745{
11746 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11747}
11748
11749/*
11750 * "tabpagebuflist()" function
11751 */
11752 static void
11753f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11754{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011755 tabpage_T *tp;
11756 win_T *wp = NULL;
11757
11758 if (argvars[0].v_type == VAR_UNKNOWN)
11759 wp = firstwin;
11760 else
11761 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011762 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011763 if (tp != NULL)
11764 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11765 }
11766 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11767 {
11768 for (; wp != NULL; wp = wp->w_next)
11769 if (list_append_number(rettv->vval.v_list,
11770 wp->w_buffer->b_fnum) == FAIL)
11771 break;
11772 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011773}
11774
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011775/*
11776 * "tabpagenr()" function
11777 */
11778 static void
11779f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11780{
11781 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011782 char_u *arg;
11783
11784 if (argvars[0].v_type != VAR_UNKNOWN)
11785 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011786 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011787 nr = 0;
11788 if (arg != NULL)
11789 {
11790 if (STRCMP(arg, "$") == 0)
11791 nr = tabpage_index(NULL) - 1;
11792 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011793 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011794 }
11795 }
11796 else
11797 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011798 rettv->vval.v_number = nr;
11799}
11800
11801
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011802/*
11803 * Common code for tabpagewinnr() and winnr().
11804 */
11805 static int
11806get_winnr(tabpage_T *tp, typval_T *argvar)
11807{
11808 win_T *twin;
11809 int nr = 1;
11810 win_T *wp;
11811 char_u *arg;
11812
11813 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11814 if (argvar->v_type != VAR_UNKNOWN)
11815 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011816 int invalid_arg = FALSE;
11817
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011818 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011819 if (arg == NULL)
11820 nr = 0; /* type error; errmsg already given */
11821 else if (STRCMP(arg, "$") == 0)
11822 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11823 else if (STRCMP(arg, "#") == 0)
11824 {
11825 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11826 if (twin == NULL)
11827 nr = 0;
11828 }
11829 else
11830 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011831 long count;
11832 char_u *endp;
11833
11834 // Extract the window count (if specified). e.g. winnr('3j')
11835 count = strtol((char *)arg, (char **)&endp, 10);
11836 if (count <= 0)
11837 count = 1; // if count is not specified, default to 1
11838 if (endp != NULL && *endp != '\0')
11839 {
11840 if (STRCMP(endp, "j") == 0)
11841 twin = win_vert_neighbor(tp, twin, FALSE, count);
11842 else if (STRCMP(endp, "k") == 0)
11843 twin = win_vert_neighbor(tp, twin, TRUE, count);
11844 else if (STRCMP(endp, "h") == 0)
11845 twin = win_horz_neighbor(tp, twin, TRUE, count);
11846 else if (STRCMP(endp, "l") == 0)
11847 twin = win_horz_neighbor(tp, twin, FALSE, count);
11848 else
11849 invalid_arg = TRUE;
11850 }
11851 else
11852 invalid_arg = TRUE;
11853 }
11854
11855 if (invalid_arg)
11856 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011857 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011858 nr = 0;
11859 }
11860 }
11861
11862 if (nr > 0)
11863 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11864 wp != twin; wp = wp->w_next)
11865 {
11866 if (wp == NULL)
11867 {
11868 /* didn't find it in this tabpage */
11869 nr = 0;
11870 break;
11871 }
11872 ++nr;
11873 }
11874 return nr;
11875}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011876
11877/*
11878 * "tabpagewinnr()" function
11879 */
11880 static void
11881f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11882{
11883 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011884 tabpage_T *tp;
11885
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011886 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011887 if (tp == NULL)
11888 nr = 0;
11889 else
11890 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011891 rettv->vval.v_number = nr;
11892}
11893
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011894/*
11895 * "tagfiles()" function
11896 */
11897 static void
11898f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11899{
11900 char_u *fname;
11901 tagname_T tn;
11902 int first;
11903
11904 if (rettv_list_alloc(rettv) == FAIL)
11905 return;
11906 fname = alloc(MAXPATHL);
11907 if (fname == NULL)
11908 return;
11909
11910 for (first = TRUE; ; first = FALSE)
11911 if (get_tagfname(&tn, first, fname) == FAIL
11912 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11913 break;
11914 tagname_free(&tn);
11915 vim_free(fname);
11916}
11917
11918/*
11919 * "taglist()" function
11920 */
11921 static void
11922f_taglist(typval_T *argvars, typval_T *rettv)
11923{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011924 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011925 char_u *tag_pattern;
11926
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011927 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011928
11929 rettv->vval.v_number = FALSE;
11930 if (*tag_pattern == NUL)
11931 return;
11932
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011933 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011934 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011935 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011936 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011937}
11938
11939/*
11940 * "tempname()" function
11941 */
11942 static void
11943f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11944{
11945 static int x = 'A';
11946
11947 rettv->v_type = VAR_STRING;
11948 rettv->vval.v_string = vim_tempname(x, FALSE);
11949
11950 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11951 * names. Skip 'I' and 'O', they are used for shell redirection. */
11952 do
11953 {
11954 if (x == 'Z')
11955 x = '0';
11956 else if (x == '9')
11957 x = 'A';
11958 else
11959 {
11960#ifdef EBCDIC
11961 if (x == 'I')
11962 x = 'J';
11963 else if (x == 'R')
11964 x = 'S';
11965 else
11966#endif
11967 ++x;
11968 }
11969 } while (x == 'I' || x == 'O');
11970}
11971
11972#ifdef FEAT_FLOAT
11973/*
11974 * "tan()" function
11975 */
11976 static void
11977f_tan(typval_T *argvars, typval_T *rettv)
11978{
11979 float_T f = 0.0;
11980
11981 rettv->v_type = VAR_FLOAT;
11982 if (get_float_arg(argvars, &f) == OK)
11983 rettv->vval.v_float = tan(f);
11984 else
11985 rettv->vval.v_float = 0.0;
11986}
11987
11988/*
11989 * "tanh()" function
11990 */
11991 static void
11992f_tanh(typval_T *argvars, typval_T *rettv)
11993{
11994 float_T f = 0.0;
11995
11996 rettv->v_type = VAR_FLOAT;
11997 if (get_float_arg(argvars, &f) == OK)
11998 rettv->vval.v_float = tanh(f);
11999 else
12000 rettv->vval.v_float = 0.0;
12001}
12002#endif
12003
12004/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012005 * Get a callback from "arg". It can be a Funcref or a function name.
12006 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012007 * "cb_name" is not allocated.
12008 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012009 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012010 callback_T
12011get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012012{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012013 callback_T res;
12014
12015 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012016 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12017 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012018 res.cb_partial = arg->vval.v_partial;
12019 ++res.cb_partial->pt_refcount;
12020 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012021 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012022 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012023 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012024 res.cb_partial = NULL;
12025 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12026 {
12027 // Note that we don't make a copy of the string.
12028 res.cb_name = arg->vval.v_string;
12029 func_ref(res.cb_name);
12030 }
12031 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12032 {
12033 res.cb_name = (char_u *)"";
12034 }
12035 else
12036 {
12037 emsg(_("E921: Invalid callback argument"));
12038 res.cb_name = NULL;
12039 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012040 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012041 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012042}
12043
12044/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012045 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012046 */
12047 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012048put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012049{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012050 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012051 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012052 tv->v_type = VAR_PARTIAL;
12053 tv->vval.v_partial = cb->cb_partial;
12054 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012055 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012056 else
12057 {
12058 tv->v_type = VAR_FUNC;
12059 tv->vval.v_string = vim_strsave(cb->cb_name);
12060 func_ref(cb->cb_name);
12061 }
12062}
12063
12064/*
12065 * Make a copy of "src" into "dest", allocating the function name if needed,
12066 * without incrementing the refcount.
12067 */
12068 void
12069set_callback(callback_T *dest, callback_T *src)
12070{
12071 if (src->cb_partial == NULL)
12072 {
12073 // just a function name, make a copy
12074 dest->cb_name = vim_strsave(src->cb_name);
12075 dest->cb_free_name = TRUE;
12076 }
12077 else
12078 {
12079 // cb_name is a pointer into cb_partial
12080 dest->cb_name = src->cb_name;
12081 dest->cb_free_name = FALSE;
12082 }
12083 dest->cb_partial = src->cb_partial;
12084}
12085
12086/*
12087 * Unref/free "callback" returned by get_callback() or set_callback().
12088 */
12089 void
12090free_callback(callback_T *callback)
12091{
12092 if (callback->cb_partial != NULL)
12093 {
12094 partial_unref(callback->cb_partial);
12095 callback->cb_partial = NULL;
12096 }
12097 else if (callback->cb_name != NULL)
12098 func_unref(callback->cb_name);
12099 if (callback->cb_free_name)
12100 {
12101 vim_free(callback->cb_name);
12102 callback->cb_free_name = FALSE;
12103 }
12104 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012105}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012106
12107#ifdef FEAT_TIMERS
12108/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012109 * "timer_info([timer])" function
12110 */
12111 static void
12112f_timer_info(typval_T *argvars, typval_T *rettv)
12113{
12114 timer_T *timer = NULL;
12115
12116 if (rettv_list_alloc(rettv) != OK)
12117 return;
12118 if (argvars[0].v_type != VAR_UNKNOWN)
12119 {
12120 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012121 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012122 else
12123 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012124 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012125 if (timer != NULL)
12126 add_timer_info(rettv, timer);
12127 }
12128 }
12129 else
12130 add_timer_info_all(rettv);
12131}
12132
12133/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012134 * "timer_pause(timer, paused)" function
12135 */
12136 static void
12137f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12138{
12139 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012140 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012141
12142 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012143 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012144 else
12145 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012146 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012147 if (timer != NULL)
12148 timer->tr_paused = paused;
12149 }
12150}
12151
12152/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012153 * "timer_start(time, callback [, options])" function
12154 */
12155 static void
12156f_timer_start(typval_T *argvars, typval_T *rettv)
12157{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012158 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012159 timer_T *timer;
12160 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012161 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012162 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012163
Bram Moolenaar75537a92016-09-05 22:45:28 +020012164 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012165 if (check_secure())
12166 return;
12167 if (argvars[2].v_type != VAR_UNKNOWN)
12168 {
12169 if (argvars[2].v_type != VAR_DICT
12170 || (dict = argvars[2].vval.v_dict) == NULL)
12171 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012172 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012173 return;
12174 }
12175 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012176 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012177 }
12178
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012179 callback = get_callback(&argvars[1]);
12180 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012181 return;
12182
12183 timer = create_timer(msec, repeat);
12184 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012185 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012186 else
12187 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012188 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012189 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012190 }
12191}
12192
12193/*
12194 * "timer_stop(timer)" function
12195 */
12196 static void
12197f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12198{
12199 timer_T *timer;
12200
12201 if (argvars[0].v_type != VAR_NUMBER)
12202 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012203 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012204 return;
12205 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012206 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012207 if (timer != NULL)
12208 stop_timer(timer);
12209}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012210
12211/*
12212 * "timer_stopall()" function
12213 */
12214 static void
12215f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12216{
12217 stop_all_timers();
12218}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012219#endif
12220
12221/*
12222 * "tolower(string)" function
12223 */
12224 static void
12225f_tolower(typval_T *argvars, typval_T *rettv)
12226{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012227 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012228 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012229}
12230
12231/*
12232 * "toupper(string)" function
12233 */
12234 static void
12235f_toupper(typval_T *argvars, typval_T *rettv)
12236{
12237 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012238 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012239}
12240
12241/*
12242 * "tr(string, fromstr, tostr)" function
12243 */
12244 static void
12245f_tr(typval_T *argvars, typval_T *rettv)
12246{
12247 char_u *in_str;
12248 char_u *fromstr;
12249 char_u *tostr;
12250 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012251 int inlen;
12252 int fromlen;
12253 int tolen;
12254 int idx;
12255 char_u *cpstr;
12256 int cplen;
12257 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012258 char_u buf[NUMBUFLEN];
12259 char_u buf2[NUMBUFLEN];
12260 garray_T ga;
12261
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012262 in_str = tv_get_string(&argvars[0]);
12263 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12264 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012265
12266 /* Default return value: empty string. */
12267 rettv->v_type = VAR_STRING;
12268 rettv->vval.v_string = NULL;
12269 if (fromstr == NULL || tostr == NULL)
12270 return; /* type error; errmsg already given */
12271 ga_init2(&ga, (int)sizeof(char), 80);
12272
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012273 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012274 /* not multi-byte: fromstr and tostr must be the same length */
12275 if (STRLEN(fromstr) != STRLEN(tostr))
12276 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012277error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012278 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012279 ga_clear(&ga);
12280 return;
12281 }
12282
12283 /* fromstr and tostr have to contain the same number of chars */
12284 while (*in_str != NUL)
12285 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012286 if (has_mbyte)
12287 {
12288 inlen = (*mb_ptr2len)(in_str);
12289 cpstr = in_str;
12290 cplen = inlen;
12291 idx = 0;
12292 for (p = fromstr; *p != NUL; p += fromlen)
12293 {
12294 fromlen = (*mb_ptr2len)(p);
12295 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12296 {
12297 for (p = tostr; *p != NUL; p += tolen)
12298 {
12299 tolen = (*mb_ptr2len)(p);
12300 if (idx-- == 0)
12301 {
12302 cplen = tolen;
12303 cpstr = p;
12304 break;
12305 }
12306 }
12307 if (*p == NUL) /* tostr is shorter than fromstr */
12308 goto error;
12309 break;
12310 }
12311 ++idx;
12312 }
12313
12314 if (first && cpstr == in_str)
12315 {
12316 /* Check that fromstr and tostr have the same number of
12317 * (multi-byte) characters. Done only once when a character
12318 * of in_str doesn't appear in fromstr. */
12319 first = FALSE;
12320 for (p = tostr; *p != NUL; p += tolen)
12321 {
12322 tolen = (*mb_ptr2len)(p);
12323 --idx;
12324 }
12325 if (idx != 0)
12326 goto error;
12327 }
12328
12329 (void)ga_grow(&ga, cplen);
12330 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12331 ga.ga_len += cplen;
12332
12333 in_str += inlen;
12334 }
12335 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012336 {
12337 /* When not using multi-byte chars we can do it faster. */
12338 p = vim_strchr(fromstr, *in_str);
12339 if (p != NULL)
12340 ga_append(&ga, tostr[p - fromstr]);
12341 else
12342 ga_append(&ga, *in_str);
12343 ++in_str;
12344 }
12345 }
12346
12347 /* add a terminating NUL */
12348 (void)ga_grow(&ga, 1);
12349 ga_append(&ga, NUL);
12350
12351 rettv->vval.v_string = ga.ga_data;
12352}
12353
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012354/*
12355 * "trim({expr})" function
12356 */
12357 static void
12358f_trim(typval_T *argvars, typval_T *rettv)
12359{
12360 char_u buf1[NUMBUFLEN];
12361 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012362 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012363 char_u *mask = NULL;
12364 char_u *tail;
12365 char_u *prev;
12366 char_u *p;
12367 int c1;
12368
12369 rettv->v_type = VAR_STRING;
12370 if (head == NULL)
12371 {
12372 rettv->vval.v_string = NULL;
12373 return;
12374 }
12375
12376 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012377 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012378
12379 while (*head != NUL)
12380 {
12381 c1 = PTR2CHAR(head);
12382 if (mask == NULL)
12383 {
12384 if (c1 > ' ' && c1 != 0xa0)
12385 break;
12386 }
12387 else
12388 {
12389 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12390 if (c1 == PTR2CHAR(p))
12391 break;
12392 if (*p == NUL)
12393 break;
12394 }
12395 MB_PTR_ADV(head);
12396 }
12397
12398 for (tail = head + STRLEN(head); tail > head; tail = prev)
12399 {
12400 prev = tail;
12401 MB_PTR_BACK(head, prev);
12402 c1 = PTR2CHAR(prev);
12403 if (mask == NULL)
12404 {
12405 if (c1 > ' ' && c1 != 0xa0)
12406 break;
12407 }
12408 else
12409 {
12410 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12411 if (c1 == PTR2CHAR(p))
12412 break;
12413 if (*p == NUL)
12414 break;
12415 }
12416 }
12417 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12418}
12419
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012420#ifdef FEAT_FLOAT
12421/*
12422 * "trunc({float})" function
12423 */
12424 static void
12425f_trunc(typval_T *argvars, typval_T *rettv)
12426{
12427 float_T f = 0.0;
12428
12429 rettv->v_type = VAR_FLOAT;
12430 if (get_float_arg(argvars, &f) == OK)
12431 /* trunc() is not in C90, use floor() or ceil() instead. */
12432 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12433 else
12434 rettv->vval.v_float = 0.0;
12435}
12436#endif
12437
12438/*
12439 * "type(expr)" function
12440 */
12441 static void
12442f_type(typval_T *argvars, typval_T *rettv)
12443{
12444 int n = -1;
12445
12446 switch (argvars[0].v_type)
12447 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012448 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12449 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012450 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012451 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12452 case VAR_LIST: n = VAR_TYPE_LIST; break;
12453 case VAR_DICT: n = VAR_TYPE_DICT; break;
12454 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012455 case VAR_SPECIAL:
12456 if (argvars[0].vval.v_number == VVAL_FALSE
12457 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012458 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012459 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012460 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012461 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012462 case VAR_JOB: n = VAR_TYPE_JOB; break;
12463 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012464 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012465 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012466 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012467 n = -1;
12468 break;
12469 }
12470 rettv->vval.v_number = n;
12471}
12472
12473/*
12474 * "undofile(name)" function
12475 */
12476 static void
12477f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12478{
12479 rettv->v_type = VAR_STRING;
12480#ifdef FEAT_PERSISTENT_UNDO
12481 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012482 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012483
12484 if (*fname == NUL)
12485 {
12486 /* If there is no file name there will be no undo file. */
12487 rettv->vval.v_string = NULL;
12488 }
12489 else
12490 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012491 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012492
12493 if (ffname != NULL)
12494 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12495 vim_free(ffname);
12496 }
12497 }
12498#else
12499 rettv->vval.v_string = NULL;
12500#endif
12501}
12502
12503/*
12504 * "undotree()" function
12505 */
12506 static void
12507f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12508{
12509 if (rettv_dict_alloc(rettv) == OK)
12510 {
12511 dict_T *dict = rettv->vval.v_dict;
12512 list_T *list;
12513
Bram Moolenaare0be1672018-07-08 16:50:37 +020012514 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12515 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12516 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12517 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12518 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12519 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012520
12521 list = list_alloc();
12522 if (list != NULL)
12523 {
12524 u_eval_tree(curbuf->b_u_oldhead, list);
12525 dict_add_list(dict, "entries", list);
12526 }
12527 }
12528}
12529
12530/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012531 * "virtcol(string)" function
12532 */
12533 static void
12534f_virtcol(typval_T *argvars, typval_T *rettv)
12535{
12536 colnr_T vcol = 0;
12537 pos_T *fp;
12538 int fnum = curbuf->b_fnum;
12539
12540 fp = var2fpos(&argvars[0], FALSE, &fnum);
12541 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12542 && fnum == curbuf->b_fnum)
12543 {
12544 getvvcol(curwin, fp, NULL, NULL, &vcol);
12545 ++vcol;
12546 }
12547
12548 rettv->vval.v_number = vcol;
12549}
12550
12551/*
12552 * "visualmode()" function
12553 */
12554 static void
12555f_visualmode(typval_T *argvars, typval_T *rettv)
12556{
12557 char_u str[2];
12558
12559 rettv->v_type = VAR_STRING;
12560 str[0] = curbuf->b_visual_mode_eval;
12561 str[1] = NUL;
12562 rettv->vval.v_string = vim_strsave(str);
12563
12564 /* A non-zero number or non-empty string argument: reset mode. */
12565 if (non_zero_arg(&argvars[0]))
12566 curbuf->b_visual_mode_eval = NUL;
12567}
12568
12569/*
12570 * "wildmenumode()" function
12571 */
12572 static void
12573f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12574{
12575#ifdef FEAT_WILDMENU
12576 if (wild_menu_showing)
12577 rettv->vval.v_number = 1;
12578#endif
12579}
12580
12581/*
12582 * "winbufnr(nr)" function
12583 */
12584 static void
12585f_winbufnr(typval_T *argvars, typval_T *rettv)
12586{
12587 win_T *wp;
12588
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012589 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012590 if (wp == NULL)
12591 rettv->vval.v_number = -1;
12592 else
12593 rettv->vval.v_number = wp->w_buffer->b_fnum;
12594}
12595
12596/*
12597 * "wincol()" function
12598 */
12599 static void
12600f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12601{
12602 validate_cursor();
12603 rettv->vval.v_number = curwin->w_wcol + 1;
12604}
12605
12606/*
12607 * "winheight(nr)" function
12608 */
12609 static void
12610f_winheight(typval_T *argvars, typval_T *rettv)
12611{
12612 win_T *wp;
12613
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012614 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012615 if (wp == NULL)
12616 rettv->vval.v_number = -1;
12617 else
12618 rettv->vval.v_number = wp->w_height;
12619}
12620
12621/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012622 * "winlayout()" function
12623 */
12624 static void
12625f_winlayout(typval_T *argvars, typval_T *rettv)
12626{
12627 tabpage_T *tp;
12628
12629 if (rettv_list_alloc(rettv) != OK)
12630 return;
12631
12632 if (argvars[0].v_type == VAR_UNKNOWN)
12633 tp = curtab;
12634 else
12635 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012636 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012637 if (tp == NULL)
12638 return;
12639 }
12640
12641 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12642}
12643
12644/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012645 * "winline()" function
12646 */
12647 static void
12648f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12649{
12650 validate_cursor();
12651 rettv->vval.v_number = curwin->w_wrow + 1;
12652}
12653
12654/*
12655 * "winnr()" function
12656 */
12657 static void
12658f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12659{
12660 int nr = 1;
12661
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012662 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012663 rettv->vval.v_number = nr;
12664}
12665
12666/*
12667 * "winrestcmd()" function
12668 */
12669 static void
12670f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12671{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012672 win_T *wp;
12673 int winnr = 1;
12674 garray_T ga;
12675 char_u buf[50];
12676
12677 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012678 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012679 {
12680 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12681 ga_concat(&ga, buf);
12682 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12683 ga_concat(&ga, buf);
12684 ++winnr;
12685 }
12686 ga_append(&ga, NUL);
12687
12688 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012689 rettv->v_type = VAR_STRING;
12690}
12691
12692/*
12693 * "winrestview()" function
12694 */
12695 static void
12696f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12697{
12698 dict_T *dict;
12699
12700 if (argvars[0].v_type != VAR_DICT
12701 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012702 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012703 else
12704 {
12705 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012706 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012707 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012708 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012709 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012710 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012711 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12712 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012713 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012714 curwin->w_set_curswant = FALSE;
12715 }
12716
12717 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012718 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012719#ifdef FEAT_DIFF
12720 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012721 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012722#endif
12723 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012724 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012725 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012726 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012727
12728 check_cursor();
12729 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012730 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012731 changed_window_setting();
12732
12733 if (curwin->w_topline <= 0)
12734 curwin->w_topline = 1;
12735 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12736 curwin->w_topline = curbuf->b_ml.ml_line_count;
12737#ifdef FEAT_DIFF
12738 check_topfill(curwin, TRUE);
12739#endif
12740 }
12741}
12742
12743/*
12744 * "winsaveview()" function
12745 */
12746 static void
12747f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12748{
12749 dict_T *dict;
12750
12751 if (rettv_dict_alloc(rettv) == FAIL)
12752 return;
12753 dict = rettv->vval.v_dict;
12754
Bram Moolenaare0be1672018-07-08 16:50:37 +020012755 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12756 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012757 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012758 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012759 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012760
Bram Moolenaare0be1672018-07-08 16:50:37 +020012761 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012762#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012763 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012764#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012765 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12766 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012767}
12768
12769/*
12770 * "winwidth(nr)" function
12771 */
12772 static void
12773f_winwidth(typval_T *argvars, typval_T *rettv)
12774{
12775 win_T *wp;
12776
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012777 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012778 if (wp == NULL)
12779 rettv->vval.v_number = -1;
12780 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012781 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012782}
12783
12784/*
12785 * "wordcount()" function
12786 */
12787 static void
12788f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12789{
12790 if (rettv_dict_alloc(rettv) == FAIL)
12791 return;
12792 cursor_pos_info(rettv->vval.v_dict);
12793}
12794
12795/*
12796 * "writefile()" function
12797 */
12798 static void
12799f_writefile(typval_T *argvars, typval_T *rettv)
12800{
12801 int binary = FALSE;
12802 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012803#ifdef HAVE_FSYNC
12804 int do_fsync = p_fs;
12805#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012806 char_u *fname;
12807 FILE *fd;
12808 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012809 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012810 list_T *list = NULL;
12811 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012812
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012813 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012814 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012815 return;
12816
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012817 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012818 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012819 list = argvars[0].vval.v_list;
12820 if (list == NULL)
12821 return;
12822 for (li = list->lv_first; li != NULL; li = li->li_next)
12823 if (tv_get_string_chk(&li->li_tv) == NULL)
12824 return;
12825 }
12826 else if (argvars[0].v_type == VAR_BLOB)
12827 {
12828 blob = argvars[0].vval.v_blob;
12829 if (blob == NULL)
12830 return;
12831 }
12832 else
12833 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012834 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012835 return;
12836 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012837
12838 if (argvars[2].v_type != VAR_UNKNOWN)
12839 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012840 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012841
12842 if (arg2 == NULL)
12843 return;
12844 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012845 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012846 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012847 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012848#ifdef HAVE_FSYNC
12849 if (vim_strchr(arg2, 's') != NULL)
12850 do_fsync = TRUE;
12851 else if (vim_strchr(arg2, 'S') != NULL)
12852 do_fsync = FALSE;
12853#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012854 }
12855
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012856 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012857 if (fname == NULL)
12858 return;
12859
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012860 /* Always open the file in binary mode, library functions have a mind of
12861 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012862 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12863 append ? APPENDBIN : WRITEBIN)) == NULL)
12864 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012865 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012866 ret = -1;
12867 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012868 else if (blob)
12869 {
12870 if (write_blob(fd, blob) == FAIL)
12871 ret = -1;
12872#ifdef HAVE_FSYNC
12873 else if (do_fsync)
12874 // Ignore the error, the user wouldn't know what to do about it.
12875 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012876 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012877#endif
12878 fclose(fd);
12879 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012880 else
12881 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012882 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012883 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012884#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012885 else if (do_fsync)
12886 /* Ignore the error, the user wouldn't know what to do about it.
12887 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012888 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012889#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012890 fclose(fd);
12891 }
12892
12893 rettv->vval.v_number = ret;
12894}
12895
12896/*
12897 * "xor(expr, expr)" function
12898 */
12899 static void
12900f_xor(typval_T *argvars, typval_T *rettv)
12901{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012902 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
12903 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012904}
12905
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012906#endif /* FEAT_EVAL */