blob: 814499331dd4659ca83450568c916a6d83ed6715 [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 +020038static void f_argc(typval_T *argvars, typval_T *rettv);
39static void f_argidx(typval_T *argvars, typval_T *rettv);
40static void f_arglistid(typval_T *argvars, typval_T *rettv);
41static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020042#ifdef FEAT_FLOAT
43static void f_asin(typval_T *argvars, typval_T *rettv);
44static void f_atan(typval_T *argvars, typval_T *rettv);
45static void f_atan2(typval_T *argvars, typval_T *rettv);
46#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010047#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020048static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010049static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010050# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010051static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010052# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010053#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_browse(typval_T *argvars, typval_T *rettv);
55static void f_browsedir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020056static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_bufexists(typval_T *argvars, typval_T *rettv);
58static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020059static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020060static void f_bufloaded(typval_T *argvars, typval_T *rettv);
61static void f_bufname(typval_T *argvars, typval_T *rettv);
62static void f_bufnr(typval_T *argvars, typval_T *rettv);
63static void f_bufwinid(typval_T *argvars, typval_T *rettv);
64static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
65static void f_byte2line(typval_T *argvars, typval_T *rettv);
66static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
67static void f_byteidx(typval_T *argvars, typval_T *rettv);
68static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
69static void f_call(typval_T *argvars, typval_T *rettv);
70#ifdef FEAT_FLOAT
71static void f_ceil(typval_T *argvars, typval_T *rettv);
72#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_changenr(typval_T *argvars, typval_T *rettv);
74static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +020075static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020078static void f_confirm(typval_T *argvars, typval_T *rettv);
79static void f_copy(typval_T *argvars, typval_T *rettv);
80#ifdef FEAT_FLOAT
81static void f_cos(typval_T *argvars, typval_T *rettv);
82static void f_cosh(typval_T *argvars, typval_T *rettv);
83#endif
84static void f_count(typval_T *argvars, typval_T *rettv);
85static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
86static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010087#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020088static void f_debugbreak(typval_T *argvars, typval_T *rettv);
89#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020090static void f_deepcopy(typval_T *argvars, typval_T *rettv);
91static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020092static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_did_filetype(typval_T *argvars, typval_T *rettv);
94static void f_diff_filler(typval_T *argvars, typval_T *rettv);
95static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
96static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020097static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020098static void f_escape(typval_T *argvars, typval_T *rettv);
99static void f_eval(typval_T *argvars, typval_T *rettv);
100static void f_eventhandler(typval_T *argvars, typval_T *rettv);
101static void f_executable(typval_T *argvars, typval_T *rettv);
102static void f_execute(typval_T *argvars, typval_T *rettv);
103static void f_exepath(typval_T *argvars, typval_T *rettv);
104static void f_exists(typval_T *argvars, typval_T *rettv);
105#ifdef FEAT_FLOAT
106static void f_exp(typval_T *argvars, typval_T *rettv);
107#endif
108static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200109static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200110static void f_extend(typval_T *argvars, typval_T *rettv);
111static void f_feedkeys(typval_T *argvars, typval_T *rettv);
112static void f_filereadable(typval_T *argvars, typval_T *rettv);
113static void f_filewritable(typval_T *argvars, typval_T *rettv);
114static void f_filter(typval_T *argvars, typval_T *rettv);
115static void f_finddir(typval_T *argvars, typval_T *rettv);
116static void f_findfile(typval_T *argvars, typval_T *rettv);
117#ifdef FEAT_FLOAT
118static void f_float2nr(typval_T *argvars, typval_T *rettv);
119static void f_floor(typval_T *argvars, typval_T *rettv);
120static void f_fmod(typval_T *argvars, typval_T *rettv);
121#endif
122static void f_fnameescape(typval_T *argvars, typval_T *rettv);
123static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
124static void f_foldclosed(typval_T *argvars, typval_T *rettv);
125static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
126static void f_foldlevel(typval_T *argvars, typval_T *rettv);
127static void f_foldtext(typval_T *argvars, typval_T *rettv);
128static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
129static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200130static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200131static void f_function(typval_T *argvars, typval_T *rettv);
132static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
133static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200134static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_getbufline(typval_T *argvars, typval_T *rettv);
136static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100137static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200138static void f_getchar(typval_T *argvars, typval_T *rettv);
139static void f_getcharmod(typval_T *argvars, typval_T *rettv);
140static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
141static void f_getcmdline(typval_T *argvars, typval_T *rettv);
142#if defined(FEAT_CMDL_COMPL)
143static void f_getcompletion(typval_T *argvars, typval_T *rettv);
144#endif
145static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
146static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
147static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
148static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200149static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200150static void f_getfontname(typval_T *argvars, typval_T *rettv);
151static void f_getfperm(typval_T *argvars, typval_T *rettv);
152static void f_getfsize(typval_T *argvars, typval_T *rettv);
153static void f_getftime(typval_T *argvars, typval_T *rettv);
154static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100155static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200157static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200158static void f_getpid(typval_T *argvars, typval_T *rettv);
159static void f_getcurpos(typval_T *argvars, typval_T *rettv);
160static void f_getpos(typval_T *argvars, typval_T *rettv);
161static void f_getqflist(typval_T *argvars, typval_T *rettv);
162static void f_getreg(typval_T *argvars, typval_T *rettv);
163static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200164static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_gettabvar(typval_T *argvars, typval_T *rettv);
166static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100167static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200168static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100169static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_getwinposx(typval_T *argvars, typval_T *rettv);
171static void f_getwinposy(typval_T *argvars, typval_T *rettv);
172static void f_getwinvar(typval_T *argvars, typval_T *rettv);
173static void f_glob(typval_T *argvars, typval_T *rettv);
174static void f_globpath(typval_T *argvars, typval_T *rettv);
175static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
176static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
178static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179static void f_hlID(typval_T *argvars, typval_T *rettv);
180static void f_hlexists(typval_T *argvars, typval_T *rettv);
181static void f_hostname(typval_T *argvars, typval_T *rettv);
182static void f_iconv(typval_T *argvars, typval_T *rettv);
183static void f_indent(typval_T *argvars, typval_T *rettv);
184static void f_index(typval_T *argvars, typval_T *rettv);
185static void f_input(typval_T *argvars, typval_T *rettv);
186static void f_inputdialog(typval_T *argvars, typval_T *rettv);
187static void f_inputlist(typval_T *argvars, typval_T *rettv);
188static void f_inputrestore(typval_T *argvars, typval_T *rettv);
189static void f_inputsave(typval_T *argvars, typval_T *rettv);
190static void f_inputsecret(typval_T *argvars, typval_T *rettv);
191static void f_insert(typval_T *argvars, typval_T *rettv);
192static void f_invert(typval_T *argvars, typval_T *rettv);
193static void f_isdirectory(typval_T *argvars, typval_T *rettv);
194static void f_islocked(typval_T *argvars, typval_T *rettv);
195#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200196static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_isnan(typval_T *argvars, typval_T *rettv);
198#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200199static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
200static void f_len(typval_T *argvars, typval_T *rettv);
201static void f_libcall(typval_T *argvars, typval_T *rettv);
202static void f_libcallnr(typval_T *argvars, typval_T *rettv);
203static void f_line(typval_T *argvars, typval_T *rettv);
204static void f_line2byte(typval_T *argvars, typval_T *rettv);
205static void f_lispindent(typval_T *argvars, typval_T *rettv);
206static void f_localtime(typval_T *argvars, typval_T *rettv);
207#ifdef FEAT_FLOAT
208static void f_log(typval_T *argvars, typval_T *rettv);
209static void f_log10(typval_T *argvars, typval_T *rettv);
210#endif
211#ifdef FEAT_LUA
212static void f_luaeval(typval_T *argvars, typval_T *rettv);
213#endif
214static void f_map(typval_T *argvars, typval_T *rettv);
215static void f_maparg(typval_T *argvars, typval_T *rettv);
216static void f_mapcheck(typval_T *argvars, typval_T *rettv);
217static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200218static void f_matchend(typval_T *argvars, typval_T *rettv);
219static void f_matchlist(typval_T *argvars, typval_T *rettv);
220static void f_matchstr(typval_T *argvars, typval_T *rettv);
221static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
222static void f_max(typval_T *argvars, typval_T *rettv);
223static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200224static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_mode(typval_T *argvars, typval_T *rettv);
226#ifdef FEAT_MZSCHEME
227static void f_mzeval(typval_T *argvars, typval_T *rettv);
228#endif
229static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
230static void f_nr2char(typval_T *argvars, typval_T *rettv);
231static void f_or(typval_T *argvars, typval_T *rettv);
232static void f_pathshorten(typval_T *argvars, typval_T *rettv);
233#ifdef FEAT_PERL
234static void f_perleval(typval_T *argvars, typval_T *rettv);
235#endif
236#ifdef FEAT_FLOAT
237static void f_pow(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
240static void f_printf(typval_T *argvars, typval_T *rettv);
241static void f_pumvisible(typval_T *argvars, typval_T *rettv);
242#ifdef FEAT_PYTHON3
243static void f_py3eval(typval_T *argvars, typval_T *rettv);
244#endif
245#ifdef FEAT_PYTHON
246static void f_pyeval(typval_T *argvars, typval_T *rettv);
247#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100248#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
249static void f_pyxeval(typval_T *argvars, typval_T *rettv);
250#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200251static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200252static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200253static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200254static void f_reg_executing(typval_T *argvars, typval_T *rettv);
255static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256static void f_reltime(typval_T *argvars, typval_T *rettv);
257#ifdef FEAT_FLOAT
258static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
259#endif
260static void f_reltimestr(typval_T *argvars, typval_T *rettv);
261static void f_remote_expr(typval_T *argvars, typval_T *rettv);
262static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
263static void f_remote_peek(typval_T *argvars, typval_T *rettv);
264static void f_remote_read(typval_T *argvars, typval_T *rettv);
265static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100266static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200267static void f_remove(typval_T *argvars, typval_T *rettv);
268static void f_rename(typval_T *argvars, typval_T *rettv);
269static void f_repeat(typval_T *argvars, typval_T *rettv);
270static void f_resolve(typval_T *argvars, typval_T *rettv);
271static void f_reverse(typval_T *argvars, typval_T *rettv);
272#ifdef FEAT_FLOAT
273static void f_round(typval_T *argvars, typval_T *rettv);
274#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100275#ifdef FEAT_RUBY
276static void f_rubyeval(typval_T *argvars, typval_T *rettv);
277#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200278static void f_screenattr(typval_T *argvars, typval_T *rettv);
279static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100280static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200281static void f_screencol(typval_T *argvars, typval_T *rettv);
282static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100283static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200284static void f_search(typval_T *argvars, typval_T *rettv);
285static void f_searchdecl(typval_T *argvars, typval_T *rettv);
286static void f_searchpair(typval_T *argvars, typval_T *rettv);
287static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
288static void f_searchpos(typval_T *argvars, typval_T *rettv);
289static void f_server2client(typval_T *argvars, typval_T *rettv);
290static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200291static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200292static void f_setbufvar(typval_T *argvars, typval_T *rettv);
293static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
294static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200295static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200296static void f_setfperm(typval_T *argvars, typval_T *rettv);
297static void f_setline(typval_T *argvars, typval_T *rettv);
298static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200299static void f_setpos(typval_T *argvars, typval_T *rettv);
300static void f_setqflist(typval_T *argvars, typval_T *rettv);
301static void f_setreg(typval_T *argvars, typval_T *rettv);
302static void f_settabvar(typval_T *argvars, typval_T *rettv);
303static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100304static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200305static void f_setwinvar(typval_T *argvars, typval_T *rettv);
306#ifdef FEAT_CRYPT
307static void f_sha256(typval_T *argvars, typval_T *rettv);
308#endif /* FEAT_CRYPT */
309static void f_shellescape(typval_T *argvars, typval_T *rettv);
310static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
311static void f_simplify(typval_T *argvars, typval_T *rettv);
312#ifdef FEAT_FLOAT
313static void f_sin(typval_T *argvars, typval_T *rettv);
314static void f_sinh(typval_T *argvars, typval_T *rettv);
315#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200316static void f_soundfold(typval_T *argvars, typval_T *rettv);
317static void f_spellbadword(typval_T *argvars, typval_T *rettv);
318static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
319static void f_split(typval_T *argvars, typval_T *rettv);
320#ifdef FEAT_FLOAT
321static void f_sqrt(typval_T *argvars, typval_T *rettv);
322static void f_str2float(typval_T *argvars, typval_T *rettv);
323#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200324static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200325static void f_str2nr(typval_T *argvars, typval_T *rettv);
326static void f_strchars(typval_T *argvars, typval_T *rettv);
327#ifdef HAVE_STRFTIME
328static void f_strftime(typval_T *argvars, typval_T *rettv);
329#endif
330static void f_strgetchar(typval_T *argvars, typval_T *rettv);
331static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200332static void f_strlen(typval_T *argvars, typval_T *rettv);
333static void f_strcharpart(typval_T *argvars, typval_T *rettv);
334static void f_strpart(typval_T *argvars, typval_T *rettv);
335static void f_strridx(typval_T *argvars, typval_T *rettv);
336static void f_strtrans(typval_T *argvars, typval_T *rettv);
337static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
338static void f_strwidth(typval_T *argvars, typval_T *rettv);
339static void f_submatch(typval_T *argvars, typval_T *rettv);
340static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200341static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200342static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200343static void f_synID(typval_T *argvars, typval_T *rettv);
344static void f_synIDattr(typval_T *argvars, typval_T *rettv);
345static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
346static void f_synstack(typval_T *argvars, typval_T *rettv);
347static void f_synconcealed(typval_T *argvars, typval_T *rettv);
348static void f_system(typval_T *argvars, typval_T *rettv);
349static void f_systemlist(typval_T *argvars, typval_T *rettv);
350static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
351static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
352static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
353static void f_taglist(typval_T *argvars, typval_T *rettv);
354static void f_tagfiles(typval_T *argvars, typval_T *rettv);
355static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200356#ifdef FEAT_FLOAT
357static void f_tan(typval_T *argvars, typval_T *rettv);
358static void f_tanh(typval_T *argvars, typval_T *rettv);
359#endif
360#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200361static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200362static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200363static void f_timer_start(typval_T *argvars, typval_T *rettv);
364static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200365static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366#endif
367static void f_tolower(typval_T *argvars, typval_T *rettv);
368static void f_toupper(typval_T *argvars, typval_T *rettv);
369static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100370static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200371#ifdef FEAT_FLOAT
372static void f_trunc(typval_T *argvars, typval_T *rettv);
373#endif
374static void f_type(typval_T *argvars, typval_T *rettv);
375static void f_undofile(typval_T *argvars, typval_T *rettv);
376static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200377static void f_virtcol(typval_T *argvars, typval_T *rettv);
378static void f_visualmode(typval_T *argvars, typval_T *rettv);
379static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200380static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
382static void f_win_getid(typval_T *argvars, typval_T *rettv);
383static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
384static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
385static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100386static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200387static void f_winbufnr(typval_T *argvars, typval_T *rettv);
388static void f_wincol(typval_T *argvars, typval_T *rettv);
389static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200390static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391static void f_winline(typval_T *argvars, typval_T *rettv);
392static void f_winnr(typval_T *argvars, typval_T *rettv);
393static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
394static void f_winrestview(typval_T *argvars, typval_T *rettv);
395static void f_winsaveview(typval_T *argvars, typval_T *rettv);
396static void f_winwidth(typval_T *argvars, typval_T *rettv);
397static void f_writefile(typval_T *argvars, typval_T *rettv);
398static void f_wordcount(typval_T *argvars, typval_T *rettv);
399static void f_xor(typval_T *argvars, typval_T *rettv);
400
401/*
402 * Array with names and number of arguments of all internal functions
403 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
404 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200405typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200407 char *f_name; // function name
408 char f_min_argc; // minimal number of arguments
409 char f_max_argc; // maximal number of arguments
410 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200411 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200412 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200413} funcentry_T;
414
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200415// values for f_argtype; zero means it cannot be used as a method
416#define FEARG_1 1 // base is the first argument
417#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200418#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200419#define FEARG_LAST 9 // base is the last argument
420
Bram Moolenaarac92e252019-08-03 21:58:38 +0200421static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200422{
423#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200424 {"abs", 1, 1, 0, f_abs},
425 {"acos", 1, 1, 0, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200426#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200427 {"add", 2, 2, FEARG_1, f_add},
428 {"and", 2, 2, 0, f_and},
429 {"append", 2, 2, FEARG_LAST, f_append},
430 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
431 {"argc", 0, 1, 0, f_argc},
432 {"argidx", 0, 0, 0, f_argidx},
433 {"arglistid", 0, 2, 0, f_arglistid},
434 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200436 {"asin", 1, 1, 0, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200438 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200439 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
440 {"assert_equalfile", 2, 2, 0, f_assert_equalfile},
441 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200442 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
443 {"assert_false", 1, 2, FEARG_1, f_assert_false},
444 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
445 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200446 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200447 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200448 {"assert_report", 1, 1, 0, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200449 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200450#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200451 {"atan", 1, 1, 0, f_atan},
452 {"atan2", 2, 2, 0, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200453#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100454#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200455 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
456 {"balloon_show", 1, 1, 0, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100457# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200458 {"balloon_split", 1, 1, 0, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100459# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100460#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200461 {"browse", 4, 4, 0, f_browse},
462 {"browsedir", 2, 2, 0, f_browsedir},
463 {"bufadd", 1, 1, 0, f_bufadd},
464 {"bufexists", 1, 1, 0, f_bufexists},
465 {"buffer_exists", 1, 1, 0, f_bufexists}, // obsolete
466 {"buffer_name", 1, 1, 0, f_bufname}, // obsolete
467 {"buffer_number", 1, 1, 0, f_bufnr}, // obsolete
468 {"buflisted", 1, 1, 0, f_buflisted},
469 {"bufload", 1, 1, 0, f_bufload},
470 {"bufloaded", 1, 1, 0, f_bufloaded},
471 {"bufname", 1, 1, 0, f_bufname},
472 {"bufnr", 1, 2, 0, f_bufnr},
473 {"bufwinid", 1, 1, 0, f_bufwinid},
474 {"bufwinnr", 1, 1, 0, f_bufwinnr},
475 {"byte2line", 1, 1, 0, f_byte2line},
476 {"byteidx", 2, 2, 0, f_byteidx},
477 {"byteidxcomp", 2, 2, 0, f_byteidxcomp},
478 {"call", 2, 3, 0, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200479#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200480 {"ceil", 1, 1, 0, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200481#endif
482#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200483 {"ch_canread", 1, 1, 0, f_ch_canread},
484 {"ch_close", 1, 1, 0, f_ch_close},
485 {"ch_close_in", 1, 1, 0, f_ch_close_in},
486 {"ch_evalexpr", 2, 3, 0, f_ch_evalexpr},
487 {"ch_evalraw", 2, 3, 0, f_ch_evalraw},
488 {"ch_getbufnr", 2, 2, 0, f_ch_getbufnr},
489 {"ch_getjob", 1, 1, 0, f_ch_getjob},
490 {"ch_info", 1, 1, 0, f_ch_info},
491 {"ch_log", 1, 2, 0, f_ch_log},
492 {"ch_logfile", 1, 2, 0, f_ch_logfile},
493 {"ch_open", 1, 2, 0, f_ch_open},
494 {"ch_read", 1, 2, 0, f_ch_read},
495 {"ch_readblob", 1, 2, 0, f_ch_readblob},
496 {"ch_readraw", 1, 2, 0, f_ch_readraw},
497 {"ch_sendexpr", 2, 3, 0, f_ch_sendexpr},
498 {"ch_sendraw", 2, 3, 0, f_ch_sendraw},
499 {"ch_setoptions", 2, 2, 0, f_ch_setoptions},
500 {"ch_status", 1, 2, 0, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200501#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200502 {"changenr", 0, 0, 0, f_changenr},
503 {"char2nr", 1, 2, 0, f_char2nr},
504 {"chdir", 1, 1, 0, f_chdir},
505 {"cindent", 1, 1, 0, f_cindent},
506 {"clearmatches", 0, 1, 0, f_clearmatches},
507 {"col", 1, 1, 0, f_col},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508#if defined(FEAT_INS_EXPAND)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200509 {"complete", 2, 2, 0, f_complete},
510 {"complete_add", 1, 1, 0, f_complete_add},
511 {"complete_check", 0, 0, 0, f_complete_check},
512 {"complete_info", 0, 1, 0, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200514 {"confirm", 1, 4, 0, f_confirm},
515 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200517 {"cos", 1, 1, 0, f_cos},
518 {"cosh", 1, 1, 0, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200519#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200520 {"count", 2, 4, FEARG_1, f_count},
521 {"cscope_connection",0,3, 0, f_cscope_connection},
522 {"cursor", 1, 3, 0, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100523#ifdef MSWIN
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200524 {"debugbreak", 1, 1, 0, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200525#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200526 {"deepcopy", 1, 2, 0, f_deepcopy},
527 {"delete", 1, 2, 0, f_delete},
528 {"deletebufline", 2, 3, 0, f_deletebufline},
529 {"did_filetype", 0, 0, 0, f_did_filetype},
530 {"diff_filler", 1, 1, 0, f_diff_filler},
531 {"diff_hlID", 2, 2, 0, f_diff_hlID},
532 {"empty", 1, 1, FEARG_1, f_empty},
533 {"environ", 0, 0, 0, f_environ},
534 {"escape", 2, 2, 0, f_escape},
535 {"eval", 1, 1, FEARG_1, f_eval},
536 {"eventhandler", 0, 0, 0, f_eventhandler},
537 {"executable", 1, 1, 0, f_executable},
538 {"execute", 1, 2, 0, f_execute},
539 {"exepath", 1, 1, 0, f_exepath},
540 {"exists", 1, 1, 0, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200541#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200542 {"exp", 1, 1, 0, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200543#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200544 {"expand", 1, 3, 0, f_expand},
545 {"expandcmd", 1, 1, 0, f_expandcmd},
546 {"extend", 2, 3, FEARG_1, f_extend},
547 {"feedkeys", 1, 2, 0, f_feedkeys},
548 {"file_readable", 1, 1, 0, f_filereadable}, // obsolete
549 {"filereadable", 1, 1, 0, f_filereadable},
550 {"filewritable", 1, 1, 0, f_filewritable},
551 {"filter", 2, 2, FEARG_1, f_filter},
552 {"finddir", 1, 3, 0, f_finddir},
553 {"findfile", 1, 3, 0, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200554#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200555 {"float2nr", 1, 1, 0, f_float2nr},
556 {"floor", 1, 1, 0, f_floor},
557 {"fmod", 2, 2, 0, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200558#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200559 {"fnameescape", 1, 1, 0, f_fnameescape},
560 {"fnamemodify", 2, 2, 0, f_fnamemodify},
561 {"foldclosed", 1, 1, 0, f_foldclosed},
562 {"foldclosedend", 1, 1, 0, f_foldclosedend},
563 {"foldlevel", 1, 1, 0, f_foldlevel},
564 {"foldtext", 0, 0, 0, f_foldtext},
565 {"foldtextresult", 1, 1, 0, f_foldtextresult},
566 {"foreground", 0, 0, 0, f_foreground},
567 {"funcref", 1, 3, 0, f_funcref},
568 {"function", 1, 3, 0, f_function},
569 {"garbagecollect", 0, 1, 0, f_garbagecollect},
570 {"get", 2, 3, FEARG_1, f_get},
571 {"getbufinfo", 0, 1, 0, f_getbufinfo},
572 {"getbufline", 2, 3, 0, f_getbufline},
573 {"getbufvar", 2, 3, 0, f_getbufvar},
574 {"getchangelist", 1, 1, 0, f_getchangelist},
575 {"getchar", 0, 1, 0, f_getchar},
576 {"getcharmod", 0, 0, 0, f_getcharmod},
577 {"getcharsearch", 0, 0, 0, f_getcharsearch},
578 {"getcmdline", 0, 0, 0, f_getcmdline},
579 {"getcmdpos", 0, 0, 0, f_getcmdpos},
580 {"getcmdtype", 0, 0, 0, f_getcmdtype},
581 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200582#if defined(FEAT_CMDL_COMPL)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200583 {"getcompletion", 2, 3, 0, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200584#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200585 {"getcurpos", 0, 0, 0, f_getcurpos},
586 {"getcwd", 0, 2, 0, f_getcwd},
587 {"getenv", 1, 1, 0, f_getenv},
588 {"getfontname", 0, 1, 0, f_getfontname},
589 {"getfperm", 1, 1, 0, f_getfperm},
590 {"getfsize", 1, 1, 0, f_getfsize},
591 {"getftime", 1, 1, 0, f_getftime},
592 {"getftype", 1, 1, 0, f_getftype},
593 {"getjumplist", 0, 2, 0, f_getjumplist},
594 {"getline", 1, 2, 0, f_getline},
595 {"getloclist", 1, 2, 0, f_getloclist},
596 {"getmatches", 0, 1, 0, f_getmatches},
597 {"getpid", 0, 0, 0, f_getpid},
598 {"getpos", 1, 1, 0, f_getpos},
599 {"getqflist", 0, 1, 0, f_getqflist},
600 {"getreg", 0, 3, 0, f_getreg},
601 {"getregtype", 0, 1, 0, f_getregtype},
602 {"gettabinfo", 0, 1, 0, f_gettabinfo},
603 {"gettabvar", 2, 3, 0, f_gettabvar},
604 {"gettabwinvar", 3, 4, 0, f_gettabwinvar},
605 {"gettagstack", 0, 1, 0, f_gettagstack},
606 {"getwininfo", 0, 1, 0, f_getwininfo},
607 {"getwinpos", 0, 1, 0, f_getwinpos},
608 {"getwinposx", 0, 0, 0, f_getwinposx},
609 {"getwinposy", 0, 0, 0, f_getwinposy},
610 {"getwinvar", 2, 3, 0, f_getwinvar},
611 {"glob", 1, 4, 0, f_glob},
612 {"glob2regpat", 1, 1, 0, f_glob2regpat},
613 {"globpath", 2, 5, 0, f_globpath},
614 {"has", 1, 1, 0, f_has},
615 {"has_key", 2, 2, FEARG_1, f_has_key},
616 {"haslocaldir", 0, 2, 0, f_haslocaldir},
617 {"hasmapto", 1, 3, 0, f_hasmapto},
618 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
619 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
620 {"histadd", 2, 2, 0, f_histadd},
621 {"histdel", 1, 2, 0, f_histdel},
622 {"histget", 1, 2, 0, f_histget},
623 {"histnr", 1, 1, 0, f_histnr},
624 {"hlID", 1, 1, 0, f_hlID},
625 {"hlexists", 1, 1, 0, f_hlexists},
626 {"hostname", 0, 0, 0, f_hostname},
627 {"iconv", 3, 3, 0, f_iconv},
628 {"indent", 1, 1, 0, f_indent},
629 {"index", 2, 4, FEARG_1, f_index},
630 {"input", 1, 3, 0, f_input},
631 {"inputdialog", 1, 3, 0, f_inputdialog},
632 {"inputlist", 1, 1, 0, f_inputlist},
633 {"inputrestore", 0, 0, 0, f_inputrestore},
634 {"inputsave", 0, 0, 0, f_inputsave},
635 {"inputsecret", 1, 2, 0, f_inputsecret},
636 {"insert", 2, 3, FEARG_1, f_insert},
637 {"invert", 1, 1, 0, f_invert},
638 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200639#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200640 {"isinf", 1, 1, 0, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200641#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200642 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200644 {"isnan", 1, 1, 0, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200645#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200646 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200647#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200648 {"job_getchannel", 1, 1, 0, f_job_getchannel},
649 {"job_info", 0, 1, 0, f_job_info},
650 {"job_setoptions", 2, 2, 0, f_job_setoptions},
651 {"job_start", 1, 2, 0, f_job_start},
652 {"job_status", 1, 1, 0, f_job_status},
653 {"job_stop", 1, 2, 0, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200654#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200655 {"join", 1, 2, FEARG_1, f_join},
656 {"js_decode", 1, 1, 0, f_js_decode},
657 {"js_encode", 1, 1, 0, f_js_encode},
658 {"json_decode", 1, 1, 0, f_json_decode},
659 {"json_encode", 1, 1, 0, f_json_encode},
660 {"keys", 1, 1, FEARG_1, f_keys},
661 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
662 {"len", 1, 1, FEARG_1, f_len},
663 {"libcall", 3, 3, 0, f_libcall},
664 {"libcallnr", 3, 3, 0, f_libcallnr},
665 {"line", 1, 1, 0, f_line},
666 {"line2byte", 1, 1, 0, f_line2byte},
667 {"lispindent", 1, 1, 0, f_lispindent},
668 {"list2str", 1, 2, 0, f_list2str},
669 {"listener_add", 1, 2, 0, f_listener_add},
670 {"listener_flush", 0, 1, 0, f_listener_flush},
671 {"listener_remove", 1, 1, 0, f_listener_remove},
672 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200673#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200674 {"log", 1, 1, 0, f_log},
675 {"log10", 1, 1, 0, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200676#endif
677#ifdef FEAT_LUA
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200678 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200679#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200680 {"map", 2, 2, FEARG_1, f_map},
681 {"maparg", 1, 4, 0, f_maparg},
682 {"mapcheck", 1, 3, 0, f_mapcheck},
683 {"match", 2, 4, 0, f_match},
684 {"matchadd", 2, 5, 0, f_matchadd},
685 {"matchaddpos", 2, 5, 0, f_matchaddpos},
686 {"matcharg", 1, 1, 0, f_matcharg},
687 {"matchdelete", 1, 2, 0, f_matchdelete},
688 {"matchend", 2, 4, 0, f_matchend},
689 {"matchlist", 2, 4, 0, f_matchlist},
690 {"matchstr", 2, 4, 0, f_matchstr},
691 {"matchstrpos", 2, 4, 0, f_matchstrpos},
692 {"max", 1, 1, FEARG_1, f_max},
693 {"min", 1, 1, FEARG_1, f_min},
694 {"mkdir", 1, 3, 0, f_mkdir},
695 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200696#ifdef FEAT_MZSCHEME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200697 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200698#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200699 {"nextnonblank", 1, 1, 0, f_nextnonblank},
700 {"nr2char", 1, 2, 0, f_nr2char},
701 {"or", 2, 2, 0, f_or},
702 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200703#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200704 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200705#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200706#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200707 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
708 {"popup_beval", 2, 2, 0, f_popup_beval},
709 {"popup_clear", 0, 0, 0, f_popup_clear},
710 {"popup_close", 1, 2, 0, f_popup_close},
711 {"popup_create", 2, 2, 0, f_popup_create},
712 {"popup_dialog", 2, 2, 0, f_popup_dialog},
713 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
714 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
715 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
716 {"popup_getpos", 1, 1, 0, f_popup_getpos},
717 {"popup_getpreview", 0, 0, 0, f_popup_getpreview},
718 {"popup_hide", 1, 1, 0, f_popup_hide},
719 {"popup_locate", 2, 2, 0, f_popup_locate},
720 {"popup_menu", 2, 2, 0, f_popup_menu},
721 {"popup_move", 2, 2, 0, f_popup_move},
722 {"popup_notification", 2, 2, 0, f_popup_notification},
723 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
724 {"popup_settext", 2, 2, 0, f_popup_settext},
725 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200726#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200728 {"pow", 2, 2, 0, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200729#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200730 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200731 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200732#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200733 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
734 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
735 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200736#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100737#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200738 {"prop_add", 3, 3, 0, f_prop_add},
739 {"prop_clear", 1, 3, 0, f_prop_clear},
740 {"prop_list", 1, 2, 0, f_prop_list},
741 {"prop_remove", 1, 3, 0, f_prop_remove},
742 {"prop_type_add", 2, 2, 0, f_prop_type_add},
743 {"prop_type_change", 2, 2, 0, f_prop_type_change},
744 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
745 {"prop_type_get", 1, 2, 0, f_prop_type_get},
746 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100747#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200748 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200749#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200750 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200751#endif
752#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200753 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200754#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100755#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200756 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100757#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200758 {"range", 1, 3, 0, f_range},
759 {"readdir", 1, 2, 0, f_readdir},
760 {"readfile", 1, 3, 0, f_readfile},
761 {"reg_executing", 0, 0, 0, f_reg_executing},
762 {"reg_recording", 0, 0, 0, f_reg_recording},
763 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200764#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200765 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200766#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200767 {"reltimestr", 1, 1, 0, f_reltimestr},
768 {"remote_expr", 2, 4, 0, f_remote_expr},
769 {"remote_foreground", 1, 1, 0, f_remote_foreground},
770 {"remote_peek", 1, 2, 0, f_remote_peek},
771 {"remote_read", 1, 2, 0, f_remote_read},
772 {"remote_send", 2, 3, 0, f_remote_send},
773 {"remote_startserver", 1, 1, 0, f_remote_startserver},
774 {"remove", 2, 3, FEARG_1, f_remove},
775 {"rename", 2, 2, 0, f_rename},
776 {"repeat", 2, 2, FEARG_1, f_repeat},
777 {"resolve", 1, 1, 0, f_resolve},
778 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200780 {"round", 1, 1, 0, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200781#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100782#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200783 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100784#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200785 {"screenattr", 2, 2, 0, f_screenattr},
786 {"screenchar", 2, 2, 0, f_screenchar},
787 {"screenchars", 2, 2, 0, f_screenchars},
788 {"screencol", 0, 0, 0, f_screencol},
789 {"screenpos", 3, 3, 0, f_screenpos},
790 {"screenrow", 0, 0, 0, f_screenrow},
791 {"screenstring", 2, 2, 0, f_screenstring},
792 {"search", 1, 4, 0, f_search},
793 {"searchdecl", 1, 3, 0, f_searchdecl},
794 {"searchpair", 3, 7, 0, f_searchpair},
795 {"searchpairpos", 3, 7, 0, f_searchpairpos},
796 {"searchpos", 1, 4, 0, f_searchpos},
797 {"server2client", 2, 2, 0, f_server2client},
798 {"serverlist", 0, 0, 0, f_serverlist},
799 {"setbufline", 3, 3, 0, f_setbufline},
800 {"setbufvar", 3, 3, 0, f_setbufvar},
801 {"setcharsearch", 1, 1, 0, f_setcharsearch},
802 {"setcmdpos", 1, 1, 0, f_setcmdpos},
803 {"setenv", 2, 2, 0, f_setenv},
804 {"setfperm", 2, 2, 0, f_setfperm},
805 {"setline", 2, 2, 0, f_setline},
806 {"setloclist", 2, 4, 0, f_setloclist},
807 {"setmatches", 1, 2, 0, f_setmatches},
808 {"setpos", 2, 2, 0, f_setpos},
809 {"setqflist", 1, 3, 0, f_setqflist},
810 {"setreg", 2, 3, 0, f_setreg},
811 {"settabvar", 3, 3, 0, f_settabvar},
812 {"settabwinvar", 4, 4, 0, f_settabwinvar},
813 {"settagstack", 2, 3, 0, f_settagstack},
814 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200815#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200816 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200818 {"shellescape", 1, 2, 0, f_shellescape},
819 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100820#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200821 {"sign_define", 1, 2, 0, f_sign_define},
822 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
823 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
824 {"sign_jump", 3, 3, 0, f_sign_jump},
825 {"sign_place", 4, 5, 0, f_sign_place},
826 {"sign_placelist", 1, 1, 0, f_sign_placelist},
827 {"sign_undefine", 0, 1, 0, f_sign_undefine},
828 {"sign_unplace", 1, 2, 0, f_sign_unplace},
829 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100830#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200831 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200832#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200833 {"sin", 1, 1, 0, f_sin},
834 {"sinh", 1, 1, 0, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200835#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200836 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200837#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200838 {"sound_clear", 0, 0, 0, f_sound_clear},
839 {"sound_playevent", 1, 2, 0, f_sound_playevent},
840 {"sound_playfile", 1, 2, 0, f_sound_playfile},
841 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200842#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200843 {"soundfold", 1, 1, 0, f_soundfold},
844 {"spellbadword", 0, 1, 0, f_spellbadword},
845 {"spellsuggest", 1, 3, 0, f_spellsuggest},
846 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200848 {"sqrt", 1, 1, 0, f_sqrt},
849 {"str2float", 1, 1, 0, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200851 {"str2list", 1, 2, FEARG_1, f_str2list},
852 {"str2nr", 1, 2, 0, f_str2nr},
853 {"strcharpart", 2, 3, 0, f_strcharpart},
854 {"strchars", 1, 2, 0, f_strchars},
855 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200857 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200858#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200859 {"strgetchar", 2, 2, 0, f_strgetchar},
860 {"stridx", 2, 3, 0, f_stridx},
861 {"string", 1, 1, FEARG_1, f_string},
862 {"strlen", 1, 1, FEARG_1, f_strlen},
863 {"strpart", 2, 3, 0, f_strpart},
864 {"strridx", 2, 3, 0, f_strridx},
865 {"strtrans", 1, 1, FEARG_1, f_strtrans},
866 {"strwidth", 1, 1, FEARG_1, f_strwidth},
867 {"submatch", 1, 2, 0, f_submatch},
868 {"substitute", 4, 4, FEARG_1, f_substitute},
869 {"swapinfo", 1, 1, 0, f_swapinfo},
870 {"swapname", 1, 1, 0, f_swapname},
871 {"synID", 3, 3, 0, f_synID},
872 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
873 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
874 {"synconcealed", 2, 2, 0, f_synconcealed},
875 {"synstack", 2, 2, 0, f_synstack},
876 {"system", 1, 2, FEARG_1, f_system},
877 {"systemlist", 1, 2, FEARG_1, f_systemlist},
878 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
879 {"tabpagenr", 0, 1, 0, f_tabpagenr},
880 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
881 {"tagfiles", 0, 0, 0, f_tagfiles},
882 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200884 {"tan", 1, 1, 0, f_tan},
885 {"tanh", 1, 1, 0, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200887 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200888#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200889 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
890 {"term_dumpload", 1, 2, 0, f_term_dumpload},
891 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
892 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200893# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200894 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200895# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200896 {"term_getattr", 2, 2, 0, f_term_getattr},
897 {"term_getcursor", 1, 1, 0, f_term_getcursor},
898 {"term_getjob", 1, 1, 0, f_term_getjob},
899 {"term_getline", 2, 2, 0, f_term_getline},
900 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
901 {"term_getsize", 1, 1, 0, f_term_getsize},
902 {"term_getstatus", 1, 1, 0, f_term_getstatus},
903 {"term_gettitle", 1, 1, 0, f_term_gettitle},
904 {"term_gettty", 1, 2, 0, f_term_gettty},
905 {"term_list", 0, 0, 0, f_term_list},
906 {"term_scrape", 2, 2, 0, f_term_scrape},
907 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200908# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200909 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200910# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200911 {"term_setkill", 2, 2, 0, f_term_setkill},
912 {"term_setrestore", 2, 2, 0, f_term_setrestore},
913 {"term_setsize", 3, 3, 0, f_term_setsize},
914 {"term_start", 1, 2, 0, f_term_start},
915 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200916#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200917 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
918 {"test_autochdir", 0, 0, 0, f_test_autochdir},
919 {"test_feedinput", 1, 1, 0, f_test_feedinput},
920 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
921 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
922 {"test_getvalue", 1, 1, 0, f_test_getvalue},
923 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
924 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200926 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200927#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200928 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200930 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200931#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200932 {"test_null_list", 0, 0, 0, f_test_null_list},
933 {"test_null_partial", 0, 0, 0, f_test_null_partial},
934 {"test_null_string", 0, 0, 0, f_test_null_string},
935 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
936 {"test_override", 2, 2, 0, f_test_override},
937 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200938#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200939 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200940#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200941#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200942 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200943#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200944 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200945#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200946 {"timer_info", 0, 1, 0, f_timer_info},
947 {"timer_pause", 2, 2, 0, f_timer_pause},
948 {"timer_start", 2, 3, 0, f_timer_start},
949 {"timer_stop", 1, 1, 0, f_timer_stop},
950 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200952 {"tolower", 1, 1, 0, f_tolower},
953 {"toupper", 1, 1, 0, f_toupper},
954 {"tr", 3, 3, 0, f_tr},
955 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200957 {"trunc", 1, 1, 0, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200958#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200959 {"type", 1, 1, FEARG_1, f_type},
960 {"undofile", 1, 1, 0, f_undofile},
961 {"undotree", 0, 0, 0, f_undotree},
962 {"uniq", 1, 3, FEARG_1, f_uniq},
963 {"values", 1, 1, FEARG_1, f_values},
964 {"virtcol", 1, 1, 0, f_virtcol},
965 {"visualmode", 0, 1, 0, f_visualmode},
966 {"wildmenumode", 0, 0, 0, f_wildmenumode},
967 {"win_execute", 2, 3, 0, f_win_execute},
968 {"win_findbuf", 1, 1, 0, f_win_findbuf},
969 {"win_getid", 0, 2, 0, f_win_getid},
970 {"win_gotoid", 1, 1, 0, f_win_gotoid},
971 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
972 {"win_id2win", 1, 1, 0, f_win_id2win},
973 {"win_screenpos", 1, 1, 0, f_win_screenpos},
974 {"winbufnr", 1, 1, 0, f_winbufnr},
975 {"wincol", 0, 0, 0, f_wincol},
976 {"winheight", 1, 1, 0, f_winheight},
977 {"winlayout", 0, 1, 0, f_winlayout},
978 {"winline", 0, 0, 0, f_winline},
979 {"winnr", 0, 1, 0, f_winnr},
980 {"winrestcmd", 0, 0, 0, f_winrestcmd},
981 {"winrestview", 1, 1, 0, f_winrestview},
982 {"winsaveview", 0, 0, 0, f_winsaveview},
983 {"winwidth", 1, 1, 0, f_winwidth},
984 {"wordcount", 0, 0, 0, f_wordcount},
985 {"writefile", 2, 3, 0, f_writefile},
986 {"xor", 2, 2, 0, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200987};
988
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200989#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
990
991/*
992 * Function given to ExpandGeneric() to obtain the list of internal
993 * or user defined function names.
994 */
995 char_u *
996get_function_name(expand_T *xp, int idx)
997{
998 static int intidx = -1;
999 char_u *name;
1000
1001 if (idx == 0)
1002 intidx = -1;
1003 if (intidx < 0)
1004 {
1005 name = get_user_func_name(xp, idx);
1006 if (name != NULL)
1007 return name;
1008 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001009 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001010 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001011 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001013 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014 STRCAT(IObuff, ")");
1015 return IObuff;
1016 }
1017
1018 return NULL;
1019}
1020
1021/*
1022 * Function given to ExpandGeneric() to obtain the list of internal or
1023 * user defined variable or function names.
1024 */
1025 char_u *
1026get_expr_name(expand_T *xp, int idx)
1027{
1028 static int intidx = -1;
1029 char_u *name;
1030
1031 if (idx == 0)
1032 intidx = -1;
1033 if (intidx < 0)
1034 {
1035 name = get_function_name(xp, idx);
1036 if (name != NULL)
1037 return name;
1038 }
1039 return get_user_var_name(xp, ++intidx);
1040}
1041
1042#endif /* FEAT_CMDL_COMPL */
1043
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001044/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001045 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001046 * Return index, or -1 if not found
1047 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001048 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001049find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001050{
1051 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001052 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001053 int cmp;
1054 int x;
1055
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001056 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001057
1058 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001059 while (first <= last)
1060 {
1061 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001062 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001063 if (cmp < 0)
1064 last = x - 1;
1065 else if (cmp > 0)
1066 first = x + 1;
1067 else
1068 return x;
1069 }
1070 return -1;
1071}
1072
1073 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001074has_internal_func(char_u *name)
1075{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001076 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001077}
1078
1079 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080call_internal_func(
1081 char_u *name,
1082 int argcount,
1083 typval_T *argvars,
1084 typval_T *rettv)
1085{
1086 int i;
1087
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001088 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001089 if (i < 0)
1090 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001091 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001092 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001093 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001094 return ERROR_TOOMANY;
1095 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001096 global_functions[i].f_func(argvars, rettv);
1097 return ERROR_NONE;
1098}
1099
1100/*
1101 * Invoke a method for base->method().
1102 */
1103 int
1104call_internal_method(
1105 char_u *name,
1106 int argcount,
1107 typval_T *argvars,
1108 typval_T *rettv,
1109 typval_T *basetv)
1110{
1111 int i;
1112 int fi;
1113 typval_T argv[MAX_FUNC_ARGS + 1];
1114
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001115 fi = find_internal_func(name);
1116 if (fi < 0 || global_functions[fi].f_argtype == 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001117 return ERROR_UNKNOWN;
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
1497/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001498 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499 */
1500 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001501f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001503 win_T *wp;
1504
1505 if (argvars[0].v_type == VAR_UNKNOWN)
1506 // use the current window
1507 rettv->vval.v_number = ARGCOUNT;
1508 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001509 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001510 // use the global argument list
1511 rettv->vval.v_number = GARGCOUNT;
1512 else
1513 {
1514 // use the argument list of the specified window
1515 wp = find_win_by_nr_or_id(&argvars[0]);
1516 if (wp != NULL)
1517 rettv->vval.v_number = WARGCOUNT(wp);
1518 else
1519 rettv->vval.v_number = -1;
1520 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001521}
1522
1523/*
1524 * "argidx()" function
1525 */
1526 static void
1527f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1528{
1529 rettv->vval.v_number = curwin->w_arg_idx;
1530}
1531
1532/*
1533 * "arglistid()" function
1534 */
1535 static void
1536f_arglistid(typval_T *argvars, typval_T *rettv)
1537{
1538 win_T *wp;
1539
1540 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001541 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542 if (wp != NULL)
1543 rettv->vval.v_number = wp->w_alist->id;
1544}
1545
1546/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001547 * Get the argument list for a given window
1548 */
1549 static void
1550get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1551{
1552 int idx;
1553
1554 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1555 for (idx = 0; idx < argcount; ++idx)
1556 list_append_string(rettv->vval.v_list,
1557 alist_name(&arglist[idx]), -1);
1558}
1559
1560/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001561 * "argv(nr)" function
1562 */
1563 static void
1564f_argv(typval_T *argvars, typval_T *rettv)
1565{
1566 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001567 aentry_T *arglist = NULL;
1568 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001569
1570 if (argvars[0].v_type != VAR_UNKNOWN)
1571 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001572 if (argvars[1].v_type == VAR_UNKNOWN)
1573 {
1574 arglist = ARGLIST;
1575 argcount = ARGCOUNT;
1576 }
1577 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001578 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001579 {
1580 arglist = GARGLIST;
1581 argcount = GARGCOUNT;
1582 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001583 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001584 {
1585 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1586
1587 if (wp != NULL)
1588 {
1589 /* Use the argument list of the specified window */
1590 arglist = WARGLIST(wp);
1591 argcount = WARGCOUNT(wp);
1592 }
1593 }
1594
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001595 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001596 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001597 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001598 if (arglist != NULL && idx >= 0 && idx < argcount)
1599 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1600 else if (idx == -1)
1601 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001603 else
1604 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001605}
1606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607#ifdef FEAT_FLOAT
1608/*
1609 * "asin()" function
1610 */
1611 static void
1612f_asin(typval_T *argvars, typval_T *rettv)
1613{
1614 float_T f = 0.0;
1615
1616 rettv->v_type = VAR_FLOAT;
1617 if (get_float_arg(argvars, &f) == OK)
1618 rettv->vval.v_float = asin(f);
1619 else
1620 rettv->vval.v_float = 0.0;
1621}
1622
1623/*
1624 * "atan()" function
1625 */
1626 static void
1627f_atan(typval_T *argvars, typval_T *rettv)
1628{
1629 float_T f = 0.0;
1630
1631 rettv->v_type = VAR_FLOAT;
1632 if (get_float_arg(argvars, &f) == OK)
1633 rettv->vval.v_float = atan(f);
1634 else
1635 rettv->vval.v_float = 0.0;
1636}
1637
1638/*
1639 * "atan2()" function
1640 */
1641 static void
1642f_atan2(typval_T *argvars, typval_T *rettv)
1643{
1644 float_T fx = 0.0, fy = 0.0;
1645
1646 rettv->v_type = VAR_FLOAT;
1647 if (get_float_arg(argvars, &fx) == OK
1648 && get_float_arg(&argvars[1], &fy) == OK)
1649 rettv->vval.v_float = atan2(fx, fy);
1650 else
1651 rettv->vval.v_float = 0.0;
1652}
1653#endif
1654
1655/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001656 * "balloon_show()" function
1657 */
1658#ifdef FEAT_BEVAL
1659 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001660f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1661{
1662 rettv->v_type = VAR_STRING;
1663 if (balloonEval != NULL)
1664 {
1665 if (balloonEval->msg == NULL)
1666 rettv->vval.v_string = NULL;
1667 else
1668 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1669 }
1670}
1671
1672 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001673f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1674{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001675 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001676 {
1677 if (argvars[0].v_type == VAR_LIST
1678# ifdef FEAT_GUI
1679 && !gui.in_use
1680# endif
1681 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001682 {
1683 list_T *l = argvars[0].vval.v_list;
1684
1685 // empty list removes the balloon
1686 post_balloon(balloonEval, NULL,
1687 l == NULL || l->lv_len == 0 ? NULL : l);
1688 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001689 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001690 {
1691 char_u *mesg = tv_get_string_chk(&argvars[0]);
1692
1693 if (mesg != NULL)
1694 // empty string removes the balloon
1695 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1696 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001697 }
1698}
1699
Bram Moolenaar669a8282017-11-19 20:13:05 +01001700# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001701 static void
1702f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1703{
1704 if (rettv_list_alloc(rettv) == OK)
1705 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001706 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001707
1708 if (msg != NULL)
1709 {
1710 pumitem_T *array;
1711 int size = split_message(msg, &array);
1712 int i;
1713
1714 /* Skip the first and last item, they are always empty. */
1715 for (i = 1; i < size - 1; ++i)
1716 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001717 while (size > 0)
1718 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001719 vim_free(array);
1720 }
1721 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001722}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001723# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001724#endif
1725
1726/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727 * "browse(save, title, initdir, default)" function
1728 */
1729 static void
1730f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1731{
1732#ifdef FEAT_BROWSE
1733 int save;
1734 char_u *title;
1735 char_u *initdir;
1736 char_u *defname;
1737 char_u buf[NUMBUFLEN];
1738 char_u buf2[NUMBUFLEN];
1739 int error = FALSE;
1740
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001741 save = (int)tv_get_number_chk(&argvars[0], &error);
1742 title = tv_get_string_chk(&argvars[1]);
1743 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1744 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001745
1746 if (error || title == NULL || initdir == NULL || defname == NULL)
1747 rettv->vval.v_string = NULL;
1748 else
1749 rettv->vval.v_string =
1750 do_browse(save ? BROWSE_SAVE : 0,
1751 title, defname, NULL, initdir, NULL, curbuf);
1752#else
1753 rettv->vval.v_string = NULL;
1754#endif
1755 rettv->v_type = VAR_STRING;
1756}
1757
1758/*
1759 * "browsedir(title, initdir)" function
1760 */
1761 static void
1762f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1763{
1764#ifdef FEAT_BROWSE
1765 char_u *title;
1766 char_u *initdir;
1767 char_u buf[NUMBUFLEN];
1768
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001769 title = tv_get_string_chk(&argvars[0]);
1770 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001771
1772 if (title == NULL || initdir == NULL)
1773 rettv->vval.v_string = NULL;
1774 else
1775 rettv->vval.v_string = do_browse(BROWSE_DIR,
1776 title, NULL, NULL, initdir, NULL, curbuf);
1777#else
1778 rettv->vval.v_string = NULL;
1779#endif
1780 rettv->v_type = VAR_STRING;
1781}
1782
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001783/*
1784 * Find a buffer by number or exact name.
1785 */
1786 static buf_T *
1787find_buffer(typval_T *avar)
1788{
1789 buf_T *buf = NULL;
1790
1791 if (avar->v_type == VAR_NUMBER)
1792 buf = buflist_findnr((int)avar->vval.v_number);
1793 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1794 {
1795 buf = buflist_findname_exp(avar->vval.v_string);
1796 if (buf == NULL)
1797 {
1798 /* No full path name match, try a match with a URL or a "nofile"
1799 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001800 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001801 if (buf->b_fname != NULL
1802 && (path_with_url(buf->b_fname)
1803#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001804 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001805#endif
1806 )
1807 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1808 break;
1809 }
1810 }
1811 return buf;
1812}
1813
1814/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001815 * "bufadd(expr)" function
1816 */
1817 static void
1818f_bufadd(typval_T *argvars, typval_T *rettv)
1819{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001820 char_u *name = tv_get_string(&argvars[0]);
1821
1822 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001823}
1824
1825/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001826 * "bufexists(expr)" function
1827 */
1828 static void
1829f_bufexists(typval_T *argvars, typval_T *rettv)
1830{
1831 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1832}
1833
1834/*
1835 * "buflisted(expr)" function
1836 */
1837 static void
1838f_buflisted(typval_T *argvars, typval_T *rettv)
1839{
1840 buf_T *buf;
1841
1842 buf = find_buffer(&argvars[0]);
1843 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1844}
1845
1846/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001847 * "bufload(expr)" function
1848 */
1849 static void
1850f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1851{
1852 buf_T *buf = get_buf_arg(&argvars[0]);
1853
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001854 if (buf != NULL)
1855 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001856}
1857
1858/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001859 * "bufloaded(expr)" function
1860 */
1861 static void
1862f_bufloaded(typval_T *argvars, typval_T *rettv)
1863{
1864 buf_T *buf;
1865
1866 buf = find_buffer(&argvars[0]);
1867 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1868}
1869
1870 buf_T *
1871buflist_find_by_name(char_u *name, int curtab_only)
1872{
1873 int save_magic;
1874 char_u *save_cpo;
1875 buf_T *buf;
1876
1877 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1878 save_magic = p_magic;
1879 p_magic = TRUE;
1880 save_cpo = p_cpo;
1881 p_cpo = (char_u *)"";
1882
1883 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1884 TRUE, FALSE, curtab_only));
1885
1886 p_magic = save_magic;
1887 p_cpo = save_cpo;
1888 return buf;
1889}
1890
1891/*
1892 * Get buffer by number or pattern.
1893 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001894 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001895tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001896{
1897 char_u *name = tv->vval.v_string;
1898 buf_T *buf;
1899
1900 if (tv->v_type == VAR_NUMBER)
1901 return buflist_findnr((int)tv->vval.v_number);
1902 if (tv->v_type != VAR_STRING)
1903 return NULL;
1904 if (name == NULL || *name == NUL)
1905 return curbuf;
1906 if (name[0] == '$' && name[1] == NUL)
1907 return lastbuf;
1908
1909 buf = buflist_find_by_name(name, curtab_only);
1910
1911 /* If not found, try expanding the name, like done for bufexists(). */
1912 if (buf == NULL)
1913 buf = find_buffer(tv);
1914
1915 return buf;
1916}
1917
1918/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001919 * Get the buffer from "arg" and give an error and return NULL if it is not
1920 * valid.
1921 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001922 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001923get_buf_arg(typval_T *arg)
1924{
1925 buf_T *buf;
1926
1927 ++emsg_off;
1928 buf = tv_get_buf(arg, FALSE);
1929 --emsg_off;
1930 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001931 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001932 return buf;
1933}
1934
1935/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001936 * "bufname(expr)" function
1937 */
1938 static void
1939f_bufname(typval_T *argvars, typval_T *rettv)
1940{
1941 buf_T *buf;
1942
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001943 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001944 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001945 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001946 rettv->v_type = VAR_STRING;
1947 if (buf != NULL && buf->b_fname != NULL)
1948 rettv->vval.v_string = vim_strsave(buf->b_fname);
1949 else
1950 rettv->vval.v_string = NULL;
1951 --emsg_off;
1952}
1953
1954/*
1955 * "bufnr(expr)" function
1956 */
1957 static void
1958f_bufnr(typval_T *argvars, typval_T *rettv)
1959{
1960 buf_T *buf;
1961 int error = FALSE;
1962 char_u *name;
1963
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001964 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001965 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001966 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001967 --emsg_off;
1968
1969 /* If the buffer isn't found and the second argument is not zero create a
1970 * new buffer. */
1971 if (buf == NULL
1972 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001973 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001974 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001975 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 && !error)
1977 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1978
1979 if (buf != NULL)
1980 rettv->vval.v_number = buf->b_fnum;
1981 else
1982 rettv->vval.v_number = -1;
1983}
1984
1985 static void
1986buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1987{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988 win_T *wp;
1989 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001990 buf_T *buf;
1991
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001992 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001993 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001994 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001995 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996 {
1997 ++winnr;
1998 if (wp->w_buffer == buf)
1999 break;
2000 }
2001 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002 --emsg_off;
2003}
2004
2005/*
2006 * "bufwinid(nr)" function
2007 */
2008 static void
2009f_bufwinid(typval_T *argvars, typval_T *rettv)
2010{
2011 buf_win_common(argvars, rettv, FALSE);
2012}
2013
2014/*
2015 * "bufwinnr(nr)" function
2016 */
2017 static void
2018f_bufwinnr(typval_T *argvars, typval_T *rettv)
2019{
2020 buf_win_common(argvars, rettv, TRUE);
2021}
2022
2023/*
2024 * "byte2line(byte)" function
2025 */
2026 static void
2027f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2028{
2029#ifndef FEAT_BYTEOFF
2030 rettv->vval.v_number = -1;
2031#else
2032 long boff = 0;
2033
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002034 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035 if (boff < 0)
2036 rettv->vval.v_number = -1;
2037 else
2038 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2039 (linenr_T)0, &boff);
2040#endif
2041}
2042
2043 static void
2044byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2045{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002046 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002047 char_u *str;
2048 varnumber_T idx;
2049
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002050 str = tv_get_string_chk(&argvars[0]);
2051 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052 rettv->vval.v_number = -1;
2053 if (str == NULL || idx < 0)
2054 return;
2055
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002056 t = str;
2057 for ( ; idx > 0; idx--)
2058 {
2059 if (*t == NUL) /* EOL reached */
2060 return;
2061 if (enc_utf8 && comp)
2062 t += utf_ptr2len(t);
2063 else
2064 t += (*mb_ptr2len)(t);
2065 }
2066 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002067}
2068
2069/*
2070 * "byteidx()" function
2071 */
2072 static void
2073f_byteidx(typval_T *argvars, typval_T *rettv)
2074{
2075 byteidx(argvars, rettv, FALSE);
2076}
2077
2078/*
2079 * "byteidxcomp()" function
2080 */
2081 static void
2082f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2083{
2084 byteidx(argvars, rettv, TRUE);
2085}
2086
2087/*
2088 * "call(func, arglist [, dict])" function
2089 */
2090 static void
2091f_call(typval_T *argvars, typval_T *rettv)
2092{
2093 char_u *func;
2094 partial_T *partial = NULL;
2095 dict_T *selfdict = NULL;
2096
2097 if (argvars[1].v_type != VAR_LIST)
2098 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002099 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002100 return;
2101 }
2102 if (argvars[1].vval.v_list == NULL)
2103 return;
2104
2105 if (argvars[0].v_type == VAR_FUNC)
2106 func = argvars[0].vval.v_string;
2107 else if (argvars[0].v_type == VAR_PARTIAL)
2108 {
2109 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002110 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002111 }
2112 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002113 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002114 if (*func == NUL)
2115 return; /* type error or empty name */
2116
2117 if (argvars[2].v_type != VAR_UNKNOWN)
2118 {
2119 if (argvars[2].v_type != VAR_DICT)
2120 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002121 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 return;
2123 }
2124 selfdict = argvars[2].vval.v_dict;
2125 }
2126
2127 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2128}
2129
2130#ifdef FEAT_FLOAT
2131/*
2132 * "ceil({float})" function
2133 */
2134 static void
2135f_ceil(typval_T *argvars, typval_T *rettv)
2136{
2137 float_T f = 0.0;
2138
2139 rettv->v_type = VAR_FLOAT;
2140 if (get_float_arg(argvars, &f) == OK)
2141 rettv->vval.v_float = ceil(f);
2142 else
2143 rettv->vval.v_float = 0.0;
2144}
2145#endif
2146
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147/*
2148 * "changenr()" function
2149 */
2150 static void
2151f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2152{
2153 rettv->vval.v_number = curbuf->b_u_seq_cur;
2154}
2155
2156/*
2157 * "char2nr(string)" function
2158 */
2159 static void
2160f_char2nr(typval_T *argvars, typval_T *rettv)
2161{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162 if (has_mbyte)
2163 {
2164 int utf8 = 0;
2165
2166 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002167 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002168
2169 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002170 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002172 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173 }
2174 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002175 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176}
2177
2178/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002179 * "chdir(dir)" function
2180 */
2181 static void
2182f_chdir(typval_T *argvars, typval_T *rettv)
2183{
2184 char_u *cwd;
2185 cdscope_T scope = CDSCOPE_GLOBAL;
2186
2187 rettv->v_type = VAR_STRING;
2188 rettv->vval.v_string = NULL;
2189
2190 if (argvars[0].v_type != VAR_STRING)
2191 return;
2192
2193 // Return the current directory
2194 cwd = alloc(MAXPATHL);
2195 if (cwd != NULL)
2196 {
2197 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2198 {
2199#ifdef BACKSLASH_IN_FILENAME
2200 slash_adjust(cwd);
2201#endif
2202 rettv->vval.v_string = vim_strsave(cwd);
2203 }
2204 vim_free(cwd);
2205 }
2206
2207 if (curwin->w_localdir != NULL)
2208 scope = CDSCOPE_WINDOW;
2209 else if (curtab->tp_localdir != NULL)
2210 scope = CDSCOPE_TABPAGE;
2211
2212 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2213 // Directory change failed
2214 VIM_CLEAR(rettv->vval.v_string);
2215}
2216
2217/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002218 * "cindent(lnum)" function
2219 */
2220 static void
2221f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2222{
2223#ifdef FEAT_CINDENT
2224 pos_T pos;
2225 linenr_T lnum;
2226
2227 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002228 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002229 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2230 {
2231 curwin->w_cursor.lnum = lnum;
2232 rettv->vval.v_number = get_c_indent();
2233 curwin->w_cursor = pos;
2234 }
2235 else
2236#endif
2237 rettv->vval.v_number = -1;
2238}
2239
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002240 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002241get_optional_window(typval_T *argvars, int idx)
2242{
2243 win_T *win = curwin;
2244
2245 if (argvars[idx].v_type != VAR_UNKNOWN)
2246 {
2247 win = find_win_by_nr_or_id(&argvars[idx]);
2248 if (win == NULL)
2249 {
2250 emsg(_(e_invalwindow));
2251 return NULL;
2252 }
2253 }
2254 return win;
2255}
2256
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002257/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002258 * "col(string)" function
2259 */
2260 static void
2261f_col(typval_T *argvars, typval_T *rettv)
2262{
2263 colnr_T col = 0;
2264 pos_T *fp;
2265 int fnum = curbuf->b_fnum;
2266
2267 fp = var2fpos(&argvars[0], FALSE, &fnum);
2268 if (fp != NULL && fnum == curbuf->b_fnum)
2269 {
2270 if (fp->col == MAXCOL)
2271 {
2272 /* '> can be MAXCOL, get the length of the line then */
2273 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2274 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2275 else
2276 col = MAXCOL;
2277 }
2278 else
2279 {
2280 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002281 /* col(".") when the cursor is on the NUL at the end of the line
2282 * because of "coladd" can be seen as an extra column. */
2283 if (virtual_active() && fp == &curwin->w_cursor)
2284 {
2285 char_u *p = ml_get_cursor();
2286
2287 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2288 curwin->w_virtcol - curwin->w_cursor.coladd))
2289 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290 int l;
2291
2292 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2293 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002294 }
2295 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296 }
2297 }
2298 rettv->vval.v_number = col;
2299}
2300
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301/*
2302 * "confirm(message, buttons[, default [, type]])" function
2303 */
2304 static void
2305f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2306{
2307#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2308 char_u *message;
2309 char_u *buttons = NULL;
2310 char_u buf[NUMBUFLEN];
2311 char_u buf2[NUMBUFLEN];
2312 int def = 1;
2313 int type = VIM_GENERIC;
2314 char_u *typestr;
2315 int error = FALSE;
2316
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002317 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002318 if (message == NULL)
2319 error = TRUE;
2320 if (argvars[1].v_type != VAR_UNKNOWN)
2321 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002322 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002323 if (buttons == NULL)
2324 error = TRUE;
2325 if (argvars[2].v_type != VAR_UNKNOWN)
2326 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002327 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002328 if (argvars[3].v_type != VAR_UNKNOWN)
2329 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002330 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002331 if (typestr == NULL)
2332 error = TRUE;
2333 else
2334 {
2335 switch (TOUPPER_ASC(*typestr))
2336 {
2337 case 'E': type = VIM_ERROR; break;
2338 case 'Q': type = VIM_QUESTION; break;
2339 case 'I': type = VIM_INFO; break;
2340 case 'W': type = VIM_WARNING; break;
2341 case 'G': type = VIM_GENERIC; break;
2342 }
2343 }
2344 }
2345 }
2346 }
2347
2348 if (buttons == NULL || *buttons == NUL)
2349 buttons = (char_u *)_("&Ok");
2350
2351 if (!error)
2352 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2353 def, NULL, FALSE);
2354#endif
2355}
2356
2357/*
2358 * "copy()" function
2359 */
2360 static void
2361f_copy(typval_T *argvars, typval_T *rettv)
2362{
2363 item_copy(&argvars[0], rettv, FALSE, 0);
2364}
2365
2366#ifdef FEAT_FLOAT
2367/*
2368 * "cos()" function
2369 */
2370 static void
2371f_cos(typval_T *argvars, typval_T *rettv)
2372{
2373 float_T f = 0.0;
2374
2375 rettv->v_type = VAR_FLOAT;
2376 if (get_float_arg(argvars, &f) == OK)
2377 rettv->vval.v_float = cos(f);
2378 else
2379 rettv->vval.v_float = 0.0;
2380}
2381
2382/*
2383 * "cosh()" function
2384 */
2385 static void
2386f_cosh(typval_T *argvars, typval_T *rettv)
2387{
2388 float_T f = 0.0;
2389
2390 rettv->v_type = VAR_FLOAT;
2391 if (get_float_arg(argvars, &f) == OK)
2392 rettv->vval.v_float = cosh(f);
2393 else
2394 rettv->vval.v_float = 0.0;
2395}
2396#endif
2397
2398/*
2399 * "count()" function
2400 */
2401 static void
2402f_count(typval_T *argvars, typval_T *rettv)
2403{
2404 long n = 0;
2405 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002406 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002407
Bram Moolenaar9966b212017-07-28 16:46:57 +02002408 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002409 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002410
2411 if (argvars[0].v_type == VAR_STRING)
2412 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002413 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002414 char_u *p = argvars[0].vval.v_string;
2415 char_u *next;
2416
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002417 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002418 {
2419 if (ic)
2420 {
2421 size_t len = STRLEN(expr);
2422
2423 while (*p != NUL)
2424 {
2425 if (MB_STRNICMP(p, expr, len) == 0)
2426 {
2427 ++n;
2428 p += len;
2429 }
2430 else
2431 MB_PTR_ADV(p);
2432 }
2433 }
2434 else
2435 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2436 != NULL)
2437 {
2438 ++n;
2439 p = next + STRLEN(expr);
2440 }
2441 }
2442
2443 }
2444 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002445 {
2446 listitem_T *li;
2447 list_T *l;
2448 long idx;
2449
2450 if ((l = argvars[0].vval.v_list) != NULL)
2451 {
2452 li = l->lv_first;
2453 if (argvars[2].v_type != VAR_UNKNOWN)
2454 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002455 if (argvars[3].v_type != VAR_UNKNOWN)
2456 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002457 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458 if (!error)
2459 {
2460 li = list_find(l, idx);
2461 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002462 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002463 }
2464 }
2465 if (error)
2466 li = NULL;
2467 }
2468
2469 for ( ; li != NULL; li = li->li_next)
2470 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2471 ++n;
2472 }
2473 }
2474 else if (argvars[0].v_type == VAR_DICT)
2475 {
2476 int todo;
2477 dict_T *d;
2478 hashitem_T *hi;
2479
2480 if ((d = argvars[0].vval.v_dict) != NULL)
2481 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002482 if (argvars[2].v_type != VAR_UNKNOWN)
2483 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002484 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002485 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002486 }
2487
2488 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2489 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2490 {
2491 if (!HASHITEM_EMPTY(hi))
2492 {
2493 --todo;
2494 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2495 ++n;
2496 }
2497 }
2498 }
2499 }
2500 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002501 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002502 rettv->vval.v_number = n;
2503}
2504
2505/*
2506 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2507 *
2508 * Checks the existence of a cscope connection.
2509 */
2510 static void
2511f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2512{
2513#ifdef FEAT_CSCOPE
2514 int num = 0;
2515 char_u *dbpath = NULL;
2516 char_u *prepend = NULL;
2517 char_u buf[NUMBUFLEN];
2518
2519 if (argvars[0].v_type != VAR_UNKNOWN
2520 && argvars[1].v_type != VAR_UNKNOWN)
2521 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002522 num = (int)tv_get_number(&argvars[0]);
2523 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002524 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002525 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 }
2527
2528 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2529#endif
2530}
2531
2532/*
2533 * "cursor(lnum, col)" function, or
2534 * "cursor(list)"
2535 *
2536 * Moves the cursor to the specified line and column.
2537 * Returns 0 when the position could be set, -1 otherwise.
2538 */
2539 static void
2540f_cursor(typval_T *argvars, typval_T *rettv)
2541{
2542 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002544 int set_curswant = TRUE;
2545
2546 rettv->vval.v_number = -1;
2547 if (argvars[1].v_type == VAR_UNKNOWN)
2548 {
2549 pos_T pos;
2550 colnr_T curswant = -1;
2551
2552 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2553 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002554 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002555 return;
2556 }
2557 line = pos.lnum;
2558 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002559 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002560 if (curswant >= 0)
2561 {
2562 curwin->w_curswant = curswant - 1;
2563 set_curswant = FALSE;
2564 }
2565 }
2566 else
2567 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002568 line = tv_get_lnum(argvars);
2569 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002570 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002571 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002572 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002573 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 return; /* type error; errmsg already given */
2575 if (line > 0)
2576 curwin->w_cursor.lnum = line;
2577 if (col > 0)
2578 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002579 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002580
2581 /* Make sure the cursor is in a valid position. */
2582 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002583 /* Correct cursor for multi-byte character. */
2584 if (has_mbyte)
2585 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002586
2587 curwin->w_set_curswant = set_curswant;
2588 rettv->vval.v_number = 0;
2589}
2590
Bram Moolenaar4f974752019-02-17 17:44:42 +01002591#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002592/*
2593 * "debugbreak()" function
2594 */
2595 static void
2596f_debugbreak(typval_T *argvars, typval_T *rettv)
2597{
2598 int pid;
2599
2600 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002601 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002602 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002603 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002604 else
2605 {
2606 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2607
2608 if (hProcess != NULL)
2609 {
2610 DebugBreakProcess(hProcess);
2611 CloseHandle(hProcess);
2612 rettv->vval.v_number = OK;
2613 }
2614 }
2615}
2616#endif
2617
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618/*
2619 * "deepcopy()" function
2620 */
2621 static void
2622f_deepcopy(typval_T *argvars, typval_T *rettv)
2623{
2624 int noref = 0;
2625 int copyID;
2626
2627 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002628 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002629 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002630 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002631 else
2632 {
2633 copyID = get_copyID();
2634 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2635 }
2636}
2637
2638/*
2639 * "delete()" function
2640 */
2641 static void
2642f_delete(typval_T *argvars, typval_T *rettv)
2643{
2644 char_u nbuf[NUMBUFLEN];
2645 char_u *name;
2646 char_u *flags;
2647
2648 rettv->vval.v_number = -1;
2649 if (check_restricted() || check_secure())
2650 return;
2651
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002652 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 if (name == NULL || *name == NUL)
2654 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002655 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 return;
2657 }
2658
2659 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002660 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002661 else
2662 flags = (char_u *)"";
2663
2664 if (*flags == NUL)
2665 /* delete a file */
2666 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2667 else if (STRCMP(flags, "d") == 0)
2668 /* delete an empty directory */
2669 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2670 else if (STRCMP(flags, "rf") == 0)
2671 /* delete a directory recursively */
2672 rettv->vval.v_number = delete_recursive(name);
2673 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002674 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675}
2676
2677/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002678 * "deletebufline()" function
2679 */
2680 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002681f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002682{
2683 buf_T *buf;
2684 linenr_T first, last;
2685 linenr_T lnum;
2686 long count;
2687 int is_curbuf;
2688 buf_T *curbuf_save = NULL;
2689 win_T *curwin_save = NULL;
2690 tabpage_T *tp;
2691 win_T *wp;
2692
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002693 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002694 if (buf == NULL)
2695 {
2696 rettv->vval.v_number = 1; /* FAIL */
2697 return;
2698 }
2699 is_curbuf = buf == curbuf;
2700
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002701 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002702 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002703 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002704 else
2705 last = first;
2706
2707 if (buf->b_ml.ml_mfp == NULL || first < 1
2708 || first > buf->b_ml.ml_line_count || last < first)
2709 {
2710 rettv->vval.v_number = 1; /* FAIL */
2711 return;
2712 }
2713
2714 if (!is_curbuf)
2715 {
2716 curbuf_save = curbuf;
2717 curwin_save = curwin;
2718 curbuf = buf;
2719 find_win_for_curbuf();
2720 }
2721 if (last > curbuf->b_ml.ml_line_count)
2722 last = curbuf->b_ml.ml_line_count;
2723 count = last - first + 1;
2724
2725 // When coming here from Insert mode, sync undo, so that this can be
2726 // undone separately from what was previously inserted.
2727 if (u_sync_once == 2)
2728 {
2729 u_sync_once = 1; // notify that u_sync() was called
2730 u_sync(TRUE);
2731 }
2732
2733 if (u_save(first - 1, last + 1) == FAIL)
2734 {
2735 rettv->vval.v_number = 1; /* FAIL */
2736 return;
2737 }
2738
2739 for (lnum = first; lnum <= last; ++lnum)
2740 ml_delete(first, TRUE);
2741
2742 FOR_ALL_TAB_WINDOWS(tp, wp)
2743 if (wp->w_buffer == buf)
2744 {
2745 if (wp->w_cursor.lnum > last)
2746 wp->w_cursor.lnum -= count;
2747 else if (wp->w_cursor.lnum> first)
2748 wp->w_cursor.lnum = first;
2749 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2750 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2751 }
2752 check_cursor_col();
2753 deleted_lines_mark(first, count);
2754
2755 if (!is_curbuf)
2756 {
2757 curbuf = curbuf_save;
2758 curwin = curwin_save;
2759 }
2760}
2761
2762/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 * "did_filetype()" function
2764 */
2765 static void
2766f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2767{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002768 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002769}
2770
2771/*
2772 * "diff_filler()" function
2773 */
2774 static void
2775f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2776{
2777#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002778 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002779#endif
2780}
2781
2782/*
2783 * "diff_hlID()" function
2784 */
2785 static void
2786f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2787{
2788#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002789 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002790 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002791 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792 static int fnum = 0;
2793 static int change_start = 0;
2794 static int change_end = 0;
2795 static hlf_T hlID = (hlf_T)0;
2796 int filler_lines;
2797 int col;
2798
2799 if (lnum < 0) /* ignore type error in {lnum} arg */
2800 lnum = 0;
2801 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002802 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002803 || fnum != curbuf->b_fnum)
2804 {
2805 /* New line, buffer, change: need to get the values. */
2806 filler_lines = diff_check(curwin, lnum);
2807 if (filler_lines < 0)
2808 {
2809 if (filler_lines == -1)
2810 {
2811 change_start = MAXCOL;
2812 change_end = -1;
2813 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2814 hlID = HLF_ADD; /* added line */
2815 else
2816 hlID = HLF_CHD; /* changed line */
2817 }
2818 else
2819 hlID = HLF_ADD; /* added line */
2820 }
2821 else
2822 hlID = (hlf_T)0;
2823 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002824 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002825 fnum = curbuf->b_fnum;
2826 }
2827
2828 if (hlID == HLF_CHD || hlID == HLF_TXD)
2829 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002830 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002831 if (col >= change_start && col <= change_end)
2832 hlID = HLF_TXD; /* changed text */
2833 else
2834 hlID = HLF_CHD; /* changed line */
2835 }
2836 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2837#endif
2838}
2839
2840/*
2841 * "empty({expr})" function
2842 */
2843 static void
2844f_empty(typval_T *argvars, typval_T *rettv)
2845{
2846 int n = FALSE;
2847
2848 switch (argvars[0].v_type)
2849 {
2850 case VAR_STRING:
2851 case VAR_FUNC:
2852 n = argvars[0].vval.v_string == NULL
2853 || *argvars[0].vval.v_string == NUL;
2854 break;
2855 case VAR_PARTIAL:
2856 n = FALSE;
2857 break;
2858 case VAR_NUMBER:
2859 n = argvars[0].vval.v_number == 0;
2860 break;
2861 case VAR_FLOAT:
2862#ifdef FEAT_FLOAT
2863 n = argvars[0].vval.v_float == 0.0;
2864 break;
2865#endif
2866 case VAR_LIST:
2867 n = argvars[0].vval.v_list == NULL
2868 || argvars[0].vval.v_list->lv_first == NULL;
2869 break;
2870 case VAR_DICT:
2871 n = argvars[0].vval.v_dict == NULL
2872 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2873 break;
2874 case VAR_SPECIAL:
2875 n = argvars[0].vval.v_number != VVAL_TRUE;
2876 break;
2877
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002878 case VAR_BLOB:
2879 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002880 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2881 break;
2882
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002883 case VAR_JOB:
2884#ifdef FEAT_JOB_CHANNEL
2885 n = argvars[0].vval.v_job == NULL
2886 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2887 break;
2888#endif
2889 case VAR_CHANNEL:
2890#ifdef FEAT_JOB_CHANNEL
2891 n = argvars[0].vval.v_channel == NULL
2892 || !channel_is_open(argvars[0].vval.v_channel);
2893 break;
2894#endif
2895 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002896 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002897 n = TRUE;
2898 break;
2899 }
2900
2901 rettv->vval.v_number = n;
2902}
2903
2904/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002905 * "environ()" function
2906 */
2907 static void
2908f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2909{
2910#if !defined(AMIGA)
2911 int i = 0;
2912 char_u *entry, *value;
2913# ifdef MSWIN
2914 extern wchar_t **_wenviron;
2915# else
2916 extern char **environ;
2917# endif
2918
2919 if (rettv_dict_alloc(rettv) != OK)
2920 return;
2921
2922# ifdef MSWIN
2923 if (*_wenviron == NULL)
2924 return;
2925# else
2926 if (*environ == NULL)
2927 return;
2928# endif
2929
2930 for (i = 0; ; ++i)
2931 {
2932# ifdef MSWIN
2933 short_u *p;
2934
2935 if ((p = (short_u *)_wenviron[i]) == NULL)
2936 return;
2937 entry = utf16_to_enc(p, NULL);
2938# else
2939 if ((entry = (char_u *)environ[i]) == NULL)
2940 return;
2941 entry = vim_strsave(entry);
2942# endif
2943 if (entry == NULL) // out of memory
2944 return;
2945 if ((value = vim_strchr(entry, '=')) == NULL)
2946 {
2947 vim_free(entry);
2948 continue;
2949 }
2950 *value++ = NUL;
2951 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2952 vim_free(entry);
2953 }
2954#endif
2955}
2956
2957/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002958 * "escape({string}, {chars})" function
2959 */
2960 static void
2961f_escape(typval_T *argvars, typval_T *rettv)
2962{
2963 char_u buf[NUMBUFLEN];
2964
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002965 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2966 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002967 rettv->v_type = VAR_STRING;
2968}
2969
2970/*
2971 * "eval()" function
2972 */
2973 static void
2974f_eval(typval_T *argvars, typval_T *rettv)
2975{
2976 char_u *s, *p;
2977
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002978 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002979 if (s != NULL)
2980 s = skipwhite(s);
2981
2982 p = s;
2983 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2984 {
2985 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002986 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002987 need_clr_eos = FALSE;
2988 rettv->v_type = VAR_NUMBER;
2989 rettv->vval.v_number = 0;
2990 }
2991 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002992 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002993}
2994
2995/*
2996 * "eventhandler()" function
2997 */
2998 static void
2999f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3000{
3001 rettv->vval.v_number = vgetc_busy;
3002}
3003
3004/*
3005 * "executable()" function
3006 */
3007 static void
3008f_executable(typval_T *argvars, typval_T *rettv)
3009{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003010 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003011
3012 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003013 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003014}
3015
3016static garray_T redir_execute_ga;
3017
3018/*
3019 * Append "value[value_len]" to the execute() output.
3020 */
3021 void
3022execute_redir_str(char_u *value, int value_len)
3023{
3024 int len;
3025
3026 if (value_len == -1)
3027 len = (int)STRLEN(value); /* Append the entire string */
3028 else
3029 len = value_len; /* Append only "value_len" characters */
3030 if (ga_grow(&redir_execute_ga, len) == OK)
3031 {
3032 mch_memmove((char *)redir_execute_ga.ga_data
3033 + redir_execute_ga.ga_len, value, len);
3034 redir_execute_ga.ga_len += len;
3035 }
3036}
3037
3038/*
3039 * Get next line from a list.
3040 * Called by do_cmdline() to get the next line.
3041 * Returns allocated string, or NULL for end of function.
3042 */
3043
3044 static char_u *
3045get_list_line(
3046 int c UNUSED,
3047 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003048 int indent UNUSED,
3049 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003050{
3051 listitem_T **p = (listitem_T **)cookie;
3052 listitem_T *item = *p;
3053 char_u buf[NUMBUFLEN];
3054 char_u *s;
3055
3056 if (item == NULL)
3057 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003058 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059 *p = item->li_next;
3060 return s == NULL ? NULL : vim_strsave(s);
3061}
3062
3063/*
3064 * "execute()" function
3065 */
3066 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003067execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003068{
3069 char_u *cmd = NULL;
3070 list_T *list = NULL;
3071 int save_msg_silent = msg_silent;
3072 int save_emsg_silent = emsg_silent;
3073 int save_emsg_noredir = emsg_noredir;
3074 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003075 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003077 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003078 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079
3080 rettv->vval.v_string = NULL;
3081 rettv->v_type = VAR_STRING;
3082
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003083 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003084 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003085 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003086 if (list == NULL || list->lv_first == NULL)
3087 /* empty list, no commands, empty output */
3088 return;
3089 ++list->lv_refcount;
3090 }
3091 else
3092 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003093 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003094 if (cmd == NULL)
3095 return;
3096 }
3097
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003098 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 {
3100 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003101 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102
3103 if (s == NULL)
3104 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003105 if (*s == NUL)
3106 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003107 if (STRNCMP(s, "silent", 6) == 0)
3108 ++msg_silent;
3109 if (STRCMP(s, "silent!") == 0)
3110 {
3111 emsg_silent = TRUE;
3112 emsg_noredir = TRUE;
3113 }
3114 }
3115 else
3116 ++msg_silent;
3117
3118 if (redir_execute)
3119 save_ga = redir_execute_ga;
3120 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3121 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003122 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003123 if (!echo_output)
3124 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003125
3126 if (cmd != NULL)
3127 do_cmdline_cmd(cmd);
3128 else
3129 {
3130 listitem_T *item = list->lv_first;
3131
3132 do_cmdline(NULL, get_list_line, (void *)&item,
3133 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3134 --list->lv_refcount;
3135 }
3136
Bram Moolenaard297f352017-01-29 20:31:21 +01003137 /* Need to append a NUL to the result. */
3138 if (ga_grow(&redir_execute_ga, 1) == OK)
3139 {
3140 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3141 rettv->vval.v_string = redir_execute_ga.ga_data;
3142 }
3143 else
3144 {
3145 ga_clear(&redir_execute_ga);
3146 rettv->vval.v_string = NULL;
3147 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003148 msg_silent = save_msg_silent;
3149 emsg_silent = save_emsg_silent;
3150 emsg_noredir = save_emsg_noredir;
3151
3152 redir_execute = save_redir_execute;
3153 if (redir_execute)
3154 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003155 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003156
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003157 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003158 if (echo_output)
3159 // When not working silently: put it in column zero. A following
3160 // "echon" will overwrite the message, unavoidably.
3161 msg_col = 0;
3162 else
3163 // When working silently: Put it back where it was, since nothing
3164 // should have been written.
3165 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003166}
3167
3168/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003169 * "execute()" function
3170 */
3171 static void
3172f_execute(typval_T *argvars, typval_T *rettv)
3173{
3174 execute_common(argvars, rettv, 0);
3175}
3176
3177/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003178 * "exepath()" function
3179 */
3180 static void
3181f_exepath(typval_T *argvars, typval_T *rettv)
3182{
3183 char_u *p = NULL;
3184
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003185 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003186 rettv->v_type = VAR_STRING;
3187 rettv->vval.v_string = p;
3188}
3189
3190/*
3191 * "exists()" function
3192 */
3193 static void
3194f_exists(typval_T *argvars, typval_T *rettv)
3195{
3196 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003197 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003198
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003199 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003200 if (*p == '$') /* environment variable */
3201 {
3202 /* first try "normal" environment variables (fast) */
3203 if (mch_getenv(p + 1) != NULL)
3204 n = TRUE;
3205 else
3206 {
3207 /* try expanding things like $VIM and ${HOME} */
3208 p = expand_env_save(p);
3209 if (p != NULL && *p != '$')
3210 n = TRUE;
3211 vim_free(p);
3212 }
3213 }
3214 else if (*p == '&' || *p == '+') /* option */
3215 {
3216 n = (get_option_tv(&p, NULL, TRUE) == OK);
3217 if (*skipwhite(p) != NUL)
3218 n = FALSE; /* trailing garbage */
3219 }
3220 else if (*p == '*') /* internal or user defined function */
3221 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003222 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003223 }
3224 else if (*p == ':')
3225 {
3226 n = cmd_exists(p + 1);
3227 }
3228 else if (*p == '#')
3229 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230 if (p[1] == '#')
3231 n = autocmd_supported(p + 2);
3232 else
3233 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003234 }
3235 else /* internal variable */
3236 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003237 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 }
3239
3240 rettv->vval.v_number = n;
3241}
3242
3243#ifdef FEAT_FLOAT
3244/*
3245 * "exp()" function
3246 */
3247 static void
3248f_exp(typval_T *argvars, typval_T *rettv)
3249{
3250 float_T f = 0.0;
3251
3252 rettv->v_type = VAR_FLOAT;
3253 if (get_float_arg(argvars, &f) == OK)
3254 rettv->vval.v_float = exp(f);
3255 else
3256 rettv->vval.v_float = 0.0;
3257}
3258#endif
3259
3260/*
3261 * "expand()" function
3262 */
3263 static void
3264f_expand(typval_T *argvars, typval_T *rettv)
3265{
3266 char_u *s;
3267 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003268 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003269 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3270 expand_T xpc;
3271 int error = FALSE;
3272 char_u *result;
3273
3274 rettv->v_type = VAR_STRING;
3275 if (argvars[1].v_type != VAR_UNKNOWN
3276 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003277 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003278 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003279 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003280
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003281 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003282 if (*s == '%' || *s == '#' || *s == '<')
3283 {
3284 ++emsg_off;
3285 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3286 --emsg_off;
3287 if (rettv->v_type == VAR_LIST)
3288 {
3289 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3290 list_append_string(rettv->vval.v_list, result, -1);
3291 else
3292 vim_free(result);
3293 }
3294 else
3295 rettv->vval.v_string = result;
3296 }
3297 else
3298 {
3299 /* When the optional second argument is non-zero, don't remove matches
3300 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3301 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003302 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003303 options |= WILD_KEEP_ALL;
3304 if (!error)
3305 {
3306 ExpandInit(&xpc);
3307 xpc.xp_context = EXPAND_FILES;
3308 if (p_wic)
3309 options += WILD_ICASE;
3310 if (rettv->v_type == VAR_STRING)
3311 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3312 options, WILD_ALL);
3313 else if (rettv_list_alloc(rettv) != FAIL)
3314 {
3315 int i;
3316
3317 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3318 for (i = 0; i < xpc.xp_numfiles; i++)
3319 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3320 ExpandCleanup(&xpc);
3321 }
3322 }
3323 else
3324 rettv->vval.v_string = NULL;
3325 }
3326}
3327
3328/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003329 * "expandcmd()" function
3330 * Expand all the special characters in a command string.
3331 */
3332 static void
3333f_expandcmd(typval_T *argvars, typval_T *rettv)
3334{
3335 exarg_T eap;
3336 char_u *cmdstr;
3337 char *errormsg = NULL;
3338
3339 rettv->v_type = VAR_STRING;
3340 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3341
3342 memset(&eap, 0, sizeof(eap));
3343 eap.cmd = cmdstr;
3344 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003345 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003346 eap.usefilter = FALSE;
3347 eap.nextcmd = NULL;
3348 eap.cmdidx = CMD_USER;
3349
3350 expand_filename(&eap, &cmdstr, &errormsg);
3351 if (errormsg != NULL && *errormsg != NUL)
3352 emsg(errormsg);
3353
3354 rettv->vval.v_string = cmdstr;
3355}
3356
3357/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003358 * "extend(list, list [, idx])" function
3359 * "extend(dict, dict [, action])" function
3360 */
3361 static void
3362f_extend(typval_T *argvars, typval_T *rettv)
3363{
3364 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3365
3366 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3367 {
3368 list_T *l1, *l2;
3369 listitem_T *item;
3370 long before;
3371 int error = FALSE;
3372
3373 l1 = argvars[0].vval.v_list;
3374 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003375 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376 && l2 != NULL)
3377 {
3378 if (argvars[2].v_type != VAR_UNKNOWN)
3379 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003380 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003381 if (error)
3382 return; /* type error; errmsg already given */
3383
3384 if (before == l1->lv_len)
3385 item = NULL;
3386 else
3387 {
3388 item = list_find(l1, before);
3389 if (item == NULL)
3390 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003391 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 return;
3393 }
3394 }
3395 }
3396 else
3397 item = NULL;
3398 list_extend(l1, l2, item);
3399
3400 copy_tv(&argvars[0], rettv);
3401 }
3402 }
3403 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3404 {
3405 dict_T *d1, *d2;
3406 char_u *action;
3407 int i;
3408
3409 d1 = argvars[0].vval.v_dict;
3410 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003411 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003412 && d2 != NULL)
3413 {
3414 /* Check the third argument. */
3415 if (argvars[2].v_type != VAR_UNKNOWN)
3416 {
3417 static char *(av[]) = {"keep", "force", "error"};
3418
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003419 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003420 if (action == NULL)
3421 return; /* type error; errmsg already given */
3422 for (i = 0; i < 3; ++i)
3423 if (STRCMP(action, av[i]) == 0)
3424 break;
3425 if (i == 3)
3426 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003427 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428 return;
3429 }
3430 }
3431 else
3432 action = (char_u *)"force";
3433
3434 dict_extend(d1, d2, action);
3435
3436 copy_tv(&argvars[0], rettv);
3437 }
3438 }
3439 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003440 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003441}
3442
3443/*
3444 * "feedkeys()" function
3445 */
3446 static void
3447f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3448{
3449 int remap = TRUE;
3450 int insert = FALSE;
3451 char_u *keys, *flags;
3452 char_u nbuf[NUMBUFLEN];
3453 int typed = FALSE;
3454 int execute = FALSE;
3455 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003456 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457 char_u *keys_esc;
3458
3459 /* This is not allowed in the sandbox. If the commands would still be
3460 * executed in the sandbox it would be OK, but it probably happens later,
3461 * when "sandbox" is no longer set. */
3462 if (check_secure())
3463 return;
3464
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003465 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003466
3467 if (argvars[1].v_type != VAR_UNKNOWN)
3468 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003469 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470 for ( ; *flags != NUL; ++flags)
3471 {
3472 switch (*flags)
3473 {
3474 case 'n': remap = FALSE; break;
3475 case 'm': remap = TRUE; break;
3476 case 't': typed = TRUE; break;
3477 case 'i': insert = TRUE; break;
3478 case 'x': execute = TRUE; break;
3479 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003480 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003481 }
3482 }
3483 }
3484
3485 if (*keys != NUL || execute)
3486 {
3487 /* Need to escape K_SPECIAL and CSI before putting the string in the
3488 * typeahead buffer. */
3489 keys_esc = vim_strsave_escape_csi(keys);
3490 if (keys_esc != NULL)
3491 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003492 if (lowlevel)
3493 {
3494#ifdef USE_INPUT_BUF
3495 add_to_input_buf(keys, (int)STRLEN(keys));
3496#else
3497 emsg(_("E980: lowlevel input not supported"));
3498#endif
3499 }
3500 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003501 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003502 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003504 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003505#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003506 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003507#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003508 )
3509 typebuf_was_filled = TRUE;
3510 }
3511 vim_free(keys_esc);
3512
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003513 if (execute)
3514 {
3515 int save_msg_scroll = msg_scroll;
3516
3517 /* Avoid a 1 second delay when the keys start Insert mode. */
3518 msg_scroll = FALSE;
3519
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003520 if (!dangerous)
3521 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003522 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003523 if (!dangerous)
3524 --ex_normal_busy;
3525
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003526 msg_scroll |= save_msg_scroll;
3527 }
3528 }
3529 }
3530}
3531
3532/*
3533 * "filereadable()" function
3534 */
3535 static void
3536f_filereadable(typval_T *argvars, typval_T *rettv)
3537{
3538 int fd;
3539 char_u *p;
3540 int n;
3541
3542#ifndef O_NONBLOCK
3543# define O_NONBLOCK 0
3544#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003545 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3547 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3548 {
3549 n = TRUE;
3550 close(fd);
3551 }
3552 else
3553 n = FALSE;
3554
3555 rettv->vval.v_number = n;
3556}
3557
3558/*
3559 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3560 * rights to write into.
3561 */
3562 static void
3563f_filewritable(typval_T *argvars, typval_T *rettv)
3564{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003565 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003566}
3567
3568 static void
3569findfilendir(
3570 typval_T *argvars UNUSED,
3571 typval_T *rettv,
3572 int find_what UNUSED)
3573{
3574#ifdef FEAT_SEARCHPATH
3575 char_u *fname;
3576 char_u *fresult = NULL;
3577 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3578 char_u *p;
3579 char_u pathbuf[NUMBUFLEN];
3580 int count = 1;
3581 int first = TRUE;
3582 int error = FALSE;
3583#endif
3584
3585 rettv->vval.v_string = NULL;
3586 rettv->v_type = VAR_STRING;
3587
3588#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003589 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590
3591 if (argvars[1].v_type != VAR_UNKNOWN)
3592 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003593 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003594 if (p == NULL)
3595 error = TRUE;
3596 else
3597 {
3598 if (*p != NUL)
3599 path = p;
3600
3601 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003602 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603 }
3604 }
3605
3606 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3607 error = TRUE;
3608
3609 if (*fname != NUL && !error)
3610 {
3611 do
3612 {
3613 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3614 vim_free(fresult);
3615 fresult = find_file_in_path_option(first ? fname : NULL,
3616 first ? (int)STRLEN(fname) : 0,
3617 0, first, path,
3618 find_what,
3619 curbuf->b_ffname,
3620 find_what == FINDFILE_DIR
3621 ? (char_u *)"" : curbuf->b_p_sua);
3622 first = FALSE;
3623
3624 if (fresult != NULL && rettv->v_type == VAR_LIST)
3625 list_append_string(rettv->vval.v_list, fresult, -1);
3626
3627 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3628 }
3629
3630 if (rettv->v_type == VAR_STRING)
3631 rettv->vval.v_string = fresult;
3632#endif
3633}
3634
3635/*
3636 * "filter()" function
3637 */
3638 static void
3639f_filter(typval_T *argvars, typval_T *rettv)
3640{
3641 filter_map(argvars, rettv, FALSE);
3642}
3643
3644/*
3645 * "finddir({fname}[, {path}[, {count}]])" function
3646 */
3647 static void
3648f_finddir(typval_T *argvars, typval_T *rettv)
3649{
3650 findfilendir(argvars, rettv, FINDFILE_DIR);
3651}
3652
3653/*
3654 * "findfile({fname}[, {path}[, {count}]])" function
3655 */
3656 static void
3657f_findfile(typval_T *argvars, typval_T *rettv)
3658{
3659 findfilendir(argvars, rettv, FINDFILE_FILE);
3660}
3661
3662#ifdef FEAT_FLOAT
3663/*
3664 * "float2nr({float})" function
3665 */
3666 static void
3667f_float2nr(typval_T *argvars, typval_T *rettv)
3668{
3669 float_T f = 0.0;
3670
3671 if (get_float_arg(argvars, &f) == OK)
3672 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003673 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003674 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003675 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003676 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677 else
3678 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003679 }
3680}
3681
3682/*
3683 * "floor({float})" function
3684 */
3685 static void
3686f_floor(typval_T *argvars, typval_T *rettv)
3687{
3688 float_T f = 0.0;
3689
3690 rettv->v_type = VAR_FLOAT;
3691 if (get_float_arg(argvars, &f) == OK)
3692 rettv->vval.v_float = floor(f);
3693 else
3694 rettv->vval.v_float = 0.0;
3695}
3696
3697/*
3698 * "fmod()" function
3699 */
3700 static void
3701f_fmod(typval_T *argvars, typval_T *rettv)
3702{
3703 float_T fx = 0.0, fy = 0.0;
3704
3705 rettv->v_type = VAR_FLOAT;
3706 if (get_float_arg(argvars, &fx) == OK
3707 && get_float_arg(&argvars[1], &fy) == OK)
3708 rettv->vval.v_float = fmod(fx, fy);
3709 else
3710 rettv->vval.v_float = 0.0;
3711}
3712#endif
3713
3714/*
3715 * "fnameescape({string})" function
3716 */
3717 static void
3718f_fnameescape(typval_T *argvars, typval_T *rettv)
3719{
3720 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003721 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722 rettv->v_type = VAR_STRING;
3723}
3724
3725/*
3726 * "fnamemodify({fname}, {mods})" function
3727 */
3728 static void
3729f_fnamemodify(typval_T *argvars, typval_T *rettv)
3730{
3731 char_u *fname;
3732 char_u *mods;
3733 int usedlen = 0;
3734 int len;
3735 char_u *fbuf = NULL;
3736 char_u buf[NUMBUFLEN];
3737
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003738 fname = tv_get_string_chk(&argvars[0]);
3739 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740 if (fname == NULL || mods == NULL)
3741 fname = NULL;
3742 else
3743 {
3744 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003745 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003746 }
3747
3748 rettv->v_type = VAR_STRING;
3749 if (fname == NULL)
3750 rettv->vval.v_string = NULL;
3751 else
3752 rettv->vval.v_string = vim_strnsave(fname, len);
3753 vim_free(fbuf);
3754}
3755
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003756/*
3757 * "foldclosed()" function
3758 */
3759 static void
3760foldclosed_both(
3761 typval_T *argvars UNUSED,
3762 typval_T *rettv,
3763 int end UNUSED)
3764{
3765#ifdef FEAT_FOLDING
3766 linenr_T lnum;
3767 linenr_T first, last;
3768
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003769 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003770 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3771 {
3772 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3773 {
3774 if (end)
3775 rettv->vval.v_number = (varnumber_T)last;
3776 else
3777 rettv->vval.v_number = (varnumber_T)first;
3778 return;
3779 }
3780 }
3781#endif
3782 rettv->vval.v_number = -1;
3783}
3784
3785/*
3786 * "foldclosed()" function
3787 */
3788 static void
3789f_foldclosed(typval_T *argvars, typval_T *rettv)
3790{
3791 foldclosed_both(argvars, rettv, FALSE);
3792}
3793
3794/*
3795 * "foldclosedend()" function
3796 */
3797 static void
3798f_foldclosedend(typval_T *argvars, typval_T *rettv)
3799{
3800 foldclosed_both(argvars, rettv, TRUE);
3801}
3802
3803/*
3804 * "foldlevel()" function
3805 */
3806 static void
3807f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3808{
3809#ifdef FEAT_FOLDING
3810 linenr_T lnum;
3811
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003812 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003813 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3814 rettv->vval.v_number = foldLevel(lnum);
3815#endif
3816}
3817
3818/*
3819 * "foldtext()" function
3820 */
3821 static void
3822f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3823{
3824#ifdef FEAT_FOLDING
3825 linenr_T foldstart;
3826 linenr_T foldend;
3827 char_u *dashes;
3828 linenr_T lnum;
3829 char_u *s;
3830 char_u *r;
3831 int len;
3832 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003833 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834#endif
3835
3836 rettv->v_type = VAR_STRING;
3837 rettv->vval.v_string = NULL;
3838#ifdef FEAT_FOLDING
3839 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3840 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3841 dashes = get_vim_var_str(VV_FOLDDASHES);
3842 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3843 && dashes != NULL)
3844 {
3845 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003846 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003847 if (!linewhite(lnum))
3848 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003849
3850 /* Find interesting text in this line. */
3851 s = skipwhite(ml_get(lnum));
3852 /* skip C comment-start */
3853 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3854 {
3855 s = skipwhite(s + 2);
3856 if (*skipwhite(s) == NUL
3857 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3858 {
3859 s = skipwhite(ml_get(lnum + 1));
3860 if (*s == '*')
3861 s = skipwhite(s + 1);
3862 }
3863 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003864 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003865 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003866 r = alloc(STRLEN(txt)
3867 + STRLEN(dashes) // for %s
3868 + 20 // for %3ld
3869 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003870 if (r != NULL)
3871 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003872 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003873 len = (int)STRLEN(r);
3874 STRCAT(r, s);
3875 /* remove 'foldmarker' and 'commentstring' */
3876 foldtext_cleanup(r + len);
3877 rettv->vval.v_string = r;
3878 }
3879 }
3880#endif
3881}
3882
3883/*
3884 * "foldtextresult(lnum)" function
3885 */
3886 static void
3887f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3888{
3889#ifdef FEAT_FOLDING
3890 linenr_T lnum;
3891 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003892 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003893 foldinfo_T foldinfo;
3894 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003895 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003896#endif
3897
3898 rettv->v_type = VAR_STRING;
3899 rettv->vval.v_string = NULL;
3900#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003901 if (entered)
3902 return; /* reject recursive use */
3903 entered = TRUE;
3904
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003905 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003906 /* treat illegal types and illegal string values for {lnum} the same */
3907 if (lnum < 0)
3908 lnum = 0;
3909 fold_count = foldedCount(curwin, lnum, &foldinfo);
3910 if (fold_count > 0)
3911 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003912 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3913 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003914 if (text == buf)
3915 text = vim_strsave(text);
3916 rettv->vval.v_string = text;
3917 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003918
3919 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920#endif
3921}
3922
3923/*
3924 * "foreground()" function
3925 */
3926 static void
3927f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3928{
3929#ifdef FEAT_GUI
3930 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003931 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003933 return;
3934 }
3935#endif
3936#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003937 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003938#endif
3939}
3940
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003942common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003943{
3944 char_u *s;
3945 char_u *name;
3946 int use_string = FALSE;
3947 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003948 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003949
3950 if (argvars[0].v_type == VAR_FUNC)
3951 {
3952 /* function(MyFunc, [arg], dict) */
3953 s = argvars[0].vval.v_string;
3954 }
3955 else if (argvars[0].v_type == VAR_PARTIAL
3956 && argvars[0].vval.v_partial != NULL)
3957 {
3958 /* function(dict.MyFunc, [arg]) */
3959 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003960 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003961 }
3962 else
3963 {
3964 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003965 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003966 use_string = TRUE;
3967 }
3968
Bram Moolenaar843b8842016-08-21 14:36:15 +02003969 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003970 {
3971 name = s;
3972 trans_name = trans_function_name(&name, FALSE,
3973 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3974 if (*name != NUL)
3975 s = NULL;
3976 }
3977
Bram Moolenaar843b8842016-08-21 14:36:15 +02003978 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3979 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003980 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003981 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003982 else if (trans_name != NULL && (is_funcref
3983 ? find_func(trans_name) == NULL
3984 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003985 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003986 else
3987 {
3988 int dict_idx = 0;
3989 int arg_idx = 0;
3990 list_T *list = NULL;
3991
3992 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3993 {
3994 char sid_buf[25];
3995 int off = *s == 's' ? 2 : 5;
3996
3997 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3998 * also be called from another script. Using trans_function_name()
3999 * would also work, but some plugins depend on the name being
4000 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004001 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004002 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004003 if (name != NULL)
4004 {
4005 STRCPY(name, sid_buf);
4006 STRCAT(name, s + off);
4007 }
4008 }
4009 else
4010 name = vim_strsave(s);
4011
4012 if (argvars[1].v_type != VAR_UNKNOWN)
4013 {
4014 if (argvars[2].v_type != VAR_UNKNOWN)
4015 {
4016 /* function(name, [args], dict) */
4017 arg_idx = 1;
4018 dict_idx = 2;
4019 }
4020 else if (argvars[1].v_type == VAR_DICT)
4021 /* function(name, dict) */
4022 dict_idx = 1;
4023 else
4024 /* function(name, [args]) */
4025 arg_idx = 1;
4026 if (dict_idx > 0)
4027 {
4028 if (argvars[dict_idx].v_type != VAR_DICT)
4029 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004030 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004031 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004032 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004033 }
4034 if (argvars[dict_idx].vval.v_dict == NULL)
4035 dict_idx = 0;
4036 }
4037 if (arg_idx > 0)
4038 {
4039 if (argvars[arg_idx].v_type != VAR_LIST)
4040 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004041 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004042 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004043 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044 }
4045 list = argvars[arg_idx].vval.v_list;
4046 if (list == NULL || list->lv_len == 0)
4047 arg_idx = 0;
4048 }
4049 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004050 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004051 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004052 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004053
4054 /* result is a VAR_PARTIAL */
4055 if (pt == NULL)
4056 vim_free(name);
4057 else
4058 {
4059 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4060 {
4061 listitem_T *li;
4062 int i = 0;
4063 int arg_len = 0;
4064 int lv_len = 0;
4065
4066 if (arg_pt != NULL)
4067 arg_len = arg_pt->pt_argc;
4068 if (list != NULL)
4069 lv_len = list->lv_len;
4070 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004071 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072 if (pt->pt_argv == NULL)
4073 {
4074 vim_free(pt);
4075 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004076 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004077 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004078 for (i = 0; i < arg_len; i++)
4079 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4080 if (lv_len > 0)
4081 for (li = list->lv_first; li != NULL;
4082 li = li->li_next)
4083 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084 }
4085
4086 /* For "function(dict.func, [], dict)" and "func" is a partial
4087 * use "dict". That is backwards compatible. */
4088 if (dict_idx > 0)
4089 {
4090 /* The dict is bound explicitly, pt_auto is FALSE. */
4091 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4092 ++pt->pt_dict->dv_refcount;
4093 }
4094 else if (arg_pt != NULL)
4095 {
4096 /* If the dict was bound automatically the result is also
4097 * bound automatically. */
4098 pt->pt_dict = arg_pt->pt_dict;
4099 pt->pt_auto = arg_pt->pt_auto;
4100 if (pt->pt_dict != NULL)
4101 ++pt->pt_dict->dv_refcount;
4102 }
4103
4104 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004105 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4106 {
4107 pt->pt_func = arg_pt->pt_func;
4108 func_ptr_ref(pt->pt_func);
4109 vim_free(name);
4110 }
4111 else if (is_funcref)
4112 {
4113 pt->pt_func = find_func(trans_name);
4114 func_ptr_ref(pt->pt_func);
4115 vim_free(name);
4116 }
4117 else
4118 {
4119 pt->pt_name = name;
4120 func_ref(name);
4121 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004122 }
4123 rettv->v_type = VAR_PARTIAL;
4124 rettv->vval.v_partial = pt;
4125 }
4126 else
4127 {
4128 /* result is a VAR_FUNC */
4129 rettv->v_type = VAR_FUNC;
4130 rettv->vval.v_string = name;
4131 func_ref(name);
4132 }
4133 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004134theend:
4135 vim_free(trans_name);
4136}
4137
4138/*
4139 * "funcref()" function
4140 */
4141 static void
4142f_funcref(typval_T *argvars, typval_T *rettv)
4143{
4144 common_function(argvars, rettv, TRUE);
4145}
4146
4147/*
4148 * "function()" function
4149 */
4150 static void
4151f_function(typval_T *argvars, typval_T *rettv)
4152{
4153 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004154}
4155
4156/*
4157 * "garbagecollect()" function
4158 */
4159 static void
4160f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4161{
4162 /* This is postponed until we are back at the toplevel, because we may be
4163 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4164 want_garbage_collect = TRUE;
4165
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004166 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004167 garbage_collect_at_exit = TRUE;
4168}
4169
4170/*
4171 * "get()" function
4172 */
4173 static void
4174f_get(typval_T *argvars, typval_T *rettv)
4175{
4176 listitem_T *li;
4177 list_T *l;
4178 dictitem_T *di;
4179 dict_T *d;
4180 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004181 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004182
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004183 if (argvars[0].v_type == VAR_BLOB)
4184 {
4185 int error = FALSE;
4186 int idx = tv_get_number_chk(&argvars[1], &error);
4187
4188 if (!error)
4189 {
4190 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004191 if (idx < 0)
4192 idx = blob_len(argvars[0].vval.v_blob) + idx;
4193 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4194 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004195 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004196 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004197 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004198 tv = rettv;
4199 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004200 }
4201 }
4202 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 {
4204 if ((l = argvars[0].vval.v_list) != NULL)
4205 {
4206 int error = FALSE;
4207
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004208 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004209 if (!error && li != NULL)
4210 tv = &li->li_tv;
4211 }
4212 }
4213 else if (argvars[0].v_type == VAR_DICT)
4214 {
4215 if ((d = argvars[0].vval.v_dict) != NULL)
4216 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004217 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004218 if (di != NULL)
4219 tv = &di->di_tv;
4220 }
4221 }
4222 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4223 {
4224 partial_T *pt;
4225 partial_T fref_pt;
4226
4227 if (argvars[0].v_type == VAR_PARTIAL)
4228 pt = argvars[0].vval.v_partial;
4229 else
4230 {
4231 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4232 fref_pt.pt_name = argvars[0].vval.v_string;
4233 pt = &fref_pt;
4234 }
4235
4236 if (pt != NULL)
4237 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004238 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004239 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004240
4241 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4242 {
4243 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004244 n = partial_name(pt);
4245 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004246 rettv->vval.v_string = NULL;
4247 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004248 {
4249 rettv->vval.v_string = vim_strsave(n);
4250 if (rettv->v_type == VAR_FUNC)
4251 func_ref(rettv->vval.v_string);
4252 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004253 }
4254 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004255 {
4256 what_is_dict = TRUE;
4257 if (pt->pt_dict != NULL)
4258 rettv_dict_set(rettv, pt->pt_dict);
4259 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004260 else if (STRCMP(what, "args") == 0)
4261 {
4262 rettv->v_type = VAR_LIST;
4263 if (rettv_list_alloc(rettv) == OK)
4264 {
4265 int i;
4266
4267 for (i = 0; i < pt->pt_argc; ++i)
4268 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4269 }
4270 }
4271 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004272 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004273
4274 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4275 // third argument
4276 if (!what_is_dict)
4277 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004278 }
4279 }
4280 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004281 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004282
4283 if (tv == NULL)
4284 {
4285 if (argvars[2].v_type != VAR_UNKNOWN)
4286 copy_tv(&argvars[2], rettv);
4287 }
4288 else
4289 copy_tv(tv, rettv);
4290}
4291
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004292/*
4293 * Returns buffer options, variables and other attributes in a dictionary.
4294 */
4295 static dict_T *
4296get_buffer_info(buf_T *buf)
4297{
4298 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004299 tabpage_T *tp;
4300 win_T *wp;
4301 list_T *windows;
4302
4303 dict = dict_alloc();
4304 if (dict == NULL)
4305 return NULL;
4306
Bram Moolenaare0be1672018-07-08 16:50:37 +02004307 dict_add_number(dict, "bufnr", buf->b_fnum);
4308 dict_add_string(dict, "name", buf->b_ffname);
4309 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4310 : buflist_findlnum(buf));
4311 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4312 dict_add_number(dict, "listed", buf->b_p_bl);
4313 dict_add_number(dict, "changed", bufIsChanged(buf));
4314 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4315 dict_add_number(dict, "hidden",
4316 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004317
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004318 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004319 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004320
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004321 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004322 windows = list_alloc();
4323 if (windows != NULL)
4324 {
4325 FOR_ALL_TAB_WINDOWS(tp, wp)
4326 if (wp->w_buffer == buf)
4327 list_append_number(windows, (varnumber_T)wp->w_id);
4328 dict_add_list(dict, "windows", windows);
4329 }
4330
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004331#ifdef FEAT_TEXT_PROP
4332 // List of popup windows displaying this buffer
4333 windows = list_alloc();
4334 if (windows != NULL)
4335 {
4336 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4337 if (wp->w_buffer == buf)
4338 list_append_number(windows, (varnumber_T)wp->w_id);
4339 FOR_ALL_TABPAGES(tp)
4340 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4341 if (wp->w_buffer == buf)
4342 list_append_number(windows, (varnumber_T)wp->w_id);
4343
4344 dict_add_list(dict, "popups", windows);
4345 }
4346#endif
4347
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004348#ifdef FEAT_SIGNS
4349 if (buf->b_signlist != NULL)
4350 {
4351 /* List of signs placed in this buffer */
4352 list_T *signs = list_alloc();
4353 if (signs != NULL)
4354 {
4355 get_buffer_signs(buf, signs);
4356 dict_add_list(dict, "signs", signs);
4357 }
4358 }
4359#endif
4360
4361 return dict;
4362}
4363
4364/*
4365 * "getbufinfo()" function
4366 */
4367 static void
4368f_getbufinfo(typval_T *argvars, typval_T *rettv)
4369{
4370 buf_T *buf = NULL;
4371 buf_T *argbuf = NULL;
4372 dict_T *d;
4373 int filtered = FALSE;
4374 int sel_buflisted = FALSE;
4375 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004376 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004377
4378 if (rettv_list_alloc(rettv) != OK)
4379 return;
4380
4381 /* List of all the buffers or selected buffers */
4382 if (argvars[0].v_type == VAR_DICT)
4383 {
4384 dict_T *sel_d = argvars[0].vval.v_dict;
4385
4386 if (sel_d != NULL)
4387 {
4388 dictitem_T *di;
4389
4390 filtered = TRUE;
4391
4392 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004393 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004394 sel_buflisted = TRUE;
4395
4396 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004397 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004398 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004399
4400 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004401 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004402 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004403 }
4404 }
4405 else if (argvars[0].v_type != VAR_UNKNOWN)
4406 {
4407 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004408 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004409 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004410 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004411 --emsg_off;
4412 if (argbuf == NULL)
4413 return;
4414 }
4415
4416 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004417 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004418 {
4419 if (argbuf != NULL && argbuf != buf)
4420 continue;
4421 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004422 || (sel_buflisted && !buf->b_p_bl)
4423 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004424 continue;
4425
4426 d = get_buffer_info(buf);
4427 if (d != NULL)
4428 list_append_dict(rettv->vval.v_list, d);
4429 if (argbuf != NULL)
4430 return;
4431 }
4432}
4433
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004434/*
4435 * Get line or list of lines from buffer "buf" into "rettv".
4436 * Return a range (from start to end) of lines in rettv from the specified
4437 * buffer.
4438 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4439 */
4440 static void
4441get_buffer_lines(
4442 buf_T *buf,
4443 linenr_T start,
4444 linenr_T end,
4445 int retlist,
4446 typval_T *rettv)
4447{
4448 char_u *p;
4449
4450 rettv->v_type = VAR_STRING;
4451 rettv->vval.v_string = NULL;
4452 if (retlist && rettv_list_alloc(rettv) == FAIL)
4453 return;
4454
4455 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4456 return;
4457
4458 if (!retlist)
4459 {
4460 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4461 p = ml_get_buf(buf, start, FALSE);
4462 else
4463 p = (char_u *)"";
4464 rettv->vval.v_string = vim_strsave(p);
4465 }
4466 else
4467 {
4468 if (end < start)
4469 return;
4470
4471 if (start < 1)
4472 start = 1;
4473 if (end > buf->b_ml.ml_line_count)
4474 end = buf->b_ml.ml_line_count;
4475 while (start <= end)
4476 if (list_append_string(rettv->vval.v_list,
4477 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4478 break;
4479 }
4480}
4481
4482/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004483 * "getbufline()" function
4484 */
4485 static void
4486f_getbufline(typval_T *argvars, typval_T *rettv)
4487{
4488 linenr_T lnum;
4489 linenr_T end;
4490 buf_T *buf;
4491
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004492 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004493 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004494 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004495 --emsg_off;
4496
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004497 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004498 if (argvars[2].v_type == VAR_UNKNOWN)
4499 end = lnum;
4500 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004501 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004502
4503 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4504}
4505
4506/*
4507 * "getbufvar()" function
4508 */
4509 static void
4510f_getbufvar(typval_T *argvars, typval_T *rettv)
4511{
4512 buf_T *buf;
4513 buf_T *save_curbuf;
4514 char_u *varname;
4515 dictitem_T *v;
4516 int done = FALSE;
4517
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004518 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4519 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004520 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004521 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004522
4523 rettv->v_type = VAR_STRING;
4524 rettv->vval.v_string = NULL;
4525
4526 if (buf != NULL && varname != NULL)
4527 {
4528 /* set curbuf to be our buf, temporarily */
4529 save_curbuf = curbuf;
4530 curbuf = buf;
4531
Bram Moolenaar30567352016-08-27 21:25:44 +02004532 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004533 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004534 if (varname[1] == NUL)
4535 {
4536 /* get all buffer-local options in a dict */
4537 dict_T *opts = get_winbuf_options(TRUE);
4538
4539 if (opts != NULL)
4540 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004541 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004542 done = TRUE;
4543 }
4544 }
4545 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4546 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004547 done = TRUE;
4548 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549 else
4550 {
4551 /* Look up the variable. */
4552 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4553 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4554 'b', varname, FALSE);
4555 if (v != NULL)
4556 {
4557 copy_tv(&v->di_tv, rettv);
4558 done = TRUE;
4559 }
4560 }
4561
4562 /* restore previous notion of curbuf */
4563 curbuf = save_curbuf;
4564 }
4565
4566 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4567 /* use the default value */
4568 copy_tv(&argvars[2], rettv);
4569
4570 --emsg_off;
4571}
4572
4573/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004574 * "getchangelist()" function
4575 */
4576 static void
4577f_getchangelist(typval_T *argvars, typval_T *rettv)
4578{
4579#ifdef FEAT_JUMPLIST
4580 buf_T *buf;
4581 int i;
4582 list_T *l;
4583 dict_T *d;
4584#endif
4585
4586 if (rettv_list_alloc(rettv) != OK)
4587 return;
4588
4589#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004590 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004591 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004592 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004593 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004594 if (buf == NULL)
4595 return;
4596
4597 l = list_alloc();
4598 if (l == NULL)
4599 return;
4600
4601 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4602 return;
4603 /*
4604 * The current window change list index tracks only the position in the
4605 * current buffer change list. For other buffers, use the change list
4606 * length as the current index.
4607 */
4608 list_append_number(rettv->vval.v_list,
4609 (varnumber_T)((buf == curwin->w_buffer)
4610 ? curwin->w_changelistidx : buf->b_changelistlen));
4611
4612 for (i = 0; i < buf->b_changelistlen; ++i)
4613 {
4614 if (buf->b_changelist[i].lnum == 0)
4615 continue;
4616 if ((d = dict_alloc()) == NULL)
4617 return;
4618 if (list_append_dict(l, d) == FAIL)
4619 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004620 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4621 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004622 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004623 }
4624#endif
4625}
4626/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004627 * "getchar()" function
4628 */
4629 static void
4630f_getchar(typval_T *argvars, typval_T *rettv)
4631{
4632 varnumber_T n;
4633 int error = FALSE;
4634
Bram Moolenaar84d93902018-09-11 20:10:20 +02004635#ifdef MESSAGE_QUEUE
4636 // vpeekc() used to check for messages, but that caused problems, invoking
4637 // a callback where it was not expected. Some plugins use getchar(1) in a
4638 // loop to await a message, therefore make sure we check for messages here.
4639 parse_queued_messages();
4640#endif
4641
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004642 /* Position the cursor. Needed after a message that ends in a space. */
4643 windgoto(msg_row, msg_col);
4644
4645 ++no_mapping;
4646 ++allow_keys;
4647 for (;;)
4648 {
4649 if (argvars[0].v_type == VAR_UNKNOWN)
4650 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004651 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004652 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004653 /* getchar(1): only check if char avail */
4654 n = vpeekc_any();
4655 else if (error || vpeekc_any() == NUL)
4656 /* illegal argument or getchar(0) and no char avail: return zero */
4657 n = 0;
4658 else
4659 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004660 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661
4662 if (n == K_IGNORE)
4663 continue;
4664 break;
4665 }
4666 --no_mapping;
4667 --allow_keys;
4668
4669 set_vim_var_nr(VV_MOUSE_WIN, 0);
4670 set_vim_var_nr(VV_MOUSE_WINID, 0);
4671 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4672 set_vim_var_nr(VV_MOUSE_COL, 0);
4673
4674 rettv->vval.v_number = n;
4675 if (IS_SPECIAL(n) || mod_mask != 0)
4676 {
4677 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4678 int i = 0;
4679
4680 /* Turn a special key into three bytes, plus modifier. */
4681 if (mod_mask != 0)
4682 {
4683 temp[i++] = K_SPECIAL;
4684 temp[i++] = KS_MODIFIER;
4685 temp[i++] = mod_mask;
4686 }
4687 if (IS_SPECIAL(n))
4688 {
4689 temp[i++] = K_SPECIAL;
4690 temp[i++] = K_SECOND(n);
4691 temp[i++] = K_THIRD(n);
4692 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 else if (has_mbyte)
4694 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004695 else
4696 temp[i++] = n;
4697 temp[i++] = NUL;
4698 rettv->v_type = VAR_STRING;
4699 rettv->vval.v_string = vim_strsave(temp);
4700
4701#ifdef FEAT_MOUSE
4702 if (is_mouse_key(n))
4703 {
4704 int row = mouse_row;
4705 int col = mouse_col;
4706 win_T *win;
4707 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004708 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004709 int winnr = 1;
4710
4711 if (row >= 0 && col >= 0)
4712 {
4713 /* Find the window at the mouse coordinates and compute the
4714 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004715 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004716 if (win == NULL)
4717 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004718 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004719# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004720 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004721 winnr = 0;
4722 else
4723# endif
4724 for (wp = firstwin; wp != win && wp != NULL;
4725 wp = wp->w_next)
4726 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004727 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4728 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4729 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4730 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4731 }
4732 }
4733#endif
4734 }
4735}
4736
4737/*
4738 * "getcharmod()" function
4739 */
4740 static void
4741f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4742{
4743 rettv->vval.v_number = mod_mask;
4744}
4745
4746/*
4747 * "getcharsearch()" function
4748 */
4749 static void
4750f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4751{
4752 if (rettv_dict_alloc(rettv) != FAIL)
4753 {
4754 dict_T *dict = rettv->vval.v_dict;
4755
Bram Moolenaare0be1672018-07-08 16:50:37 +02004756 dict_add_string(dict, "char", last_csearch());
4757 dict_add_number(dict, "forward", last_csearch_forward());
4758 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004759 }
4760}
4761
4762/*
4763 * "getcmdline()" function
4764 */
4765 static void
4766f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4767{
4768 rettv->v_type = VAR_STRING;
4769 rettv->vval.v_string = get_cmdline_str();
4770}
4771
4772/*
4773 * "getcmdpos()" function
4774 */
4775 static void
4776f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4777{
4778 rettv->vval.v_number = get_cmdline_pos() + 1;
4779}
4780
4781/*
4782 * "getcmdtype()" function
4783 */
4784 static void
4785f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4786{
4787 rettv->v_type = VAR_STRING;
4788 rettv->vval.v_string = alloc(2);
4789 if (rettv->vval.v_string != NULL)
4790 {
4791 rettv->vval.v_string[0] = get_cmdline_type();
4792 rettv->vval.v_string[1] = NUL;
4793 }
4794}
4795
4796/*
4797 * "getcmdwintype()" function
4798 */
4799 static void
4800f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4801{
4802 rettv->v_type = VAR_STRING;
4803 rettv->vval.v_string = NULL;
4804#ifdef FEAT_CMDWIN
4805 rettv->vval.v_string = alloc(2);
4806 if (rettv->vval.v_string != NULL)
4807 {
4808 rettv->vval.v_string[0] = cmdwin_type;
4809 rettv->vval.v_string[1] = NUL;
4810 }
4811#endif
4812}
4813
4814#if defined(FEAT_CMDL_COMPL)
4815/*
4816 * "getcompletion()" function
4817 */
4818 static void
4819f_getcompletion(typval_T *argvars, typval_T *rettv)
4820{
4821 char_u *pat;
4822 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004823 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004824 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4825 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004826
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004827 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004828 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004829
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004830 if (p_wic)
4831 options |= WILD_ICASE;
4832
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004833 /* For filtered results, 'wildignore' is used */
4834 if (!filtered)
4835 options |= WILD_KEEP_ALL;
4836
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004837 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004838 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004840 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841 if (xpc.xp_context == EXPAND_NOTHING)
4842 {
4843 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004844 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004845 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004846 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004847 return;
4848 }
4849
4850# if defined(FEAT_MENU)
4851 if (xpc.xp_context == EXPAND_MENUS)
4852 {
4853 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4854 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4855 }
4856# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004857#ifdef FEAT_CSCOPE
4858 if (xpc.xp_context == EXPAND_CSCOPE)
4859 {
4860 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4861 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4862 }
4863#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004864#ifdef FEAT_SIGNS
4865 if (xpc.xp_context == EXPAND_SIGN)
4866 {
4867 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4868 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4869 }
4870#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004871
4872 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4873 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4874 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004875 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004876
4877 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4878
4879 for (i = 0; i < xpc.xp_numfiles; i++)
4880 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4881 }
4882 vim_free(pat);
4883 ExpandCleanup(&xpc);
4884}
4885#endif
4886
4887/*
4888 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004889 *
4890 * Return the current working directory of a window in a tab page.
4891 * First optional argument 'winnr' is the window number or -1 and the second
4892 * optional argument 'tabnr' is the tab page number.
4893 *
4894 * If no arguments are supplied, then return the directory of the current
4895 * window.
4896 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4897 * the specified window.
4898 * If 'winnr' is 0 then return the directory of the current window.
4899 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4900 * directory of the specified tab page. Otherwise return the directory of the
4901 * specified window in the specified tab page.
4902 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 */
4904 static void
4905f_getcwd(typval_T *argvars, typval_T *rettv)
4906{
4907 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004908 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004910 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911
4912 rettv->v_type = VAR_STRING;
4913 rettv->vval.v_string = NULL;
4914
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004915 if (argvars[0].v_type == VAR_NUMBER
4916 && argvars[0].vval.v_number == -1
4917 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004918 global = TRUE;
4919 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004920 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004921
4922 if (wp != NULL && wp->w_localdir != NULL)
4923 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004924 else if (tp != NULL && tp->tp_localdir != NULL)
4925 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4926 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004927 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004928 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004929 rettv->vval.v_string = vim_strsave(globaldir);
4930 else
4931 {
4932 cwd = alloc(MAXPATHL);
4933 if (cwd != NULL)
4934 {
4935 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4936 rettv->vval.v_string = vim_strsave(cwd);
4937 vim_free(cwd);
4938 }
4939 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004941#ifdef BACKSLASH_IN_FILENAME
4942 if (rettv->vval.v_string != NULL)
4943 slash_adjust(rettv->vval.v_string);
4944#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945}
4946
4947/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004948 * "getenv()" function
4949 */
4950 static void
4951f_getenv(typval_T *argvars, typval_T *rettv)
4952{
4953 int mustfree = FALSE;
4954 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4955
4956 if (p == NULL)
4957 {
4958 rettv->v_type = VAR_SPECIAL;
4959 rettv->vval.v_number = VVAL_NULL;
4960 return;
4961 }
4962 if (!mustfree)
4963 p = vim_strsave(p);
4964 rettv->vval.v_string = p;
4965 rettv->v_type = VAR_STRING;
4966}
4967
4968/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004969 * "getfontname()" function
4970 */
4971 static void
4972f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4973{
4974 rettv->v_type = VAR_STRING;
4975 rettv->vval.v_string = NULL;
4976#ifdef FEAT_GUI
4977 if (gui.in_use)
4978 {
4979 GuiFont font;
4980 char_u *name = NULL;
4981
4982 if (argvars[0].v_type == VAR_UNKNOWN)
4983 {
4984 /* Get the "Normal" font. Either the name saved by
4985 * hl_set_font_name() or from the font ID. */
4986 font = gui.norm_font;
4987 name = hl_get_font_name();
4988 }
4989 else
4990 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004991 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004992 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4993 return;
4994 font = gui_mch_get_font(name, FALSE);
4995 if (font == NOFONT)
4996 return; /* Invalid font name, return empty string. */
4997 }
4998 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4999 if (argvars[0].v_type != VAR_UNKNOWN)
5000 gui_mch_free_font(font);
5001 }
5002#endif
5003}
5004
5005/*
5006 * "getfperm({fname})" function
5007 */
5008 static void
5009f_getfperm(typval_T *argvars, typval_T *rettv)
5010{
5011 char_u *fname;
5012 stat_T st;
5013 char_u *perm = NULL;
5014 char_u flags[] = "rwx";
5015 int i;
5016
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005017 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005018
5019 rettv->v_type = VAR_STRING;
5020 if (mch_stat((char *)fname, &st) >= 0)
5021 {
5022 perm = vim_strsave((char_u *)"---------");
5023 if (perm != NULL)
5024 {
5025 for (i = 0; i < 9; i++)
5026 {
5027 if (st.st_mode & (1 << (8 - i)))
5028 perm[i] = flags[i % 3];
5029 }
5030 }
5031 }
5032 rettv->vval.v_string = perm;
5033}
5034
5035/*
5036 * "getfsize({fname})" function
5037 */
5038 static void
5039f_getfsize(typval_T *argvars, typval_T *rettv)
5040{
5041 char_u *fname;
5042 stat_T st;
5043
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005044 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005045
5046 rettv->v_type = VAR_NUMBER;
5047
5048 if (mch_stat((char *)fname, &st) >= 0)
5049 {
5050 if (mch_isdir(fname))
5051 rettv->vval.v_number = 0;
5052 else
5053 {
5054 rettv->vval.v_number = (varnumber_T)st.st_size;
5055
5056 /* non-perfect check for overflow */
5057 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5058 rettv->vval.v_number = -2;
5059 }
5060 }
5061 else
5062 rettv->vval.v_number = -1;
5063}
5064
5065/*
5066 * "getftime({fname})" function
5067 */
5068 static void
5069f_getftime(typval_T *argvars, typval_T *rettv)
5070{
5071 char_u *fname;
5072 stat_T st;
5073
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005074 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075
5076 if (mch_stat((char *)fname, &st) >= 0)
5077 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5078 else
5079 rettv->vval.v_number = -1;
5080}
5081
5082/*
5083 * "getftype({fname})" function
5084 */
5085 static void
5086f_getftype(typval_T *argvars, typval_T *rettv)
5087{
5088 char_u *fname;
5089 stat_T st;
5090 char_u *type = NULL;
5091 char *t;
5092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005093 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094
5095 rettv->v_type = VAR_STRING;
5096 if (mch_lstat((char *)fname, &st) >= 0)
5097 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005098 if (S_ISREG(st.st_mode))
5099 t = "file";
5100 else if (S_ISDIR(st.st_mode))
5101 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 else if (S_ISLNK(st.st_mode))
5103 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104 else if (S_ISBLK(st.st_mode))
5105 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106 else if (S_ISCHR(st.st_mode))
5107 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108 else if (S_ISFIFO(st.st_mode))
5109 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005111 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005112 else
5113 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114 type = vim_strsave((char_u *)t);
5115 }
5116 rettv->vval.v_string = type;
5117}
5118
5119/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005120 * "getjumplist()" function
5121 */
5122 static void
5123f_getjumplist(typval_T *argvars, typval_T *rettv)
5124{
5125#ifdef FEAT_JUMPLIST
5126 win_T *wp;
5127 int i;
5128 list_T *l;
5129 dict_T *d;
5130#endif
5131
5132 if (rettv_list_alloc(rettv) != OK)
5133 return;
5134
5135#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005136 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005137 if (wp == NULL)
5138 return;
5139
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005140 cleanup_jumplist(wp, TRUE);
5141
Bram Moolenaar4f505882018-02-10 21:06:32 +01005142 l = list_alloc();
5143 if (l == NULL)
5144 return;
5145
5146 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5147 return;
5148 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5149
5150 for (i = 0; i < wp->w_jumplistlen; ++i)
5151 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005152 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5153 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005154 if ((d = dict_alloc()) == NULL)
5155 return;
5156 if (list_append_dict(l, d) == FAIL)
5157 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005158 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5159 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005160 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005161 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005162 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005163 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005164 }
5165#endif
5166}
5167
5168/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005169 * "getline(lnum, [end])" function
5170 */
5171 static void
5172f_getline(typval_T *argvars, typval_T *rettv)
5173{
5174 linenr_T lnum;
5175 linenr_T end;
5176 int retlist;
5177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005178 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005179 if (argvars[1].v_type == VAR_UNKNOWN)
5180 {
5181 end = 0;
5182 retlist = FALSE;
5183 }
5184 else
5185 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005186 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005187 retlist = TRUE;
5188 }
5189
5190 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5191}
5192
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005193#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005194 static void
5195get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5196{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005197 if (what_arg->v_type == VAR_UNKNOWN)
5198 {
5199 if (rettv_list_alloc(rettv) == OK)
5200 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005201 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005202 }
5203 else
5204 {
5205 if (rettv_dict_alloc(rettv) == OK)
5206 if (is_qf || (wp != NULL))
5207 {
5208 if (what_arg->v_type == VAR_DICT)
5209 {
5210 dict_T *d = what_arg->vval.v_dict;
5211
5212 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005213 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005214 }
5215 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005216 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005217 }
5218 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005219}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005220#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005221
5222/*
5223 * "getloclist()" function
5224 */
5225 static void
5226f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5227{
5228#ifdef FEAT_QUICKFIX
5229 win_T *wp;
5230
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005231 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005232 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5233#endif
5234}
5235
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005236/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005237 * "getpid()" function
5238 */
5239 static void
5240f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5241{
5242 rettv->vval.v_number = mch_get_pid();
5243}
5244
5245 static void
5246getpos_both(
5247 typval_T *argvars,
5248 typval_T *rettv,
5249 int getcurpos)
5250{
5251 pos_T *fp;
5252 list_T *l;
5253 int fnum = -1;
5254
5255 if (rettv_list_alloc(rettv) == OK)
5256 {
5257 l = rettv->vval.v_list;
5258 if (getcurpos)
5259 fp = &curwin->w_cursor;
5260 else
5261 fp = var2fpos(&argvars[0], TRUE, &fnum);
5262 if (fnum != -1)
5263 list_append_number(l, (varnumber_T)fnum);
5264 else
5265 list_append_number(l, (varnumber_T)0);
5266 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5267 : (varnumber_T)0);
5268 list_append_number(l, (fp != NULL)
5269 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5270 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005271 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005272 (varnumber_T)0);
5273 if (getcurpos)
5274 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005275 int save_set_curswant = curwin->w_set_curswant;
5276 colnr_T save_curswant = curwin->w_curswant;
5277 colnr_T save_virtcol = curwin->w_virtcol;
5278
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005279 update_curswant();
5280 list_append_number(l, curwin->w_curswant == MAXCOL ?
5281 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005282
5283 // Do not change "curswant", as it is unexpected that a get
5284 // function has a side effect.
5285 if (save_set_curswant)
5286 {
5287 curwin->w_set_curswant = save_set_curswant;
5288 curwin->w_curswant = save_curswant;
5289 curwin->w_virtcol = save_virtcol;
5290 curwin->w_valid &= ~VALID_VIRTCOL;
5291 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 }
5293 }
5294 else
5295 rettv->vval.v_number = FALSE;
5296}
5297
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298/*
5299 * "getcurpos()" function
5300 */
5301 static void
5302f_getcurpos(typval_T *argvars, typval_T *rettv)
5303{
5304 getpos_both(argvars, rettv, TRUE);
5305}
5306
5307/*
5308 * "getpos(string)" function
5309 */
5310 static void
5311f_getpos(typval_T *argvars, typval_T *rettv)
5312{
5313 getpos_both(argvars, rettv, FALSE);
5314}
5315
5316/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005317 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005318 */
5319 static void
5320f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5321{
5322#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005323 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005324#endif
5325}
5326
5327/*
5328 * "getreg()" function
5329 */
5330 static void
5331f_getreg(typval_T *argvars, typval_T *rettv)
5332{
5333 char_u *strregname;
5334 int regname;
5335 int arg2 = FALSE;
5336 int return_list = FALSE;
5337 int error = FALSE;
5338
5339 if (argvars[0].v_type != VAR_UNKNOWN)
5340 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005341 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005342 error = strregname == NULL;
5343 if (argvars[1].v_type != VAR_UNKNOWN)
5344 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005345 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005346 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005347 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005348 }
5349 }
5350 else
5351 strregname = get_vim_var_str(VV_REG);
5352
5353 if (error)
5354 return;
5355
5356 regname = (strregname == NULL ? '"' : *strregname);
5357 if (regname == 0)
5358 regname = '"';
5359
5360 if (return_list)
5361 {
5362 rettv->v_type = VAR_LIST;
5363 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5364 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5365 if (rettv->vval.v_list == NULL)
5366 (void)rettv_list_alloc(rettv);
5367 else
5368 ++rettv->vval.v_list->lv_refcount;
5369 }
5370 else
5371 {
5372 rettv->v_type = VAR_STRING;
5373 rettv->vval.v_string = get_reg_contents(regname,
5374 arg2 ? GREG_EXPR_SRC : 0);
5375 }
5376}
5377
5378/*
5379 * "getregtype()" function
5380 */
5381 static void
5382f_getregtype(typval_T *argvars, typval_T *rettv)
5383{
5384 char_u *strregname;
5385 int regname;
5386 char_u buf[NUMBUFLEN + 2];
5387 long reglen = 0;
5388
5389 if (argvars[0].v_type != VAR_UNKNOWN)
5390 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005391 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005392 if (strregname == NULL) /* type error; errmsg already given */
5393 {
5394 rettv->v_type = VAR_STRING;
5395 rettv->vval.v_string = NULL;
5396 return;
5397 }
5398 }
5399 else
5400 /* Default to v:register */
5401 strregname = get_vim_var_str(VV_REG);
5402
5403 regname = (strregname == NULL ? '"' : *strregname);
5404 if (regname == 0)
5405 regname = '"';
5406
5407 buf[0] = NUL;
5408 buf[1] = NUL;
5409 switch (get_reg_type(regname, &reglen))
5410 {
5411 case MLINE: buf[0] = 'V'; break;
5412 case MCHAR: buf[0] = 'v'; break;
5413 case MBLOCK:
5414 buf[0] = Ctrl_V;
5415 sprintf((char *)buf + 1, "%ld", reglen + 1);
5416 break;
5417 }
5418 rettv->v_type = VAR_STRING;
5419 rettv->vval.v_string = vim_strsave(buf);
5420}
5421
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005422/*
5423 * Returns information (variables, options, etc.) about a tab page
5424 * as a dictionary.
5425 */
5426 static dict_T *
5427get_tabpage_info(tabpage_T *tp, int tp_idx)
5428{
5429 win_T *wp;
5430 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005431 list_T *l;
5432
5433 dict = dict_alloc();
5434 if (dict == NULL)
5435 return NULL;
5436
Bram Moolenaare0be1672018-07-08 16:50:37 +02005437 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005438
5439 l = list_alloc();
5440 if (l != NULL)
5441 {
5442 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005443 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005444 list_append_number(l, (varnumber_T)wp->w_id);
5445 dict_add_list(dict, "windows", l);
5446 }
5447
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005448 /* Make a reference to tabpage variables */
5449 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005450
5451 return dict;
5452}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005453
5454/*
5455 * "gettabinfo()" function
5456 */
5457 static void
5458f_gettabinfo(typval_T *argvars, typval_T *rettv)
5459{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005460 tabpage_T *tp, *tparg = NULL;
5461 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005462 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005463
5464 if (rettv_list_alloc(rettv) != OK)
5465 return;
5466
5467 if (argvars[0].v_type != VAR_UNKNOWN)
5468 {
5469 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005470 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005471 if (tparg == NULL)
5472 return;
5473 }
5474
5475 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005476 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005477 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005478 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005479 if (tparg != NULL && tp != tparg)
5480 continue;
5481 d = get_tabpage_info(tp, tpnr);
5482 if (d != NULL)
5483 list_append_dict(rettv->vval.v_list, d);
5484 if (tparg != NULL)
5485 return;
5486 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005487}
5488
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489/*
5490 * "gettabvar()" function
5491 */
5492 static void
5493f_gettabvar(typval_T *argvars, typval_T *rettv)
5494{
5495 win_T *oldcurwin;
5496 tabpage_T *tp, *oldtabpage;
5497 dictitem_T *v;
5498 char_u *varname;
5499 int done = FALSE;
5500
5501 rettv->v_type = VAR_STRING;
5502 rettv->vval.v_string = NULL;
5503
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005504 varname = tv_get_string_chk(&argvars[1]);
5505 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005506 if (tp != NULL && varname != NULL)
5507 {
5508 /* Set tp to be our tabpage, temporarily. Also set the window to the
5509 * first window in the tabpage, otherwise the window is not valid. */
5510 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005511 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5512 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005513 {
5514 /* look up the variable */
5515 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5516 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5517 if (v != NULL)
5518 {
5519 copy_tv(&v->di_tv, rettv);
5520 done = TRUE;
5521 }
5522 }
5523
5524 /* restore previous notion of curwin */
5525 restore_win(oldcurwin, oldtabpage, TRUE);
5526 }
5527
5528 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5529 copy_tv(&argvars[2], rettv);
5530}
5531
5532/*
5533 * "gettabwinvar()" function
5534 */
5535 static void
5536f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5537{
5538 getwinvar(argvars, rettv, 1);
5539}
5540
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005541/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005542 * "gettagstack()" function
5543 */
5544 static void
5545f_gettagstack(typval_T *argvars, typval_T *rettv)
5546{
5547 win_T *wp = curwin; // default is current window
5548
5549 if (rettv_dict_alloc(rettv) != OK)
5550 return;
5551
5552 if (argvars[0].v_type != VAR_UNKNOWN)
5553 {
5554 wp = find_win_by_nr_or_id(&argvars[0]);
5555 if (wp == NULL)
5556 return;
5557 }
5558
5559 get_tagstack(wp, rettv->vval.v_dict);
5560}
5561
5562/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005563 * Returns information about a window as a dictionary.
5564 */
5565 static dict_T *
5566get_win_info(win_T *wp, short tpnr, short winnr)
5567{
5568 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005569
5570 dict = dict_alloc();
5571 if (dict == NULL)
5572 return NULL;
5573
Bram Moolenaare0be1672018-07-08 16:50:37 +02005574 dict_add_number(dict, "tabnr", tpnr);
5575 dict_add_number(dict, "winnr", winnr);
5576 dict_add_number(dict, "winid", wp->w_id);
5577 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005578 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005579 dict_add_number(dict, "topline", wp->w_topline);
5580 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005581#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005582 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005583#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005584 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005585 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005586 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005587
Bram Moolenaar69905d12017-08-13 18:14:47 +02005588#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005589 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005590#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005591#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005592 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5593 dict_add_number(dict, "loclist",
5594 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005595#endif
5596
Bram Moolenaar30567352016-08-27 21:25:44 +02005597 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005598 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005599
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005600 return dict;
5601}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005602
5603/*
5604 * "getwininfo()" function
5605 */
5606 static void
5607f_getwininfo(typval_T *argvars, typval_T *rettv)
5608{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005609 tabpage_T *tp;
5610 win_T *wp = NULL, *wparg = NULL;
5611 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005612 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005613
5614 if (rettv_list_alloc(rettv) != OK)
5615 return;
5616
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005617 if (argvars[0].v_type != VAR_UNKNOWN)
5618 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005619 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005620 if (wparg == NULL)
5621 return;
5622 }
5623
5624 /* Collect information about either all the windows across all the tab
5625 * pages or one particular window.
5626 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005627 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005628 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005629 tabnr++;
5630 winnr = 0;
5631 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005632 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005633 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005634 if (wparg != NULL && wp != wparg)
5635 continue;
5636 d = get_win_info(wp, tabnr, winnr);
5637 if (d != NULL)
5638 list_append_dict(rettv->vval.v_list, d);
5639 if (wparg != NULL)
5640 /* found information about a specific window */
5641 return;
5642 }
5643 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005644}
5645
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005646/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005647 * "win_execute()" function
5648 */
5649 static void
5650f_win_execute(typval_T *argvars, typval_T *rettv)
5651{
5652 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005653 tabpage_T *tp;
5654 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005655 win_T *save_curwin;
5656 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005657
Bram Moolenaar820680b2019-08-09 14:56:22 +02005658 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005659 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005660 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005661 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005662 check_cursor();
5663 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005664 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005665 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005666 }
5667}
5668
5669/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005670 * "win_findbuf()" function
5671 */
5672 static void
5673f_win_findbuf(typval_T *argvars, typval_T *rettv)
5674{
5675 if (rettv_list_alloc(rettv) != FAIL)
5676 win_findbuf(argvars, rettv->vval.v_list);
5677}
5678
5679/*
5680 * "win_getid()" function
5681 */
5682 static void
5683f_win_getid(typval_T *argvars, typval_T *rettv)
5684{
5685 rettv->vval.v_number = win_getid(argvars);
5686}
5687
5688/*
5689 * "win_gotoid()" function
5690 */
5691 static void
5692f_win_gotoid(typval_T *argvars, typval_T *rettv)
5693{
5694 rettv->vval.v_number = win_gotoid(argvars);
5695}
5696
5697/*
5698 * "win_id2tabwin()" function
5699 */
5700 static void
5701f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5702{
5703 if (rettv_list_alloc(rettv) != FAIL)
5704 win_id2tabwin(argvars, rettv->vval.v_list);
5705}
5706
5707/*
5708 * "win_id2win()" function
5709 */
5710 static void
5711f_win_id2win(typval_T *argvars, typval_T *rettv)
5712{
5713 rettv->vval.v_number = win_id2win(argvars);
5714}
5715
5716/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005717 * "win_screenpos()" function
5718 */
5719 static void
5720f_win_screenpos(typval_T *argvars, typval_T *rettv)
5721{
5722 win_T *wp;
5723
5724 if (rettv_list_alloc(rettv) == FAIL)
5725 return;
5726
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005727 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005728 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5729 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5730}
5731
5732/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005733 * "getwinpos({timeout})" function
5734 */
5735 static void
5736f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5737{
5738 int x = -1;
5739 int y = -1;
5740
5741 if (rettv_list_alloc(rettv) == FAIL)
5742 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005743#if defined(FEAT_GUI) \
5744 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5745 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005746 {
5747 varnumber_T timeout = 100;
5748
5749 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005750 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005751
5752 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005753 }
5754#endif
5755 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5756 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5757}
5758
5759
5760/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005761 * "getwinposx()" function
5762 */
5763 static void
5764f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5765{
5766 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005767#if defined(FEAT_GUI) \
5768 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5769 || defined(MSWIN)
5770
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005771 {
5772 int x, y;
5773
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005774 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005775 rettv->vval.v_number = x;
5776 }
5777#endif
5778}
5779
5780/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005781 * "getwinposy()" function
5782 */
5783 static void
5784f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5785{
5786 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005787#if defined(FEAT_GUI) \
5788 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5789 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790 {
5791 int x, y;
5792
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005793 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005794 rettv->vval.v_number = y;
5795 }
5796#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005797}
5798
5799/*
5800 * "getwinvar()" function
5801 */
5802 static void
5803f_getwinvar(typval_T *argvars, typval_T *rettv)
5804{
5805 getwinvar(argvars, rettv, 0);
5806}
5807
5808/*
5809 * "glob()" function
5810 */
5811 static void
5812f_glob(typval_T *argvars, typval_T *rettv)
5813{
5814 int options = WILD_SILENT|WILD_USE_NL;
5815 expand_T xpc;
5816 int error = FALSE;
5817
5818 /* When the optional second argument is non-zero, don't remove matches
5819 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5820 rettv->v_type = VAR_STRING;
5821 if (argvars[1].v_type != VAR_UNKNOWN)
5822 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005823 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005824 options |= WILD_KEEP_ALL;
5825 if (argvars[2].v_type != VAR_UNKNOWN)
5826 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005827 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005828 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005830 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005831 options |= WILD_ALLLINKS;
5832 }
5833 }
5834 if (!error)
5835 {
5836 ExpandInit(&xpc);
5837 xpc.xp_context = EXPAND_FILES;
5838 if (p_wic)
5839 options += WILD_ICASE;
5840 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005841 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005842 NULL, options, WILD_ALL);
5843 else if (rettv_list_alloc(rettv) != FAIL)
5844 {
5845 int i;
5846
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005847 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005848 NULL, options, WILD_ALL_KEEP);
5849 for (i = 0; i < xpc.xp_numfiles; i++)
5850 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5851
5852 ExpandCleanup(&xpc);
5853 }
5854 }
5855 else
5856 rettv->vval.v_string = NULL;
5857}
5858
5859/*
5860 * "globpath()" function
5861 */
5862 static void
5863f_globpath(typval_T *argvars, typval_T *rettv)
5864{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005865 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005866 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005867 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 int error = FALSE;
5869 garray_T ga;
5870 int i;
5871
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005872 // When the optional second argument is non-zero, don't remove matches
5873 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005874 rettv->v_type = VAR_STRING;
5875 if (argvars[2].v_type != VAR_UNKNOWN)
5876 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005877 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005878 flags |= WILD_KEEP_ALL;
5879 if (argvars[3].v_type != VAR_UNKNOWN)
5880 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005881 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005882 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005883 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005884 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 flags |= WILD_ALLLINKS;
5886 }
5887 }
5888 if (file != NULL && !error)
5889 {
5890 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005891 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005892 if (rettv->v_type == VAR_STRING)
5893 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5894 else if (rettv_list_alloc(rettv) != FAIL)
5895 for (i = 0; i < ga.ga_len; ++i)
5896 list_append_string(rettv->vval.v_list,
5897 ((char_u **)(ga.ga_data))[i], -1);
5898 ga_clear_strings(&ga);
5899 }
5900 else
5901 rettv->vval.v_string = NULL;
5902}
5903
5904/*
5905 * "glob2regpat()" function
5906 */
5907 static void
5908f_glob2regpat(typval_T *argvars, typval_T *rettv)
5909{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005910 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005911
5912 rettv->v_type = VAR_STRING;
5913 rettv->vval.v_string = (pat == NULL)
5914 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5915}
5916
5917/* for VIM_VERSION_ defines */
5918#include "version.h"
5919
5920/*
5921 * "has()" function
5922 */
5923 static void
5924f_has(typval_T *argvars, typval_T *rettv)
5925{
5926 int i;
5927 char_u *name;
5928 int n = FALSE;
5929 static char *(has_list[]) =
5930 {
5931#ifdef AMIGA
5932 "amiga",
5933# ifdef FEAT_ARP
5934 "arp",
5935# endif
5936#endif
5937#ifdef __BEOS__
5938 "beos",
5939#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005940#if defined(BSD) && !defined(MACOS_X)
5941 "bsd",
5942#endif
5943#ifdef hpux
5944 "hpux",
5945#endif
5946#ifdef __linux__
5947 "linux",
5948#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005949#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005950 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5951 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005952# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005953 "macunix", /* Mac OS X, with the darwin feature */
5954 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005955# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005956#endif
5957#ifdef __QNX__
5958 "qnx",
5959#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005960#ifdef SUN_SYSTEM
5961 "sun",
5962#else
5963 "moon",
5964#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005965#ifdef UNIX
5966 "unix",
5967#endif
5968#ifdef VMS
5969 "vms",
5970#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005971#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972 "win32",
5973#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005974#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975 "win32unix",
5976#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005977#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978 "win64",
5979#endif
5980#ifdef EBCDIC
5981 "ebcdic",
5982#endif
5983#ifndef CASE_INSENSITIVE_FILENAME
5984 "fname_case",
5985#endif
5986#ifdef HAVE_ACL
5987 "acl",
5988#endif
5989#ifdef FEAT_ARABIC
5990 "arabic",
5991#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005992 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005993#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005994 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005995#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005996#ifdef FEAT_AUTOSERVERNAME
5997 "autoservername",
5998#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005999#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006000 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006001# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006002 "balloon_multiline",
6003# endif
6004#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006005#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006006 "balloon_eval_term",
6007#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006008#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6009 "builtin_terms",
6010# ifdef ALL_BUILTIN_TCAPS
6011 "all_builtin_terms",
6012# endif
6013#endif
6014#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006015 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006016 || defined(FEAT_GUI_MOTIF))
6017 "browsefilter",
6018#endif
6019#ifdef FEAT_BYTEOFF
6020 "byte_offset",
6021#endif
6022#ifdef FEAT_JOB_CHANNEL
6023 "channel",
6024#endif
6025#ifdef FEAT_CINDENT
6026 "cindent",
6027#endif
6028#ifdef FEAT_CLIENTSERVER
6029 "clientserver",
6030#endif
6031#ifdef FEAT_CLIPBOARD
6032 "clipboard",
6033#endif
6034#ifdef FEAT_CMDL_COMPL
6035 "cmdline_compl",
6036#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006037 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006038#ifdef FEAT_COMMENTS
6039 "comments",
6040#endif
6041#ifdef FEAT_CONCEAL
6042 "conceal",
6043#endif
6044#ifdef FEAT_CRYPT
6045 "cryptv",
6046 "crypt-blowfish",
6047 "crypt-blowfish2",
6048#endif
6049#ifdef FEAT_CSCOPE
6050 "cscope",
6051#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006052 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006053#ifdef CURSOR_SHAPE
6054 "cursorshape",
6055#endif
6056#ifdef DEBUG
6057 "debug",
6058#endif
6059#ifdef FEAT_CON_DIALOG
6060 "dialog_con",
6061#endif
6062#ifdef FEAT_GUI_DIALOG
6063 "dialog_gui",
6064#endif
6065#ifdef FEAT_DIFF
6066 "diff",
6067#endif
6068#ifdef FEAT_DIGRAPHS
6069 "digraphs",
6070#endif
6071#ifdef FEAT_DIRECTX
6072 "directx",
6073#endif
6074#ifdef FEAT_DND
6075 "dnd",
6076#endif
6077#ifdef FEAT_EMACS_TAGS
6078 "emacs_tags",
6079#endif
6080 "eval", /* always present, of course! */
6081 "ex_extra", /* graduated feature */
6082#ifdef FEAT_SEARCH_EXTRA
6083 "extra_search",
6084#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006085#ifdef FEAT_SEARCHPATH
6086 "file_in_path",
6087#endif
6088#ifdef FEAT_FILTERPIPE
6089 "filterpipe",
6090#endif
6091#ifdef FEAT_FIND_ID
6092 "find_in_path",
6093#endif
6094#ifdef FEAT_FLOAT
6095 "float",
6096#endif
6097#ifdef FEAT_FOLDING
6098 "folding",
6099#endif
6100#ifdef FEAT_FOOTER
6101 "footer",
6102#endif
6103#if !defined(USE_SYSTEM) && defined(UNIX)
6104 "fork",
6105#endif
6106#ifdef FEAT_GETTEXT
6107 "gettext",
6108#endif
6109#ifdef FEAT_GUI
6110 "gui",
6111#endif
6112#ifdef FEAT_GUI_ATHENA
6113# ifdef FEAT_GUI_NEXTAW
6114 "gui_neXtaw",
6115# else
6116 "gui_athena",
6117# endif
6118#endif
6119#ifdef FEAT_GUI_GTK
6120 "gui_gtk",
6121# ifdef USE_GTK3
6122 "gui_gtk3",
6123# else
6124 "gui_gtk2",
6125# endif
6126#endif
6127#ifdef FEAT_GUI_GNOME
6128 "gui_gnome",
6129#endif
6130#ifdef FEAT_GUI_MAC
6131 "gui_mac",
6132#endif
6133#ifdef FEAT_GUI_MOTIF
6134 "gui_motif",
6135#endif
6136#ifdef FEAT_GUI_PHOTON
6137 "gui_photon",
6138#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006139#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006140 "gui_win32",
6141#endif
6142#ifdef FEAT_HANGULIN
6143 "hangul_input",
6144#endif
6145#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6146 "iconv",
6147#endif
6148#ifdef FEAT_INS_EXPAND
6149 "insert_expand",
6150#endif
6151#ifdef FEAT_JOB_CHANNEL
6152 "job",
6153#endif
6154#ifdef FEAT_JUMPLIST
6155 "jumplist",
6156#endif
6157#ifdef FEAT_KEYMAP
6158 "keymap",
6159#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006160 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006161#ifdef FEAT_LANGMAP
6162 "langmap",
6163#endif
6164#ifdef FEAT_LIBCALL
6165 "libcall",
6166#endif
6167#ifdef FEAT_LINEBREAK
6168 "linebreak",
6169#endif
6170#ifdef FEAT_LISP
6171 "lispindent",
6172#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006173 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006174 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175#ifdef FEAT_LUA
6176# ifndef DYNAMIC_LUA
6177 "lua",
6178# endif
6179#endif
6180#ifdef FEAT_MENU
6181 "menu",
6182#endif
6183#ifdef FEAT_SESSION
6184 "mksession",
6185#endif
6186#ifdef FEAT_MODIFY_FNAME
6187 "modify_fname",
6188#endif
6189#ifdef FEAT_MOUSE
6190 "mouse",
6191#endif
6192#ifdef FEAT_MOUSESHAPE
6193 "mouseshape",
6194#endif
6195#if defined(UNIX) || defined(VMS)
6196# ifdef FEAT_MOUSE_DEC
6197 "mouse_dec",
6198# endif
6199# ifdef FEAT_MOUSE_GPM
6200 "mouse_gpm",
6201# endif
6202# ifdef FEAT_MOUSE_JSB
6203 "mouse_jsbterm",
6204# endif
6205# ifdef FEAT_MOUSE_NET
6206 "mouse_netterm",
6207# endif
6208# ifdef FEAT_MOUSE_PTERM
6209 "mouse_pterm",
6210# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006211# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212 "mouse_sgr",
6213# endif
6214# ifdef FEAT_SYSMOUSE
6215 "mouse_sysmouse",
6216# endif
6217# ifdef FEAT_MOUSE_URXVT
6218 "mouse_urxvt",
6219# endif
6220# ifdef FEAT_MOUSE_XTERM
6221 "mouse_xterm",
6222# endif
6223#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006224 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006225#ifdef FEAT_MBYTE_IME
6226 "multi_byte_ime",
6227#endif
6228#ifdef FEAT_MULTI_LANG
6229 "multi_lang",
6230#endif
6231#ifdef FEAT_MZSCHEME
6232#ifndef DYNAMIC_MZSCHEME
6233 "mzscheme",
6234#endif
6235#endif
6236#ifdef FEAT_NUM64
6237 "num64",
6238#endif
6239#ifdef FEAT_OLE
6240 "ole",
6241#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006242#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006243 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006244#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006245#ifdef FEAT_PATH_EXTRA
6246 "path_extra",
6247#endif
6248#ifdef FEAT_PERL
6249#ifndef DYNAMIC_PERL
6250 "perl",
6251#endif
6252#endif
6253#ifdef FEAT_PERSISTENT_UNDO
6254 "persistent_undo",
6255#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006256#if defined(FEAT_PYTHON)
6257 "python_compiled",
6258# if defined(DYNAMIC_PYTHON)
6259 "python_dynamic",
6260# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006261 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006262 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006263# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006265#if defined(FEAT_PYTHON3)
6266 "python3_compiled",
6267# if defined(DYNAMIC_PYTHON3)
6268 "python3_dynamic",
6269# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006271 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006272# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006273#endif
6274#ifdef FEAT_POSTSCRIPT
6275 "postscript",
6276#endif
6277#ifdef FEAT_PRINTER
6278 "printer",
6279#endif
6280#ifdef FEAT_PROFILE
6281 "profile",
6282#endif
6283#ifdef FEAT_RELTIME
6284 "reltime",
6285#endif
6286#ifdef FEAT_QUICKFIX
6287 "quickfix",
6288#endif
6289#ifdef FEAT_RIGHTLEFT
6290 "rightleft",
6291#endif
6292#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6293 "ruby",
6294#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006295 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006296#ifdef FEAT_CMDL_INFO
6297 "showcmd",
6298 "cmdline_info",
6299#endif
6300#ifdef FEAT_SIGNS
6301 "signs",
6302#endif
6303#ifdef FEAT_SMARTINDENT
6304 "smartindent",
6305#endif
6306#ifdef STARTUPTIME
6307 "startuptime",
6308#endif
6309#ifdef FEAT_STL_OPT
6310 "statusline",
6311#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006312#ifdef FEAT_NETBEANS_INTG
6313 "netbeans_intg",
6314#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006315#ifdef FEAT_SOUND
6316 "sound",
6317#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318#ifdef FEAT_SPELL
6319 "spell",
6320#endif
6321#ifdef FEAT_SYN_HL
6322 "syntax",
6323#endif
6324#if defined(USE_SYSTEM) || !defined(UNIX)
6325 "system",
6326#endif
6327#ifdef FEAT_TAG_BINS
6328 "tag_binary",
6329#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006330#ifdef FEAT_TCL
6331# ifndef DYNAMIC_TCL
6332 "tcl",
6333# endif
6334#endif
6335#ifdef FEAT_TERMGUICOLORS
6336 "termguicolors",
6337#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006338#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006339 "terminal",
6340#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341#ifdef TERMINFO
6342 "terminfo",
6343#endif
6344#ifdef FEAT_TERMRESPONSE
6345 "termresponse",
6346#endif
6347#ifdef FEAT_TEXTOBJ
6348 "textobjects",
6349#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006350#ifdef FEAT_TEXT_PROP
6351 "textprop",
6352#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353#ifdef HAVE_TGETENT
6354 "tgetent",
6355#endif
6356#ifdef FEAT_TIMERS
6357 "timers",
6358#endif
6359#ifdef FEAT_TITLE
6360 "title",
6361#endif
6362#ifdef FEAT_TOOLBAR
6363 "toolbar",
6364#endif
6365#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6366 "unnamedplus",
6367#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006368 "user-commands", /* was accidentally included in 5.4 */
6369 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006370#ifdef FEAT_VARTABS
6371 "vartabs",
6372#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006373 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006374#ifdef FEAT_VIMINFO
6375 "viminfo",
6376#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006377 "vimscript-1",
6378 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006379 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006380 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006381 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006382 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006383 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006384#ifdef FEAT_VTP
6385 "vtp",
6386#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006387#ifdef FEAT_WILDIGN
6388 "wildignore",
6389#endif
6390#ifdef FEAT_WILDMENU
6391 "wildmenu",
6392#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394#ifdef FEAT_WAK
6395 "winaltkeys",
6396#endif
6397#ifdef FEAT_WRITEBACKUP
6398 "writebackup",
6399#endif
6400#ifdef FEAT_XIM
6401 "xim",
6402#endif
6403#ifdef FEAT_XFONTSET
6404 "xfontset",
6405#endif
6406#ifdef FEAT_XPM_W32
6407 "xpm",
6408 "xpm_w32", /* for backward compatibility */
6409#else
6410# if defined(HAVE_XPM)
6411 "xpm",
6412# endif
6413#endif
6414#ifdef USE_XSMP
6415 "xsmp",
6416#endif
6417#ifdef USE_XSMP_INTERACT
6418 "xsmp_interact",
6419#endif
6420#ifdef FEAT_XCLIPBOARD
6421 "xterm_clipboard",
6422#endif
6423#ifdef FEAT_XTERM_SAVE
6424 "xterm_save",
6425#endif
6426#if defined(UNIX) && defined(FEAT_X11)
6427 "X11",
6428#endif
6429 NULL
6430 };
6431
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006432 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006433 for (i = 0; has_list[i] != NULL; ++i)
6434 if (STRICMP(name, has_list[i]) == 0)
6435 {
6436 n = TRUE;
6437 break;
6438 }
6439
6440 if (n == FALSE)
6441 {
6442 if (STRNICMP(name, "patch", 5) == 0)
6443 {
6444 if (name[5] == '-'
6445 && STRLEN(name) >= 11
6446 && vim_isdigit(name[6])
6447 && vim_isdigit(name[8])
6448 && vim_isdigit(name[10]))
6449 {
6450 int major = atoi((char *)name + 6);
6451 int minor = atoi((char *)name + 8);
6452
6453 /* Expect "patch-9.9.01234". */
6454 n = (major < VIM_VERSION_MAJOR
6455 || (major == VIM_VERSION_MAJOR
6456 && (minor < VIM_VERSION_MINOR
6457 || (minor == VIM_VERSION_MINOR
6458 && has_patch(atoi((char *)name + 10))))));
6459 }
6460 else
6461 n = has_patch(atoi((char *)name + 5));
6462 }
6463 else if (STRICMP(name, "vim_starting") == 0)
6464 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006465 else if (STRICMP(name, "ttyin") == 0)
6466 n = mch_input_isatty();
6467 else if (STRICMP(name, "ttyout") == 0)
6468 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006469 else if (STRICMP(name, "multi_byte_encoding") == 0)
6470 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006471#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472 else if (STRICMP(name, "balloon_multiline") == 0)
6473 n = multiline_balloon_available();
6474#endif
6475#ifdef DYNAMIC_TCL
6476 else if (STRICMP(name, "tcl") == 0)
6477 n = tcl_enabled(FALSE);
6478#endif
6479#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6480 else if (STRICMP(name, "iconv") == 0)
6481 n = iconv_enabled(FALSE);
6482#endif
6483#ifdef DYNAMIC_LUA
6484 else if (STRICMP(name, "lua") == 0)
6485 n = lua_enabled(FALSE);
6486#endif
6487#ifdef DYNAMIC_MZSCHEME
6488 else if (STRICMP(name, "mzscheme") == 0)
6489 n = mzscheme_enabled(FALSE);
6490#endif
6491#ifdef DYNAMIC_RUBY
6492 else if (STRICMP(name, "ruby") == 0)
6493 n = ruby_enabled(FALSE);
6494#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006495#ifdef DYNAMIC_PYTHON
6496 else if (STRICMP(name, "python") == 0)
6497 n = python_enabled(FALSE);
6498#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499#ifdef DYNAMIC_PYTHON3
6500 else if (STRICMP(name, "python3") == 0)
6501 n = python3_enabled(FALSE);
6502#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006503#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6504 else if (STRICMP(name, "pythonx") == 0)
6505 {
6506# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6507 if (p_pyx == 0)
6508 n = python3_enabled(FALSE) || python_enabled(FALSE);
6509 else if (p_pyx == 3)
6510 n = python3_enabled(FALSE);
6511 else if (p_pyx == 2)
6512 n = python_enabled(FALSE);
6513# elif defined(DYNAMIC_PYTHON)
6514 n = python_enabled(FALSE);
6515# elif defined(DYNAMIC_PYTHON3)
6516 n = python3_enabled(FALSE);
6517# endif
6518 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006519#endif
6520#ifdef DYNAMIC_PERL
6521 else if (STRICMP(name, "perl") == 0)
6522 n = perl_enabled(FALSE);
6523#endif
6524#ifdef FEAT_GUI
6525 else if (STRICMP(name, "gui_running") == 0)
6526 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527# ifdef FEAT_BROWSE
6528 else if (STRICMP(name, "browse") == 0)
6529 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6530# endif
6531#endif
6532#ifdef FEAT_SYN_HL
6533 else if (STRICMP(name, "syntax_items") == 0)
6534 n = syntax_present(curwin);
6535#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006536#ifdef FEAT_VTP
6537 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006538 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539#endif
6540#ifdef FEAT_NETBEANS_INTG
6541 else if (STRICMP(name, "netbeans_enabled") == 0)
6542 n = netbeans_active();
6543#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006544#ifdef FEAT_MOUSE_GPM
6545 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6546 n = gpm_enabled();
6547#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006548#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006549 else if (STRICMP(name, "terminal") == 0)
6550 n = terminal_enabled();
6551#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006552#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006553 else if (STRICMP(name, "conpty") == 0)
6554 n = use_conpty();
6555#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006556#ifdef FEAT_CLIPBOARD
6557 else if (STRICMP(name, "clipboard_working") == 0)
6558 n = clip_star.available;
6559#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 }
6561
6562 rettv->vval.v_number = n;
6563}
6564
6565/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006566 * "haslocaldir()" function
6567 */
6568 static void
6569f_haslocaldir(typval_T *argvars, typval_T *rettv)
6570{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006571 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006572 win_T *wp = NULL;
6573
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006574 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6575
6576 // Check for window-local and tab-local directories
6577 if (wp != NULL && wp->w_localdir != NULL)
6578 rettv->vval.v_number = 1;
6579 else if (tp != NULL && tp->tp_localdir != NULL)
6580 rettv->vval.v_number = 2;
6581 else
6582 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583}
6584
6585/*
6586 * "hasmapto()" function
6587 */
6588 static void
6589f_hasmapto(typval_T *argvars, typval_T *rettv)
6590{
6591 char_u *name;
6592 char_u *mode;
6593 char_u buf[NUMBUFLEN];
6594 int abbr = FALSE;
6595
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006596 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006597 if (argvars[1].v_type == VAR_UNKNOWN)
6598 mode = (char_u *)"nvo";
6599 else
6600 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006601 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006603 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006604 }
6605
6606 if (map_to_exists(name, mode, abbr))
6607 rettv->vval.v_number = TRUE;
6608 else
6609 rettv->vval.v_number = FALSE;
6610}
6611
6612/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006613 * "highlightID(name)" function
6614 */
6615 static void
6616f_hlID(typval_T *argvars, typval_T *rettv)
6617{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006618 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006619}
6620
6621/*
6622 * "highlight_exists()" function
6623 */
6624 static void
6625f_hlexists(typval_T *argvars, typval_T *rettv)
6626{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006627 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006628}
6629
6630/*
6631 * "hostname()" function
6632 */
6633 static void
6634f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6635{
6636 char_u hostname[256];
6637
6638 mch_get_host_name(hostname, 256);
6639 rettv->v_type = VAR_STRING;
6640 rettv->vval.v_string = vim_strsave(hostname);
6641}
6642
6643/*
6644 * iconv() function
6645 */
6646 static void
6647f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6648{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006649 char_u buf1[NUMBUFLEN];
6650 char_u buf2[NUMBUFLEN];
6651 char_u *from, *to, *str;
6652 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006653
6654 rettv->v_type = VAR_STRING;
6655 rettv->vval.v_string = NULL;
6656
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006657 str = tv_get_string(&argvars[0]);
6658 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6659 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006660 vimconv.vc_type = CONV_NONE;
6661 convert_setup(&vimconv, from, to);
6662
6663 /* If the encodings are equal, no conversion needed. */
6664 if (vimconv.vc_type == CONV_NONE)
6665 rettv->vval.v_string = vim_strsave(str);
6666 else
6667 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6668
6669 convert_setup(&vimconv, NULL, NULL);
6670 vim_free(from);
6671 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006672}
6673
6674/*
6675 * "indent()" function
6676 */
6677 static void
6678f_indent(typval_T *argvars, typval_T *rettv)
6679{
6680 linenr_T lnum;
6681
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006682 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6684 rettv->vval.v_number = get_indent_lnum(lnum);
6685 else
6686 rettv->vval.v_number = -1;
6687}
6688
6689/*
6690 * "index()" function
6691 */
6692 static void
6693f_index(typval_T *argvars, typval_T *rettv)
6694{
6695 list_T *l;
6696 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006697 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006698 long idx = 0;
6699 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006700 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701
6702 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006703 if (argvars[0].v_type == VAR_BLOB)
6704 {
6705 typval_T tv;
6706 int start = 0;
6707
6708 if (argvars[2].v_type != VAR_UNKNOWN)
6709 {
6710 start = tv_get_number_chk(&argvars[2], &error);
6711 if (error)
6712 return;
6713 }
6714 b = argvars[0].vval.v_blob;
6715 if (b == NULL)
6716 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006717 if (start < 0)
6718 {
6719 start = blob_len(b) + start;
6720 if (start < 0)
6721 start = 0;
6722 }
6723
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006724 for (idx = start; idx < blob_len(b); ++idx)
6725 {
6726 tv.v_type = VAR_NUMBER;
6727 tv.vval.v_number = blob_get(b, idx);
6728 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6729 {
6730 rettv->vval.v_number = idx;
6731 return;
6732 }
6733 }
6734 return;
6735 }
6736 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006738 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 return;
6740 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742 l = argvars[0].vval.v_list;
6743 if (l != NULL)
6744 {
6745 item = l->lv_first;
6746 if (argvars[2].v_type != VAR_UNKNOWN)
6747 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006748 /* Start at specified item. Use the cached index that list_find()
6749 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006750 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006751 idx = l->lv_idx;
6752 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006753 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006754 if (error)
6755 item = NULL;
6756 }
6757
6758 for ( ; item != NULL; item = item->li_next, ++idx)
6759 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6760 {
6761 rettv->vval.v_number = idx;
6762 break;
6763 }
6764 }
6765}
6766
6767static int inputsecret_flag = 0;
6768
6769/*
6770 * "input()" function
6771 * Also handles inputsecret() when inputsecret is set.
6772 */
6773 static void
6774f_input(typval_T *argvars, typval_T *rettv)
6775{
6776 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6777}
6778
6779/*
6780 * "inputdialog()" function
6781 */
6782 static void
6783f_inputdialog(typval_T *argvars, typval_T *rettv)
6784{
6785#if defined(FEAT_GUI_TEXTDIALOG)
6786 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6787 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6788 {
6789 char_u *message;
6790 char_u buf[NUMBUFLEN];
6791 char_u *defstr = (char_u *)"";
6792
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006793 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006795 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6797 else
6798 IObuff[0] = NUL;
6799 if (message != NULL && defstr != NULL
6800 && do_dialog(VIM_QUESTION, NULL, message,
6801 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6802 rettv->vval.v_string = vim_strsave(IObuff);
6803 else
6804 {
6805 if (message != NULL && defstr != NULL
6806 && argvars[1].v_type != VAR_UNKNOWN
6807 && argvars[2].v_type != VAR_UNKNOWN)
6808 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006809 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006810 else
6811 rettv->vval.v_string = NULL;
6812 }
6813 rettv->v_type = VAR_STRING;
6814 }
6815 else
6816#endif
6817 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6818}
6819
6820/*
6821 * "inputlist()" function
6822 */
6823 static void
6824f_inputlist(typval_T *argvars, typval_T *rettv)
6825{
6826 listitem_T *li;
6827 int selected;
6828 int mouse_used;
6829
6830#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006831 /* While starting up, there is no place to enter text. When running tests
6832 * with --not-a-term we assume feedkeys() will be used. */
6833 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834 return;
6835#endif
6836 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6837 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006838 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006839 return;
6840 }
6841
6842 msg_start();
6843 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6844 lines_left = Rows; /* avoid more prompt */
6845 msg_scroll = TRUE;
6846 msg_clr_eos();
6847
6848 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6849 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006850 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 msg_putchar('\n');
6852 }
6853
6854 /* Ask for choice. */
6855 selected = prompt_for_number(&mouse_used);
6856 if (mouse_used)
6857 selected -= lines_left;
6858
6859 rettv->vval.v_number = selected;
6860}
6861
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6863
6864/*
6865 * "inputrestore()" function
6866 */
6867 static void
6868f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6869{
6870 if (ga_userinput.ga_len > 0)
6871 {
6872 --ga_userinput.ga_len;
6873 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6874 + ga_userinput.ga_len);
6875 /* default return is zero == OK */
6876 }
6877 else if (p_verbose > 1)
6878 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006879 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 rettv->vval.v_number = 1; /* Failed */
6881 }
6882}
6883
6884/*
6885 * "inputsave()" function
6886 */
6887 static void
6888f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6889{
6890 /* Add an entry to the stack of typeahead storage. */
6891 if (ga_grow(&ga_userinput, 1) == OK)
6892 {
6893 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6894 + ga_userinput.ga_len);
6895 ++ga_userinput.ga_len;
6896 /* default return is zero == OK */
6897 }
6898 else
6899 rettv->vval.v_number = 1; /* Failed */
6900}
6901
6902/*
6903 * "inputsecret()" function
6904 */
6905 static void
6906f_inputsecret(typval_T *argvars, typval_T *rettv)
6907{
6908 ++cmdline_star;
6909 ++inputsecret_flag;
6910 f_input(argvars, rettv);
6911 --cmdline_star;
6912 --inputsecret_flag;
6913}
6914
6915/*
6916 * "insert()" function
6917 */
6918 static void
6919f_insert(typval_T *argvars, typval_T *rettv)
6920{
6921 long before = 0;
6922 listitem_T *item;
6923 list_T *l;
6924 int error = FALSE;
6925
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006926 if (argvars[0].v_type == VAR_BLOB)
6927 {
6928 int val, len;
6929 char_u *p;
6930
6931 len = blob_len(argvars[0].vval.v_blob);
6932 if (argvars[2].v_type != VAR_UNKNOWN)
6933 {
6934 before = (long)tv_get_number_chk(&argvars[2], &error);
6935 if (error)
6936 return; // type error; errmsg already given
6937 if (before < 0 || before > len)
6938 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006939 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006940 return;
6941 }
6942 }
6943 val = tv_get_number_chk(&argvars[1], &error);
6944 if (error)
6945 return;
6946 if (val < 0 || val > 255)
6947 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006948 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006949 return;
6950 }
6951
6952 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6953 return;
6954 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6955 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6956 *(p + before) = val;
6957 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6958
6959 copy_tv(&argvars[0], rettv);
6960 }
6961 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006962 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006963 else if ((l = argvars[0].vval.v_list) != NULL
6964 && !var_check_lock(l->lv_lock,
6965 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 {
6967 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006968 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006969 if (error)
6970 return; /* type error; errmsg already given */
6971
6972 if (before == l->lv_len)
6973 item = NULL;
6974 else
6975 {
6976 item = list_find(l, before);
6977 if (item == NULL)
6978 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006979 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006980 l = NULL;
6981 }
6982 }
6983 if (l != NULL)
6984 {
6985 list_insert_tv(l, &argvars[1], item);
6986 copy_tv(&argvars[0], rettv);
6987 }
6988 }
6989}
6990
6991/*
6992 * "invert(expr)" function
6993 */
6994 static void
6995f_invert(typval_T *argvars, typval_T *rettv)
6996{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006997 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006998}
6999
7000/*
7001 * "isdirectory()" function
7002 */
7003 static void
7004f_isdirectory(typval_T *argvars, typval_T *rettv)
7005{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007006 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007007}
7008
7009/*
7010 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7011 * or it refers to a List or Dictionary that is locked.
7012 */
7013 static int
7014tv_islocked(typval_T *tv)
7015{
7016 return (tv->v_lock & VAR_LOCKED)
7017 || (tv->v_type == VAR_LIST
7018 && tv->vval.v_list != NULL
7019 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7020 || (tv->v_type == VAR_DICT
7021 && tv->vval.v_dict != NULL
7022 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7023}
7024
7025/*
7026 * "islocked()" function
7027 */
7028 static void
7029f_islocked(typval_T *argvars, typval_T *rettv)
7030{
7031 lval_T lv;
7032 char_u *end;
7033 dictitem_T *di;
7034
7035 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007036 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007037 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038 if (end != NULL && lv.ll_name != NULL)
7039 {
7040 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007041 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007042 else
7043 {
7044 if (lv.ll_tv == NULL)
7045 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007046 di = find_var(lv.ll_name, NULL, TRUE);
7047 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007049 /* Consider a variable locked when:
7050 * 1. the variable itself is locked
7051 * 2. the value of the variable is locked.
7052 * 3. the List or Dict value is locked.
7053 */
7054 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7055 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007056 }
7057 }
7058 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007059 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007060 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007061 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 else if (lv.ll_list != NULL)
7063 /* List item. */
7064 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7065 else
7066 /* Dictionary item. */
7067 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7068 }
7069 }
7070
7071 clear_lval(&lv);
7072}
7073
7074#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7075/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007076 * "isinf()" function
7077 */
7078 static void
7079f_isinf(typval_T *argvars, typval_T *rettv)
7080{
7081 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7082 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7083}
7084
7085/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007086 * "isnan()" function
7087 */
7088 static void
7089f_isnan(typval_T *argvars, typval_T *rettv)
7090{
7091 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7092 && isnan(argvars[0].vval.v_float);
7093}
7094#endif
7095
7096/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007097 * "last_buffer_nr()" function.
7098 */
7099 static void
7100f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7101{
7102 int n = 0;
7103 buf_T *buf;
7104
Bram Moolenaar29323592016-07-24 22:04:11 +02007105 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007106 if (n < buf->b_fnum)
7107 n = buf->b_fnum;
7108
7109 rettv->vval.v_number = n;
7110}
7111
7112/*
7113 * "len()" function
7114 */
7115 static void
7116f_len(typval_T *argvars, typval_T *rettv)
7117{
7118 switch (argvars[0].v_type)
7119 {
7120 case VAR_STRING:
7121 case VAR_NUMBER:
7122 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007123 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007125 case VAR_BLOB:
7126 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7127 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007128 case VAR_LIST:
7129 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7130 break;
7131 case VAR_DICT:
7132 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7133 break;
7134 case VAR_UNKNOWN:
7135 case VAR_SPECIAL:
7136 case VAR_FLOAT:
7137 case VAR_FUNC:
7138 case VAR_PARTIAL:
7139 case VAR_JOB:
7140 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007141 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 break;
7143 }
7144}
7145
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007146 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007147libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148{
7149#ifdef FEAT_LIBCALL
7150 char_u *string_in;
7151 char_u **string_result;
7152 int nr_result;
7153#endif
7154
7155 rettv->v_type = type;
7156 if (type != VAR_NUMBER)
7157 rettv->vval.v_string = NULL;
7158
7159 if (check_restricted() || check_secure())
7160 return;
7161
7162#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007163 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7165 {
7166 string_in = NULL;
7167 if (argvars[2].v_type == VAR_STRING)
7168 string_in = argvars[2].vval.v_string;
7169 if (type == VAR_NUMBER)
7170 string_result = NULL;
7171 else
7172 string_result = &rettv->vval.v_string;
7173 if (mch_libcall(argvars[0].vval.v_string,
7174 argvars[1].vval.v_string,
7175 string_in,
7176 argvars[2].vval.v_number,
7177 string_result,
7178 &nr_result) == OK
7179 && type == VAR_NUMBER)
7180 rettv->vval.v_number = nr_result;
7181 }
7182#endif
7183}
7184
7185/*
7186 * "libcall()" function
7187 */
7188 static void
7189f_libcall(typval_T *argvars, typval_T *rettv)
7190{
7191 libcall_common(argvars, rettv, VAR_STRING);
7192}
7193
7194/*
7195 * "libcallnr()" function
7196 */
7197 static void
7198f_libcallnr(typval_T *argvars, typval_T *rettv)
7199{
7200 libcall_common(argvars, rettv, VAR_NUMBER);
7201}
7202
7203/*
7204 * "line(string)" function
7205 */
7206 static void
7207f_line(typval_T *argvars, typval_T *rettv)
7208{
7209 linenr_T lnum = 0;
7210 pos_T *fp;
7211 int fnum;
7212
7213 fp = var2fpos(&argvars[0], TRUE, &fnum);
7214 if (fp != NULL)
7215 lnum = fp->lnum;
7216 rettv->vval.v_number = lnum;
7217}
7218
7219/*
7220 * "line2byte(lnum)" function
7221 */
7222 static void
7223f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7224{
7225#ifndef FEAT_BYTEOFF
7226 rettv->vval.v_number = -1;
7227#else
7228 linenr_T lnum;
7229
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007230 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007231 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7232 rettv->vval.v_number = -1;
7233 else
7234 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7235 if (rettv->vval.v_number >= 0)
7236 ++rettv->vval.v_number;
7237#endif
7238}
7239
7240/*
7241 * "lispindent(lnum)" function
7242 */
7243 static void
7244f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7245{
7246#ifdef FEAT_LISP
7247 pos_T pos;
7248 linenr_T lnum;
7249
7250 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007251 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007252 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7253 {
7254 curwin->w_cursor.lnum = lnum;
7255 rettv->vval.v_number = get_lisp_indent();
7256 curwin->w_cursor = pos;
7257 }
7258 else
7259#endif
7260 rettv->vval.v_number = -1;
7261}
7262
7263/*
7264 * "localtime()" function
7265 */
7266 static void
7267f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7268{
7269 rettv->vval.v_number = (varnumber_T)time(NULL);
7270}
7271
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007272#ifdef FEAT_FLOAT
7273/*
7274 * "log()" function
7275 */
7276 static void
7277f_log(typval_T *argvars, typval_T *rettv)
7278{
7279 float_T f = 0.0;
7280
7281 rettv->v_type = VAR_FLOAT;
7282 if (get_float_arg(argvars, &f) == OK)
7283 rettv->vval.v_float = log(f);
7284 else
7285 rettv->vval.v_float = 0.0;
7286}
7287
7288/*
7289 * "log10()" function
7290 */
7291 static void
7292f_log10(typval_T *argvars, typval_T *rettv)
7293{
7294 float_T f = 0.0;
7295
7296 rettv->v_type = VAR_FLOAT;
7297 if (get_float_arg(argvars, &f) == OK)
7298 rettv->vval.v_float = log10(f);
7299 else
7300 rettv->vval.v_float = 0.0;
7301}
7302#endif
7303
7304#ifdef FEAT_LUA
7305/*
7306 * "luaeval()" function
7307 */
7308 static void
7309f_luaeval(typval_T *argvars, typval_T *rettv)
7310{
7311 char_u *str;
7312 char_u buf[NUMBUFLEN];
7313
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007314 if (check_restricted() || check_secure())
7315 return;
7316
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007317 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007318 do_luaeval(str, argvars + 1, rettv);
7319}
7320#endif
7321
7322/*
7323 * "map()" function
7324 */
7325 static void
7326f_map(typval_T *argvars, typval_T *rettv)
7327{
7328 filter_map(argvars, rettv, TRUE);
7329}
7330
7331/*
7332 * "maparg()" function
7333 */
7334 static void
7335f_maparg(typval_T *argvars, typval_T *rettv)
7336{
7337 get_maparg(argvars, rettv, TRUE);
7338}
7339
7340/*
7341 * "mapcheck()" function
7342 */
7343 static void
7344f_mapcheck(typval_T *argvars, typval_T *rettv)
7345{
7346 get_maparg(argvars, rettv, FALSE);
7347}
7348
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007349typedef enum
7350{
7351 MATCH_END, /* matchend() */
7352 MATCH_MATCH, /* match() */
7353 MATCH_STR, /* matchstr() */
7354 MATCH_LIST, /* matchlist() */
7355 MATCH_POS /* matchstrpos() */
7356} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007357
7358 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007359find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007360{
7361 char_u *str = NULL;
7362 long len = 0;
7363 char_u *expr = NULL;
7364 char_u *pat;
7365 regmatch_T regmatch;
7366 char_u patbuf[NUMBUFLEN];
7367 char_u strbuf[NUMBUFLEN];
7368 char_u *save_cpo;
7369 long start = 0;
7370 long nth = 1;
7371 colnr_T startcol = 0;
7372 int match = 0;
7373 list_T *l = NULL;
7374 listitem_T *li = NULL;
7375 long idx = 0;
7376 char_u *tofree = NULL;
7377
7378 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7379 save_cpo = p_cpo;
7380 p_cpo = (char_u *)"";
7381
7382 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007383 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007385 /* type MATCH_LIST: return empty list when there are no matches.
7386 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 if (rettv_list_alloc(rettv) == FAIL)
7388 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007389 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007390 && (list_append_string(rettv->vval.v_list,
7391 (char_u *)"", 0) == FAIL
7392 || list_append_number(rettv->vval.v_list,
7393 (varnumber_T)-1) == FAIL
7394 || list_append_number(rettv->vval.v_list,
7395 (varnumber_T)-1) == FAIL
7396 || list_append_number(rettv->vval.v_list,
7397 (varnumber_T)-1) == FAIL))
7398 {
7399 list_free(rettv->vval.v_list);
7400 rettv->vval.v_list = NULL;
7401 goto theend;
7402 }
7403 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007404 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 {
7406 rettv->v_type = VAR_STRING;
7407 rettv->vval.v_string = NULL;
7408 }
7409
7410 if (argvars[0].v_type == VAR_LIST)
7411 {
7412 if ((l = argvars[0].vval.v_list) == NULL)
7413 goto theend;
7414 li = l->lv_first;
7415 }
7416 else
7417 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007418 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007419 len = (long)STRLEN(str);
7420 }
7421
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007422 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 if (pat == NULL)
7424 goto theend;
7425
7426 if (argvars[2].v_type != VAR_UNKNOWN)
7427 {
7428 int error = FALSE;
7429
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007430 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431 if (error)
7432 goto theend;
7433 if (l != NULL)
7434 {
7435 li = list_find(l, start);
7436 if (li == NULL)
7437 goto theend;
7438 idx = l->lv_idx; /* use the cached index */
7439 }
7440 else
7441 {
7442 if (start < 0)
7443 start = 0;
7444 if (start > len)
7445 goto theend;
7446 /* When "count" argument is there ignore matches before "start",
7447 * otherwise skip part of the string. Differs when pattern is "^"
7448 * or "\<". */
7449 if (argvars[3].v_type != VAR_UNKNOWN)
7450 startcol = start;
7451 else
7452 {
7453 str += start;
7454 len -= start;
7455 }
7456 }
7457
7458 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007459 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007460 if (error)
7461 goto theend;
7462 }
7463
7464 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7465 if (regmatch.regprog != NULL)
7466 {
7467 regmatch.rm_ic = p_ic;
7468
7469 for (;;)
7470 {
7471 if (l != NULL)
7472 {
7473 if (li == NULL)
7474 {
7475 match = FALSE;
7476 break;
7477 }
7478 vim_free(tofree);
7479 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7480 if (str == NULL)
7481 break;
7482 }
7483
7484 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7485
7486 if (match && --nth <= 0)
7487 break;
7488 if (l == NULL && !match)
7489 break;
7490
7491 /* Advance to just after the match. */
7492 if (l != NULL)
7493 {
7494 li = li->li_next;
7495 ++idx;
7496 }
7497 else
7498 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007499 startcol = (colnr_T)(regmatch.startp[0]
7500 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501 if (startcol > (colnr_T)len
7502 || str + startcol <= regmatch.startp[0])
7503 {
7504 match = FALSE;
7505 break;
7506 }
7507 }
7508 }
7509
7510 if (match)
7511 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007512 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513 {
7514 listitem_T *li1 = rettv->vval.v_list->lv_first;
7515 listitem_T *li2 = li1->li_next;
7516 listitem_T *li3 = li2->li_next;
7517 listitem_T *li4 = li3->li_next;
7518
7519 vim_free(li1->li_tv.vval.v_string);
7520 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7521 (int)(regmatch.endp[0] - regmatch.startp[0]));
7522 li3->li_tv.vval.v_number =
7523 (varnumber_T)(regmatch.startp[0] - expr);
7524 li4->li_tv.vval.v_number =
7525 (varnumber_T)(regmatch.endp[0] - expr);
7526 if (l != NULL)
7527 li2->li_tv.vval.v_number = (varnumber_T)idx;
7528 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007529 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007530 {
7531 int i;
7532
7533 /* return list with matched string and submatches */
7534 for (i = 0; i < NSUBEXP; ++i)
7535 {
7536 if (regmatch.endp[i] == NULL)
7537 {
7538 if (list_append_string(rettv->vval.v_list,
7539 (char_u *)"", 0) == FAIL)
7540 break;
7541 }
7542 else if (list_append_string(rettv->vval.v_list,
7543 regmatch.startp[i],
7544 (int)(regmatch.endp[i] - regmatch.startp[i]))
7545 == FAIL)
7546 break;
7547 }
7548 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007549 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007550 {
7551 /* return matched string */
7552 if (l != NULL)
7553 copy_tv(&li->li_tv, rettv);
7554 else
7555 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7556 (int)(regmatch.endp[0] - regmatch.startp[0]));
7557 }
7558 else if (l != NULL)
7559 rettv->vval.v_number = idx;
7560 else
7561 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007562 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007563 rettv->vval.v_number =
7564 (varnumber_T)(regmatch.startp[0] - str);
7565 else
7566 rettv->vval.v_number =
7567 (varnumber_T)(regmatch.endp[0] - str);
7568 rettv->vval.v_number += (varnumber_T)(str - expr);
7569 }
7570 }
7571 vim_regfree(regmatch.regprog);
7572 }
7573
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007574theend:
7575 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007576 /* matchstrpos() without a list: drop the second item. */
7577 listitem_remove(rettv->vval.v_list,
7578 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007579 vim_free(tofree);
7580 p_cpo = save_cpo;
7581}
7582
7583/*
7584 * "match()" function
7585 */
7586 static void
7587f_match(typval_T *argvars, typval_T *rettv)
7588{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007589 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590}
7591
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007592/*
7593 * "matchend()" function
7594 */
7595 static void
7596f_matchend(typval_T *argvars, typval_T *rettv)
7597{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007598 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007599}
7600
7601/*
7602 * "matchlist()" function
7603 */
7604 static void
7605f_matchlist(typval_T *argvars, typval_T *rettv)
7606{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007607 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007608}
7609
7610/*
7611 * "matchstr()" function
7612 */
7613 static void
7614f_matchstr(typval_T *argvars, typval_T *rettv)
7615{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007616 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617}
7618
7619/*
7620 * "matchstrpos()" function
7621 */
7622 static void
7623f_matchstrpos(typval_T *argvars, typval_T *rettv)
7624{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007625 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626}
7627
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007628 static void
7629max_min(typval_T *argvars, typval_T *rettv, int domax)
7630{
7631 varnumber_T n = 0;
7632 varnumber_T i;
7633 int error = FALSE;
7634
7635 if (argvars[0].v_type == VAR_LIST)
7636 {
7637 list_T *l;
7638 listitem_T *li;
7639
7640 l = argvars[0].vval.v_list;
7641 if (l != NULL)
7642 {
7643 li = l->lv_first;
7644 if (li != NULL)
7645 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007646 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 for (;;)
7648 {
7649 li = li->li_next;
7650 if (li == NULL)
7651 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007652 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653 if (domax ? i > n : i < n)
7654 n = i;
7655 }
7656 }
7657 }
7658 }
7659 else if (argvars[0].v_type == VAR_DICT)
7660 {
7661 dict_T *d;
7662 int first = TRUE;
7663 hashitem_T *hi;
7664 int todo;
7665
7666 d = argvars[0].vval.v_dict;
7667 if (d != NULL)
7668 {
7669 todo = (int)d->dv_hashtab.ht_used;
7670 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7671 {
7672 if (!HASHITEM_EMPTY(hi))
7673 {
7674 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007675 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007676 if (first)
7677 {
7678 n = i;
7679 first = FALSE;
7680 }
7681 else if (domax ? i > n : i < n)
7682 n = i;
7683 }
7684 }
7685 }
7686 }
7687 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007688 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007689 rettv->vval.v_number = error ? 0 : n;
7690}
7691
7692/*
7693 * "max()" function
7694 */
7695 static void
7696f_max(typval_T *argvars, typval_T *rettv)
7697{
7698 max_min(argvars, rettv, TRUE);
7699}
7700
7701/*
7702 * "min()" function
7703 */
7704 static void
7705f_min(typval_T *argvars, typval_T *rettv)
7706{
7707 max_min(argvars, rettv, FALSE);
7708}
7709
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007710/*
7711 * Create the directory in which "dir" is located, and higher levels when
7712 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007713 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714 */
7715 static int
7716mkdir_recurse(char_u *dir, int prot)
7717{
7718 char_u *p;
7719 char_u *updir;
7720 int r = FAIL;
7721
7722 /* Get end of directory name in "dir".
7723 * We're done when it's "/" or "c:/". */
7724 p = gettail_sep(dir);
7725 if (p <= get_past_head(dir))
7726 return OK;
7727
7728 /* If the directory exists we're done. Otherwise: create it.*/
7729 updir = vim_strnsave(dir, (int)(p - dir));
7730 if (updir == NULL)
7731 return FAIL;
7732 if (mch_isdir(updir))
7733 r = OK;
7734 else if (mkdir_recurse(updir, prot) == OK)
7735 r = vim_mkdir_emsg(updir, prot);
7736 vim_free(updir);
7737 return r;
7738}
7739
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007740/*
7741 * "mkdir()" function
7742 */
7743 static void
7744f_mkdir(typval_T *argvars, typval_T *rettv)
7745{
7746 char_u *dir;
7747 char_u buf[NUMBUFLEN];
7748 int prot = 0755;
7749
7750 rettv->vval.v_number = FAIL;
7751 if (check_restricted() || check_secure())
7752 return;
7753
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007754 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007755 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007756 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007757
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007758 if (*gettail(dir) == NUL)
7759 /* remove trailing slashes */
7760 *gettail_sep(dir) = NUL;
7761
7762 if (argvars[1].v_type != VAR_UNKNOWN)
7763 {
7764 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007766 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007767 if (prot == -1)
7768 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007769 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007770 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007771 {
7772 if (mch_isdir(dir))
7773 {
7774 /* With the "p" flag it's OK if the dir already exists. */
7775 rettv->vval.v_number = OK;
7776 return;
7777 }
7778 mkdir_recurse(dir, prot);
7779 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007781 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007782}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007783
7784/*
7785 * "mode()" function
7786 */
7787 static void
7788f_mode(typval_T *argvars, typval_T *rettv)
7789{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007790 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007791
Bram Moolenaar612cc382018-07-29 15:34:26 +02007792 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007793
7794 if (time_for_testing == 93784)
7795 {
7796 /* Testing the two-character code. */
7797 buf[0] = 'x';
7798 buf[1] = '!';
7799 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007800#ifdef FEAT_TERMINAL
7801 else if (term_use_loop())
7802 buf[0] = 't';
7803#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007804 else if (VIsual_active)
7805 {
7806 if (VIsual_select)
7807 buf[0] = VIsual_mode + 's' - 'v';
7808 else
7809 buf[0] = VIsual_mode;
7810 }
7811 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7812 || State == CONFIRM)
7813 {
7814 buf[0] = 'r';
7815 if (State == ASKMORE)
7816 buf[1] = 'm';
7817 else if (State == CONFIRM)
7818 buf[1] = '?';
7819 }
7820 else if (State == EXTERNCMD)
7821 buf[0] = '!';
7822 else if (State & INSERT)
7823 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007824 if (State & VREPLACE_FLAG)
7825 {
7826 buf[0] = 'R';
7827 buf[1] = 'v';
7828 }
7829 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007830 {
7831 if (State & REPLACE_FLAG)
7832 buf[0] = 'R';
7833 else
7834 buf[0] = 'i';
7835#ifdef FEAT_INS_EXPAND
7836 if (ins_compl_active())
7837 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007838 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007839 buf[1] = 'x';
7840#endif
7841 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007842 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007843 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007844 {
7845 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007846 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007847 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007848 else if (exmode_active == EXMODE_NORMAL)
7849 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007850 }
7851 else
7852 {
7853 buf[0] = 'n';
7854 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007855 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007857 // to be able to detect force-linewise/blockwise/characterwise operations
7858 buf[2] = motion_force;
7859 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007860 else if (restart_edit == 'I' || restart_edit == 'R'
7861 || restart_edit == 'V')
7862 {
7863 buf[1] = 'i';
7864 buf[2] = restart_edit;
7865 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 }
7867
7868 /* Clear out the minor mode when the argument is not a non-zero number or
7869 * non-empty string. */
7870 if (!non_zero_arg(&argvars[0]))
7871 buf[1] = NUL;
7872
7873 rettv->vval.v_string = vim_strsave(buf);
7874 rettv->v_type = VAR_STRING;
7875}
7876
7877#if defined(FEAT_MZSCHEME) || defined(PROTO)
7878/*
7879 * "mzeval()" function
7880 */
7881 static void
7882f_mzeval(typval_T *argvars, typval_T *rettv)
7883{
7884 char_u *str;
7885 char_u buf[NUMBUFLEN];
7886
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007887 if (check_restricted() || check_secure())
7888 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007889 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 do_mzeval(str, rettv);
7891}
7892
7893 void
7894mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7895{
7896 typval_T argvars[3];
7897
7898 argvars[0].v_type = VAR_STRING;
7899 argvars[0].vval.v_string = name;
7900 copy_tv(args, &argvars[1]);
7901 argvars[2].v_type = VAR_UNKNOWN;
7902 f_call(argvars, rettv);
7903 clear_tv(&argvars[1]);
7904}
7905#endif
7906
7907/*
7908 * "nextnonblank()" function
7909 */
7910 static void
7911f_nextnonblank(typval_T *argvars, typval_T *rettv)
7912{
7913 linenr_T lnum;
7914
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007915 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007916 {
7917 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7918 {
7919 lnum = 0;
7920 break;
7921 }
7922 if (*skipwhite(ml_get(lnum)) != NUL)
7923 break;
7924 }
7925 rettv->vval.v_number = lnum;
7926}
7927
7928/*
7929 * "nr2char()" function
7930 */
7931 static void
7932f_nr2char(typval_T *argvars, typval_T *rettv)
7933{
7934 char_u buf[NUMBUFLEN];
7935
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 if (has_mbyte)
7937 {
7938 int utf8 = 0;
7939
7940 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007941 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007943 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007944 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007945 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007946 }
7947 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007948 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007949 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950 buf[1] = NUL;
7951 }
7952 rettv->v_type = VAR_STRING;
7953 rettv->vval.v_string = vim_strsave(buf);
7954}
7955
7956/*
7957 * "or(expr, expr)" function
7958 */
7959 static void
7960f_or(typval_T *argvars, typval_T *rettv)
7961{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007962 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7963 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007964}
7965
7966/*
7967 * "pathshorten()" function
7968 */
7969 static void
7970f_pathshorten(typval_T *argvars, typval_T *rettv)
7971{
7972 char_u *p;
7973
7974 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007975 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976 if (p == NULL)
7977 rettv->vval.v_string = NULL;
7978 else
7979 {
7980 p = vim_strsave(p);
7981 rettv->vval.v_string = p;
7982 if (p != NULL)
7983 shorten_dir(p);
7984 }
7985}
7986
7987#ifdef FEAT_PERL
7988/*
7989 * "perleval()" function
7990 */
7991 static void
7992f_perleval(typval_T *argvars, typval_T *rettv)
7993{
7994 char_u *str;
7995 char_u buf[NUMBUFLEN];
7996
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007997 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007998 do_perleval(str, rettv);
7999}
8000#endif
8001
8002#ifdef FEAT_FLOAT
8003/*
8004 * "pow()" function
8005 */
8006 static void
8007f_pow(typval_T *argvars, typval_T *rettv)
8008{
8009 float_T fx = 0.0, fy = 0.0;
8010
8011 rettv->v_type = VAR_FLOAT;
8012 if (get_float_arg(argvars, &fx) == OK
8013 && get_float_arg(&argvars[1], &fy) == OK)
8014 rettv->vval.v_float = pow(fx, fy);
8015 else
8016 rettv->vval.v_float = 0.0;
8017}
8018#endif
8019
8020/*
8021 * "prevnonblank()" function
8022 */
8023 static void
8024f_prevnonblank(typval_T *argvars, typval_T *rettv)
8025{
8026 linenr_T lnum;
8027
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008028 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8030 lnum = 0;
8031 else
8032 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8033 --lnum;
8034 rettv->vval.v_number = lnum;
8035}
8036
8037/* This dummy va_list is here because:
8038 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8039 * - locally in the function results in a "used before set" warning
8040 * - using va_start() to initialize it gives "function with fixed args" error */
8041static va_list ap;
8042
8043/*
8044 * "printf()" function
8045 */
8046 static void
8047f_printf(typval_T *argvars, typval_T *rettv)
8048{
8049 char_u buf[NUMBUFLEN];
8050 int len;
8051 char_u *s;
8052 int saved_did_emsg = did_emsg;
8053 char *fmt;
8054
8055 rettv->v_type = VAR_STRING;
8056 rettv->vval.v_string = NULL;
8057
8058 /* Get the required length, allocate the buffer and do it for real. */
8059 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008060 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008061 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008062 if (!did_emsg)
8063 {
8064 s = alloc(len + 1);
8065 if (s != NULL)
8066 {
8067 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008068 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8069 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070 }
8071 }
8072 did_emsg |= saved_did_emsg;
8073}
8074
8075/*
8076 * "pumvisible()" function
8077 */
8078 static void
8079f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8080{
8081#ifdef FEAT_INS_EXPAND
8082 if (pum_visible())
8083 rettv->vval.v_number = 1;
8084#endif
8085}
8086
8087#ifdef FEAT_PYTHON3
8088/*
8089 * "py3eval()" function
8090 */
8091 static void
8092f_py3eval(typval_T *argvars, typval_T *rettv)
8093{
8094 char_u *str;
8095 char_u buf[NUMBUFLEN];
8096
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008097 if (check_restricted() || check_secure())
8098 return;
8099
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008100 if (p_pyx == 0)
8101 p_pyx = 3;
8102
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008103 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008104 do_py3eval(str, rettv);
8105}
8106#endif
8107
8108#ifdef FEAT_PYTHON
8109/*
8110 * "pyeval()" function
8111 */
8112 static void
8113f_pyeval(typval_T *argvars, typval_T *rettv)
8114{
8115 char_u *str;
8116 char_u buf[NUMBUFLEN];
8117
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008118 if (check_restricted() || check_secure())
8119 return;
8120
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008121 if (p_pyx == 0)
8122 p_pyx = 2;
8123
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008124 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008125 do_pyeval(str, rettv);
8126}
8127#endif
8128
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008129#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8130/*
8131 * "pyxeval()" function
8132 */
8133 static void
8134f_pyxeval(typval_T *argvars, typval_T *rettv)
8135{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008136 if (check_restricted() || check_secure())
8137 return;
8138
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008139# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8140 init_pyxversion();
8141 if (p_pyx == 2)
8142 f_pyeval(argvars, rettv);
8143 else
8144 f_py3eval(argvars, rettv);
8145# elif defined(FEAT_PYTHON)
8146 f_pyeval(argvars, rettv);
8147# elif defined(FEAT_PYTHON3)
8148 f_py3eval(argvars, rettv);
8149# endif
8150}
8151#endif
8152
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153/*
8154 * "range()" function
8155 */
8156 static void
8157f_range(typval_T *argvars, typval_T *rettv)
8158{
8159 varnumber_T start;
8160 varnumber_T end;
8161 varnumber_T stride = 1;
8162 varnumber_T i;
8163 int error = FALSE;
8164
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008165 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008166 if (argvars[1].v_type == VAR_UNKNOWN)
8167 {
8168 end = start - 1;
8169 start = 0;
8170 }
8171 else
8172 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008173 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008175 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 }
8177
8178 if (error)
8179 return; /* type error; errmsg already given */
8180 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008181 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008183 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 else
8185 {
8186 if (rettv_list_alloc(rettv) == OK)
8187 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8188 if (list_append_number(rettv->vval.v_list,
8189 (varnumber_T)i) == FAIL)
8190 break;
8191 }
8192}
8193
8194/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008195 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008196 */
8197 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008198readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008199{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008200 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008201 typval_T save_val;
8202 typval_T rettv;
8203 typval_T argv[2];
8204 int retval = 0;
8205 int error = FALSE;
8206
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008207 if (expr->v_type == VAR_UNKNOWN)
8208 return 1;
8209
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008210 prepare_vimvar(VV_VAL, &save_val);
8211 set_vim_var_string(VV_VAL, name, -1);
8212 argv[0].v_type = VAR_STRING;
8213 argv[0].vval.v_string = name;
8214
8215 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8216 goto theend;
8217
8218 retval = tv_get_number_chk(&rettv, &error);
8219 if (error)
8220 retval = -1;
8221 clear_tv(&rettv);
8222
8223theend:
8224 set_vim_var_string(VV_VAL, NULL, 0);
8225 restore_vimvar(VV_VAL, &save_val);
8226 return retval;
8227}
8228
8229/*
8230 * "readdir()" function
8231 */
8232 static void
8233f_readdir(typval_T *argvars, typval_T *rettv)
8234{
8235 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008236 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008237 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008238 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008239 garray_T ga;
8240 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008241
8242 if (rettv_list_alloc(rettv) == FAIL)
8243 return;
8244 path = tv_get_string(&argvars[0]);
8245 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008246
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008247 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8248 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008249 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008250 for (i = 0; i < ga.ga_len; i++)
8251 {
8252 p = ((char_u **)ga.ga_data)[i];
8253 list_append_string(rettv->vval.v_list, p, -1);
8254 }
8255 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008256 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008257}
8258
8259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008260 * "readfile()" function
8261 */
8262 static void
8263f_readfile(typval_T *argvars, typval_T *rettv)
8264{
8265 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008266 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008267 int failed = FALSE;
8268 char_u *fname;
8269 FILE *fd;
8270 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8271 int io_size = sizeof(buf);
8272 int readlen; /* size of last fread() */
8273 char_u *prev = NULL; /* previously read bytes, if any */
8274 long prevlen = 0; /* length of data in prev */
8275 long prevsize = 0; /* size of prev buffer */
8276 long maxline = MAXLNUM;
8277 long cnt = 0;
8278 char_u *p; /* position in buf */
8279 char_u *start; /* start of current line */
8280
8281 if (argvars[1].v_type != VAR_UNKNOWN)
8282 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008283 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008284 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008285 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8286 blob = TRUE;
8287
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008288 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008289 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008290 }
8291
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008292 if (blob)
8293 {
8294 if (rettv_blob_alloc(rettv) == FAIL)
8295 return;
8296 }
8297 else
8298 {
8299 if (rettv_list_alloc(rettv) == FAIL)
8300 return;
8301 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302
8303 /* Always open the file in binary mode, library functions have a mind of
8304 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008305 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008306 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8307 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008308 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008309 return;
8310 }
8311
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008312 if (blob)
8313 {
8314 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8315 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008316 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008317 blob_free(rettv->vval.v_blob);
8318 }
8319 fclose(fd);
8320 return;
8321 }
8322
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008323 while (cnt < maxline || maxline < 0)
8324 {
8325 readlen = (int)fread(buf, 1, io_size, fd);
8326
8327 /* This for loop processes what was read, but is also entered at end
8328 * of file so that either:
8329 * - an incomplete line gets written
8330 * - a "binary" file gets an empty line at the end if it ends in a
8331 * newline. */
8332 for (p = buf, start = buf;
8333 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8334 ++p)
8335 {
8336 if (*p == '\n' || readlen <= 0)
8337 {
8338 listitem_T *li;
8339 char_u *s = NULL;
8340 long_u len = p - start;
8341
8342 /* Finished a line. Remove CRs before NL. */
8343 if (readlen > 0 && !binary)
8344 {
8345 while (len > 0 && start[len - 1] == '\r')
8346 --len;
8347 /* removal may cross back to the "prev" string */
8348 if (len == 0)
8349 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8350 --prevlen;
8351 }
8352 if (prevlen == 0)
8353 s = vim_strnsave(start, (int)len);
8354 else
8355 {
8356 /* Change "prev" buffer to be the right size. This way
8357 * the bytes are only copied once, and very long lines are
8358 * allocated only once. */
8359 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8360 {
8361 mch_memmove(s + prevlen, start, len);
8362 s[prevlen + len] = NUL;
8363 prev = NULL; /* the list will own the string */
8364 prevlen = prevsize = 0;
8365 }
8366 }
8367 if (s == NULL)
8368 {
8369 do_outofmem_msg((long_u) prevlen + len + 1);
8370 failed = TRUE;
8371 break;
8372 }
8373
8374 if ((li = listitem_alloc()) == NULL)
8375 {
8376 vim_free(s);
8377 failed = TRUE;
8378 break;
8379 }
8380 li->li_tv.v_type = VAR_STRING;
8381 li->li_tv.v_lock = 0;
8382 li->li_tv.vval.v_string = s;
8383 list_append(rettv->vval.v_list, li);
8384
8385 start = p + 1; /* step over newline */
8386 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8387 break;
8388 }
8389 else if (*p == NUL)
8390 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008391 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8392 * when finding the BF and check the previous two bytes. */
8393 else if (*p == 0xbf && enc_utf8 && !binary)
8394 {
8395 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8396 * + 1, these may be in the "prev" string. */
8397 char_u back1 = p >= buf + 1 ? p[-1]
8398 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8399 char_u back2 = p >= buf + 2 ? p[-2]
8400 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8401 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8402
8403 if (back2 == 0xef && back1 == 0xbb)
8404 {
8405 char_u *dest = p - 2;
8406
8407 /* Usually a BOM is at the beginning of a file, and so at
8408 * the beginning of a line; then we can just step over it.
8409 */
8410 if (start == dest)
8411 start = p + 1;
8412 else
8413 {
8414 /* have to shuffle buf to close gap */
8415 int adjust_prevlen = 0;
8416
8417 if (dest < buf)
8418 {
8419 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8420 dest = buf;
8421 }
8422 if (readlen > p - buf + 1)
8423 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8424 readlen -= 3 - adjust_prevlen;
8425 prevlen -= adjust_prevlen;
8426 p = dest - 1;
8427 }
8428 }
8429 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008430 } /* for */
8431
8432 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8433 break;
8434 if (start < p)
8435 {
8436 /* There's part of a line in buf, store it in "prev". */
8437 if (p - start + prevlen >= prevsize)
8438 {
8439 /* need bigger "prev" buffer */
8440 char_u *newprev;
8441
8442 /* A common use case is ordinary text files and "prev" gets a
8443 * fragment of a line, so the first allocation is made
8444 * small, to avoid repeatedly 'allocing' large and
8445 * 'reallocing' small. */
8446 if (prevsize == 0)
8447 prevsize = (long)(p - start);
8448 else
8449 {
8450 long grow50pc = (prevsize * 3) / 2;
8451 long growmin = (long)((p - start) * 2 + prevlen);
8452 prevsize = grow50pc > growmin ? grow50pc : growmin;
8453 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008454 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008455 if (newprev == NULL)
8456 {
8457 do_outofmem_msg((long_u)prevsize);
8458 failed = TRUE;
8459 break;
8460 }
8461 prev = newprev;
8462 }
8463 /* Add the line part to end of "prev". */
8464 mch_memmove(prev + prevlen, start, p - start);
8465 prevlen += (long)(p - start);
8466 }
8467 } /* while */
8468
8469 /*
8470 * For a negative line count use only the lines at the end of the file,
8471 * free the rest.
8472 */
8473 if (!failed && maxline < 0)
8474 while (cnt > -maxline)
8475 {
8476 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8477 --cnt;
8478 }
8479
8480 if (failed)
8481 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008482 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008483 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008484 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008485 }
8486
8487 vim_free(prev);
8488 fclose(fd);
8489}
8490
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008491 static void
8492return_register(int regname, typval_T *rettv)
8493{
8494 char_u buf[2] = {0, 0};
8495
8496 buf[0] = (char_u)regname;
8497 rettv->v_type = VAR_STRING;
8498 rettv->vval.v_string = vim_strsave(buf);
8499}
8500
8501/*
8502 * "reg_executing()" function
8503 */
8504 static void
8505f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8506{
8507 return_register(reg_executing, rettv);
8508}
8509
8510/*
8511 * "reg_recording()" function
8512 */
8513 static void
8514f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8515{
8516 return_register(reg_recording, rettv);
8517}
8518
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008519#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008520/*
8521 * Convert a List to proftime_T.
8522 * Return FAIL when there is something wrong.
8523 */
8524 static int
8525list2proftime(typval_T *arg, proftime_T *tm)
8526{
8527 long n1, n2;
8528 int error = FALSE;
8529
8530 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8531 || arg->vval.v_list->lv_len != 2)
8532 return FAIL;
8533 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8534 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008535# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008536 tm->HighPart = n1;
8537 tm->LowPart = n2;
8538# else
8539 tm->tv_sec = n1;
8540 tm->tv_usec = n2;
8541# endif
8542 return error ? FAIL : OK;
8543}
8544#endif /* FEAT_RELTIME */
8545
8546/*
8547 * "reltime()" function
8548 */
8549 static void
8550f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8551{
8552#ifdef FEAT_RELTIME
8553 proftime_T res;
8554 proftime_T start;
8555
8556 if (argvars[0].v_type == VAR_UNKNOWN)
8557 {
8558 /* No arguments: get current time. */
8559 profile_start(&res);
8560 }
8561 else if (argvars[1].v_type == VAR_UNKNOWN)
8562 {
8563 if (list2proftime(&argvars[0], &res) == FAIL)
8564 return;
8565 profile_end(&res);
8566 }
8567 else
8568 {
8569 /* Two arguments: compute the difference. */
8570 if (list2proftime(&argvars[0], &start) == FAIL
8571 || list2proftime(&argvars[1], &res) == FAIL)
8572 return;
8573 profile_sub(&res, &start);
8574 }
8575
8576 if (rettv_list_alloc(rettv) == OK)
8577 {
8578 long n1, n2;
8579
Bram Moolenaar4f974752019-02-17 17:44:42 +01008580# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008581 n1 = res.HighPart;
8582 n2 = res.LowPart;
8583# else
8584 n1 = res.tv_sec;
8585 n2 = res.tv_usec;
8586# endif
8587 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8588 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8589 }
8590#endif
8591}
8592
8593#ifdef FEAT_FLOAT
8594/*
8595 * "reltimefloat()" function
8596 */
8597 static void
8598f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8599{
8600# ifdef FEAT_RELTIME
8601 proftime_T tm;
8602# endif
8603
8604 rettv->v_type = VAR_FLOAT;
8605 rettv->vval.v_float = 0;
8606# ifdef FEAT_RELTIME
8607 if (list2proftime(&argvars[0], &tm) == OK)
8608 rettv->vval.v_float = profile_float(&tm);
8609# endif
8610}
8611#endif
8612
8613/*
8614 * "reltimestr()" function
8615 */
8616 static void
8617f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8618{
8619#ifdef FEAT_RELTIME
8620 proftime_T tm;
8621#endif
8622
8623 rettv->v_type = VAR_STRING;
8624 rettv->vval.v_string = NULL;
8625#ifdef FEAT_RELTIME
8626 if (list2proftime(&argvars[0], &tm) == OK)
8627 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8628#endif
8629}
8630
8631#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008632 static void
8633make_connection(void)
8634{
8635 if (X_DISPLAY == NULL
8636# ifdef FEAT_GUI
8637 && !gui.in_use
8638# endif
8639 )
8640 {
8641 x_force_connect = TRUE;
8642 setup_term_clip();
8643 x_force_connect = FALSE;
8644 }
8645}
8646
8647 static int
8648check_connection(void)
8649{
8650 make_connection();
8651 if (X_DISPLAY == NULL)
8652 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008653 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008654 return FAIL;
8655 }
8656 return OK;
8657}
8658#endif
8659
8660#ifdef FEAT_CLIENTSERVER
8661 static void
8662remote_common(typval_T *argvars, typval_T *rettv, int expr)
8663{
8664 char_u *server_name;
8665 char_u *keys;
8666 char_u *r = NULL;
8667 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008668 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008669# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008670 HWND w;
8671# else
8672 Window w;
8673# endif
8674
8675 if (check_restricted() || check_secure())
8676 return;
8677
8678# ifdef FEAT_X11
8679 if (check_connection() == FAIL)
8680 return;
8681# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008682 if (argvars[2].v_type != VAR_UNKNOWN
8683 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008684 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008685
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008686 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008687 if (server_name == NULL)
8688 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008689 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008690# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008691 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008692# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008693 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8694 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008695# endif
8696 {
8697 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008698 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008699 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008700 vim_free(r);
8701 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008702 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008703 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008704 return;
8705 }
8706
8707 rettv->vval.v_string = r;
8708
8709 if (argvars[2].v_type != VAR_UNKNOWN)
8710 {
8711 dictitem_T v;
8712 char_u str[30];
8713 char_u *idvar;
8714
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008715 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008716 if (idvar != NULL && *idvar != NUL)
8717 {
8718 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8719 v.di_tv.v_type = VAR_STRING;
8720 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008722 vim_free(v.di_tv.vval.v_string);
8723 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724 }
8725}
8726#endif
8727
8728/*
8729 * "remote_expr()" function
8730 */
8731 static void
8732f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8733{
8734 rettv->v_type = VAR_STRING;
8735 rettv->vval.v_string = NULL;
8736#ifdef FEAT_CLIENTSERVER
8737 remote_common(argvars, rettv, TRUE);
8738#endif
8739}
8740
8741/*
8742 * "remote_foreground()" function
8743 */
8744 static void
8745f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8746{
8747#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008748# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008749 /* On Win32 it's done in this application. */
8750 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008751 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008752
8753 if (server_name != NULL)
8754 serverForeground(server_name);
8755 }
8756# else
8757 /* Send a foreground() expression to the server. */
8758 argvars[1].v_type = VAR_STRING;
8759 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8760 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008761 rettv->v_type = VAR_STRING;
8762 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008763 remote_common(argvars, rettv, TRUE);
8764 vim_free(argvars[1].vval.v_string);
8765# endif
8766#endif
8767}
8768
8769 static void
8770f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8771{
8772#ifdef FEAT_CLIENTSERVER
8773 dictitem_T v;
8774 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008775# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008776 long_u n = 0;
8777# endif
8778 char_u *serverid;
8779
8780 if (check_restricted() || check_secure())
8781 {
8782 rettv->vval.v_number = -1;
8783 return;
8784 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008785 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008786 if (serverid == NULL)
8787 {
8788 rettv->vval.v_number = -1;
8789 return; /* type error; errmsg already given */
8790 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008791# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008792 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8793 if (n == 0)
8794 rettv->vval.v_number = -1;
8795 else
8796 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008797 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008798 rettv->vval.v_number = (s != NULL);
8799 }
8800# else
8801 if (check_connection() == FAIL)
8802 return;
8803
8804 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8805 serverStrToWin(serverid), &s);
8806# endif
8807
8808 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8809 {
8810 char_u *retvar;
8811
8812 v.di_tv.v_type = VAR_STRING;
8813 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008814 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008815 if (retvar != NULL)
8816 set_var(retvar, &v.di_tv, FALSE);
8817 vim_free(v.di_tv.vval.v_string);
8818 }
8819#else
8820 rettv->vval.v_number = -1;
8821#endif
8822}
8823
8824 static void
8825f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8826{
8827 char_u *r = NULL;
8828
8829#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008830 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008831
8832 if (serverid != NULL && !check_restricted() && !check_secure())
8833 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008834 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008835# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008836 /* The server's HWND is encoded in the 'id' parameter */
8837 long_u n = 0;
8838# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008839
8840 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008841 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008842
Bram Moolenaar4f974752019-02-17 17:44:42 +01008843# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008844 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8845 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008846 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008847 if (r == NULL)
8848# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008849 if (check_connection() == FAIL
8850 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8851 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008852# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008853 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854 }
8855#endif
8856 rettv->v_type = VAR_STRING;
8857 rettv->vval.v_string = r;
8858}
8859
8860/*
8861 * "remote_send()" function
8862 */
8863 static void
8864f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8865{
8866 rettv->v_type = VAR_STRING;
8867 rettv->vval.v_string = NULL;
8868#ifdef FEAT_CLIENTSERVER
8869 remote_common(argvars, rettv, FALSE);
8870#endif
8871}
8872
8873/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008874 * "remote_startserver()" function
8875 */
8876 static void
8877f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8878{
8879#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008880 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008881
8882 if (server == NULL)
8883 return; /* type error; errmsg already given */
8884 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008885 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008886 else
8887 {
8888# ifdef FEAT_X11
8889 if (check_connection() == OK)
8890 serverRegisterName(X_DISPLAY, server);
8891# else
8892 serverSetName(server);
8893# endif
8894 }
8895#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008896 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008897#endif
8898}
8899
8900/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008901 * "remove()" function
8902 */
8903 static void
8904f_remove(typval_T *argvars, typval_T *rettv)
8905{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008906 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8907
8908 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008909 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008910 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008911 blob_remove(argvars, rettv);
8912 else if (argvars[0].v_type == VAR_LIST)
8913 list_remove(argvars, rettv, arg_errmsg);
8914 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008915 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008916}
8917
8918/*
8919 * "rename({from}, {to})" function
8920 */
8921 static void
8922f_rename(typval_T *argvars, typval_T *rettv)
8923{
8924 char_u buf[NUMBUFLEN];
8925
8926 if (check_restricted() || check_secure())
8927 rettv->vval.v_number = -1;
8928 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008929 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8930 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008931}
8932
8933/*
8934 * "repeat()" function
8935 */
8936 static void
8937f_repeat(typval_T *argvars, typval_T *rettv)
8938{
8939 char_u *p;
8940 int n;
8941 int slen;
8942 int len;
8943 char_u *r;
8944 int i;
8945
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008946 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008947 if (argvars[0].v_type == VAR_LIST)
8948 {
8949 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8950 while (n-- > 0)
8951 if (list_extend(rettv->vval.v_list,
8952 argvars[0].vval.v_list, NULL) == FAIL)
8953 break;
8954 }
8955 else
8956 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008957 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008958 rettv->v_type = VAR_STRING;
8959 rettv->vval.v_string = NULL;
8960
8961 slen = (int)STRLEN(p);
8962 len = slen * n;
8963 if (len <= 0)
8964 return;
8965
8966 r = alloc(len + 1);
8967 if (r != NULL)
8968 {
8969 for (i = 0; i < n; i++)
8970 mch_memmove(r + i * slen, p, (size_t)slen);
8971 r[len] = NUL;
8972 }
8973
8974 rettv->vval.v_string = r;
8975 }
8976}
8977
8978/*
8979 * "resolve()" function
8980 */
8981 static void
8982f_resolve(typval_T *argvars, typval_T *rettv)
8983{
8984 char_u *p;
8985#ifdef HAVE_READLINK
8986 char_u *buf = NULL;
8987#endif
8988
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008989 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008990#ifdef FEAT_SHORTCUT
8991 {
8992 char_u *v = NULL;
8993
Bram Moolenaardce1e892019-02-10 23:18:53 +01008994 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008995 if (v != NULL)
8996 rettv->vval.v_string = v;
8997 else
8998 rettv->vval.v_string = vim_strsave(p);
8999 }
9000#else
9001# ifdef HAVE_READLINK
9002 {
9003 char_u *cpy;
9004 int len;
9005 char_u *remain = NULL;
9006 char_u *q;
9007 int is_relative_to_current = FALSE;
9008 int has_trailing_pathsep = FALSE;
9009 int limit = 100;
9010
9011 p = vim_strsave(p);
9012
9013 if (p[0] == '.' && (vim_ispathsep(p[1])
9014 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9015 is_relative_to_current = TRUE;
9016
9017 len = STRLEN(p);
9018 if (len > 0 && after_pathsep(p, p + len))
9019 {
9020 has_trailing_pathsep = TRUE;
9021 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9022 }
9023
9024 q = getnextcomp(p);
9025 if (*q != NUL)
9026 {
9027 /* Separate the first path component in "p", and keep the
9028 * remainder (beginning with the path separator). */
9029 remain = vim_strsave(q - 1);
9030 q[-1] = NUL;
9031 }
9032
9033 buf = alloc(MAXPATHL + 1);
9034 if (buf == NULL)
9035 goto fail;
9036
9037 for (;;)
9038 {
9039 for (;;)
9040 {
9041 len = readlink((char *)p, (char *)buf, MAXPATHL);
9042 if (len <= 0)
9043 break;
9044 buf[len] = NUL;
9045
9046 if (limit-- == 0)
9047 {
9048 vim_free(p);
9049 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009050 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009051 rettv->vval.v_string = NULL;
9052 goto fail;
9053 }
9054
9055 /* Ensure that the result will have a trailing path separator
9056 * if the argument has one. */
9057 if (remain == NULL && has_trailing_pathsep)
9058 add_pathsep(buf);
9059
9060 /* Separate the first path component in the link value and
9061 * concatenate the remainders. */
9062 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9063 if (*q != NUL)
9064 {
9065 if (remain == NULL)
9066 remain = vim_strsave(q - 1);
9067 else
9068 {
9069 cpy = concat_str(q - 1, remain);
9070 if (cpy != NULL)
9071 {
9072 vim_free(remain);
9073 remain = cpy;
9074 }
9075 }
9076 q[-1] = NUL;
9077 }
9078
9079 q = gettail(p);
9080 if (q > p && *q == NUL)
9081 {
9082 /* Ignore trailing path separator. */
9083 q[-1] = NUL;
9084 q = gettail(p);
9085 }
9086 if (q > p && !mch_isFullName(buf))
9087 {
9088 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009089 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009090 if (cpy != NULL)
9091 {
9092 STRCPY(cpy, p);
9093 STRCPY(gettail(cpy), buf);
9094 vim_free(p);
9095 p = cpy;
9096 }
9097 }
9098 else
9099 {
9100 vim_free(p);
9101 p = vim_strsave(buf);
9102 }
9103 }
9104
9105 if (remain == NULL)
9106 break;
9107
9108 /* Append the first path component of "remain" to "p". */
9109 q = getnextcomp(remain + 1);
9110 len = q - remain - (*q != NUL);
9111 cpy = vim_strnsave(p, STRLEN(p) + len);
9112 if (cpy != NULL)
9113 {
9114 STRNCAT(cpy, remain, len);
9115 vim_free(p);
9116 p = cpy;
9117 }
9118 /* Shorten "remain". */
9119 if (*q != NUL)
9120 STRMOVE(remain, q - 1);
9121 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009122 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009123 }
9124
9125 /* If the result is a relative path name, make it explicitly relative to
9126 * the current directory if and only if the argument had this form. */
9127 if (!vim_ispathsep(*p))
9128 {
9129 if (is_relative_to_current
9130 && *p != NUL
9131 && !(p[0] == '.'
9132 && (p[1] == NUL
9133 || vim_ispathsep(p[1])
9134 || (p[1] == '.'
9135 && (p[2] == NUL
9136 || vim_ispathsep(p[2]))))))
9137 {
9138 /* Prepend "./". */
9139 cpy = concat_str((char_u *)"./", p);
9140 if (cpy != NULL)
9141 {
9142 vim_free(p);
9143 p = cpy;
9144 }
9145 }
9146 else if (!is_relative_to_current)
9147 {
9148 /* Strip leading "./". */
9149 q = p;
9150 while (q[0] == '.' && vim_ispathsep(q[1]))
9151 q += 2;
9152 if (q > p)
9153 STRMOVE(p, p + 2);
9154 }
9155 }
9156
9157 /* Ensure that the result will have no trailing path separator
9158 * if the argument had none. But keep "/" or "//". */
9159 if (!has_trailing_pathsep)
9160 {
9161 q = p + STRLEN(p);
9162 if (after_pathsep(p, q))
9163 *gettail_sep(p) = NUL;
9164 }
9165
9166 rettv->vval.v_string = p;
9167 }
9168# else
9169 rettv->vval.v_string = vim_strsave(p);
9170# endif
9171#endif
9172
9173 simplify_filename(rettv->vval.v_string);
9174
9175#ifdef HAVE_READLINK
9176fail:
9177 vim_free(buf);
9178#endif
9179 rettv->v_type = VAR_STRING;
9180}
9181
9182/*
9183 * "reverse({list})" function
9184 */
9185 static void
9186f_reverse(typval_T *argvars, typval_T *rettv)
9187{
9188 list_T *l;
9189 listitem_T *li, *ni;
9190
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009191 if (argvars[0].v_type == VAR_BLOB)
9192 {
9193 blob_T *b = argvars[0].vval.v_blob;
9194 int i, len = blob_len(b);
9195
9196 for (i = 0; i < len / 2; i++)
9197 {
9198 int tmp = blob_get(b, i);
9199
9200 blob_set(b, i, blob_get(b, len - i - 1));
9201 blob_set(b, len - i - 1, tmp);
9202 }
9203 rettv_blob_set(rettv, b);
9204 return;
9205 }
9206
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009207 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009208 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009209 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009210 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009211 (char_u *)N_("reverse() argument"), TRUE))
9212 {
9213 li = l->lv_last;
9214 l->lv_first = l->lv_last = NULL;
9215 l->lv_len = 0;
9216 while (li != NULL)
9217 {
9218 ni = li->li_prev;
9219 list_append(l, li);
9220 li = ni;
9221 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009222 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009223 l->lv_idx = l->lv_len - l->lv_idx - 1;
9224 }
9225}
9226
9227#define SP_NOMOVE 0x01 /* don't move cursor */
9228#define SP_REPEAT 0x02 /* repeat to find outer pair */
9229#define SP_RETCOUNT 0x04 /* return matchcount */
9230#define SP_SETPCMARK 0x08 /* set previous context mark */
9231#define SP_START 0x10 /* accept match at start position */
9232#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9233#define SP_END 0x40 /* leave cursor at end of match */
9234#define SP_COLUMN 0x80 /* start at cursor column */
9235
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009236/*
9237 * Get flags for a search function.
9238 * Possibly sets "p_ws".
9239 * Returns BACKWARD, FORWARD or zero (for an error).
9240 */
9241 static int
9242get_search_arg(typval_T *varp, int *flagsp)
9243{
9244 int dir = FORWARD;
9245 char_u *flags;
9246 char_u nbuf[NUMBUFLEN];
9247 int mask;
9248
9249 if (varp->v_type != VAR_UNKNOWN)
9250 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009251 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009252 if (flags == NULL)
9253 return 0; /* type error; errmsg already given */
9254 while (*flags != NUL)
9255 {
9256 switch (*flags)
9257 {
9258 case 'b': dir = BACKWARD; break;
9259 case 'w': p_ws = TRUE; break;
9260 case 'W': p_ws = FALSE; break;
9261 default: mask = 0;
9262 if (flagsp != NULL)
9263 switch (*flags)
9264 {
9265 case 'c': mask = SP_START; break;
9266 case 'e': mask = SP_END; break;
9267 case 'm': mask = SP_RETCOUNT; break;
9268 case 'n': mask = SP_NOMOVE; break;
9269 case 'p': mask = SP_SUBPAT; break;
9270 case 'r': mask = SP_REPEAT; break;
9271 case 's': mask = SP_SETPCMARK; break;
9272 case 'z': mask = SP_COLUMN; break;
9273 }
9274 if (mask == 0)
9275 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009276 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009277 dir = 0;
9278 }
9279 else
9280 *flagsp |= mask;
9281 }
9282 if (dir == 0)
9283 break;
9284 ++flags;
9285 }
9286 }
9287 return dir;
9288}
9289
9290/*
9291 * Shared by search() and searchpos() functions.
9292 */
9293 static int
9294search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9295{
9296 int flags;
9297 char_u *pat;
9298 pos_T pos;
9299 pos_T save_cursor;
9300 int save_p_ws = p_ws;
9301 int dir;
9302 int retval = 0; /* default: FAIL */
9303 long lnum_stop = 0;
9304 proftime_T tm;
9305#ifdef FEAT_RELTIME
9306 long time_limit = 0;
9307#endif
9308 int options = SEARCH_KEEP;
9309 int subpatnum;
9310
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009311 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009312 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9313 if (dir == 0)
9314 goto theend;
9315 flags = *flagsp;
9316 if (flags & SP_START)
9317 options |= SEARCH_START;
9318 if (flags & SP_END)
9319 options |= SEARCH_END;
9320 if (flags & SP_COLUMN)
9321 options |= SEARCH_COL;
9322
9323 /* Optional arguments: line number to stop searching and timeout. */
9324 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9325 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009326 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009327 if (lnum_stop < 0)
9328 goto theend;
9329#ifdef FEAT_RELTIME
9330 if (argvars[3].v_type != VAR_UNKNOWN)
9331 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009332 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333 if (time_limit < 0)
9334 goto theend;
9335 }
9336#endif
9337 }
9338
9339#ifdef FEAT_RELTIME
9340 /* Set the time limit, if there is one. */
9341 profile_setlimit(time_limit, &tm);
9342#endif
9343
9344 /*
9345 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9346 * Check to make sure only those flags are set.
9347 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9348 * flags cannot be set. Check for that condition also.
9349 */
9350 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9351 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9352 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009353 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009354 goto theend;
9355 }
9356
9357 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009358 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009359 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009360 if (subpatnum != FAIL)
9361 {
9362 if (flags & SP_SUBPAT)
9363 retval = subpatnum;
9364 else
9365 retval = pos.lnum;
9366 if (flags & SP_SETPCMARK)
9367 setpcmark();
9368 curwin->w_cursor = pos;
9369 if (match_pos != NULL)
9370 {
9371 /* Store the match cursor position */
9372 match_pos->lnum = pos.lnum;
9373 match_pos->col = pos.col + 1;
9374 }
9375 /* "/$" will put the cursor after the end of the line, may need to
9376 * correct that here */
9377 check_cursor();
9378 }
9379
9380 /* If 'n' flag is used: restore cursor position. */
9381 if (flags & SP_NOMOVE)
9382 curwin->w_cursor = save_cursor;
9383 else
9384 curwin->w_set_curswant = TRUE;
9385theend:
9386 p_ws = save_p_ws;
9387
9388 return retval;
9389}
9390
9391#ifdef FEAT_FLOAT
9392
9393/*
9394 * round() is not in C90, use ceil() or floor() instead.
9395 */
9396 float_T
9397vim_round(float_T f)
9398{
9399 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9400}
9401
9402/*
9403 * "round({float})" function
9404 */
9405 static void
9406f_round(typval_T *argvars, typval_T *rettv)
9407{
9408 float_T f = 0.0;
9409
9410 rettv->v_type = VAR_FLOAT;
9411 if (get_float_arg(argvars, &f) == OK)
9412 rettv->vval.v_float = vim_round(f);
9413 else
9414 rettv->vval.v_float = 0.0;
9415}
9416#endif
9417
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009418#ifdef FEAT_RUBY
9419/*
9420 * "rubyeval()" function
9421 */
9422 static void
9423f_rubyeval(typval_T *argvars, typval_T *rettv)
9424{
9425 char_u *str;
9426 char_u buf[NUMBUFLEN];
9427
9428 str = tv_get_string_buf(&argvars[0], buf);
9429 do_rubyeval(str, rettv);
9430}
9431#endif
9432
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009433/*
9434 * "screenattr()" function
9435 */
9436 static void
9437f_screenattr(typval_T *argvars, typval_T *rettv)
9438{
9439 int row;
9440 int col;
9441 int c;
9442
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009443 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9444 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009445 if (row < 0 || row >= screen_Rows
9446 || col < 0 || col >= screen_Columns)
9447 c = -1;
9448 else
9449 c = ScreenAttrs[LineOffset[row] + col];
9450 rettv->vval.v_number = c;
9451}
9452
9453/*
9454 * "screenchar()" function
9455 */
9456 static void
9457f_screenchar(typval_T *argvars, typval_T *rettv)
9458{
9459 int row;
9460 int col;
9461 int off;
9462 int c;
9463
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009464 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9465 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009466 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009467 c = -1;
9468 else
9469 {
9470 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009471 if (enc_utf8 && ScreenLinesUC[off] != 0)
9472 c = ScreenLinesUC[off];
9473 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009474 c = ScreenLines[off];
9475 }
9476 rettv->vval.v_number = c;
9477}
9478
9479/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009480 * "screenchars()" function
9481 */
9482 static void
9483f_screenchars(typval_T *argvars, typval_T *rettv)
9484{
9485 int row;
9486 int col;
9487 int off;
9488 int c;
9489 int i;
9490
9491 if (rettv_list_alloc(rettv) == FAIL)
9492 return;
9493 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9494 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9495 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9496 return;
9497
9498 off = LineOffset[row] + col;
9499 if (enc_utf8 && ScreenLinesUC[off] != 0)
9500 c = ScreenLinesUC[off];
9501 else
9502 c = ScreenLines[off];
9503 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9504
9505 if (enc_utf8)
9506
9507 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9508 list_append_number(rettv->vval.v_list,
9509 (varnumber_T)ScreenLinesC[i][off]);
9510}
9511
9512/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009513 * "screencol()" function
9514 *
9515 * First column is 1 to be consistent with virtcol().
9516 */
9517 static void
9518f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9519{
9520 rettv->vval.v_number = screen_screencol() + 1;
9521}
9522
9523/*
9524 * "screenrow()" function
9525 */
9526 static void
9527f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9528{
9529 rettv->vval.v_number = screen_screenrow() + 1;
9530}
9531
9532/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009533 * "screenstring()" function
9534 */
9535 static void
9536f_screenstring(typval_T *argvars, typval_T *rettv)
9537{
9538 int row;
9539 int col;
9540 int off;
9541 int c;
9542 int i;
9543 char_u buf[MB_MAXBYTES + 1];
9544 int buflen = 0;
9545
9546 rettv->vval.v_string = NULL;
9547 rettv->v_type = VAR_STRING;
9548
9549 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9550 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9551 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9552 return;
9553
9554 off = LineOffset[row] + col;
9555 if (enc_utf8 && ScreenLinesUC[off] != 0)
9556 c = ScreenLinesUC[off];
9557 else
9558 c = ScreenLines[off];
9559 buflen += mb_char2bytes(c, buf);
9560
9561 if (enc_utf8)
9562 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9563 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9564
9565 buf[buflen] = NUL;
9566 rettv->vval.v_string = vim_strsave(buf);
9567}
9568
9569/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009570 * "search()" function
9571 */
9572 static void
9573f_search(typval_T *argvars, typval_T *rettv)
9574{
9575 int flags = 0;
9576
9577 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9578}
9579
9580/*
9581 * "searchdecl()" function
9582 */
9583 static void
9584f_searchdecl(typval_T *argvars, typval_T *rettv)
9585{
9586 int locally = 1;
9587 int thisblock = 0;
9588 int error = FALSE;
9589 char_u *name;
9590
9591 rettv->vval.v_number = 1; /* default: FAIL */
9592
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009593 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009594 if (argvars[1].v_type != VAR_UNKNOWN)
9595 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009596 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009597 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009598 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009599 }
9600 if (!error && name != NULL)
9601 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9602 locally, thisblock, SEARCH_KEEP) == FAIL;
9603}
9604
9605/*
9606 * Used by searchpair() and searchpairpos()
9607 */
9608 static int
9609searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9610{
9611 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009612 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009613 int save_p_ws = p_ws;
9614 int dir;
9615 int flags = 0;
9616 char_u nbuf1[NUMBUFLEN];
9617 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009618 int retval = 0; /* default: FAIL */
9619 long lnum_stop = 0;
9620 long time_limit = 0;
9621
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009622 /* Get the three pattern arguments: start, middle, end. Will result in an
9623 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009624 spat = tv_get_string_chk(&argvars[0]);
9625 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9626 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009627 if (spat == NULL || mpat == NULL || epat == NULL)
9628 goto theend; /* type error */
9629
9630 /* Handle the optional fourth argument: flags */
9631 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9632 if (dir == 0)
9633 goto theend;
9634
9635 /* Don't accept SP_END or SP_SUBPAT.
9636 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9637 */
9638 if ((flags & (SP_END | SP_SUBPAT)) != 0
9639 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9640 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009641 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009642 goto theend;
9643 }
9644
9645 /* Using 'r' implies 'W', otherwise it doesn't work. */
9646 if (flags & SP_REPEAT)
9647 p_ws = FALSE;
9648
9649 /* Optional fifth argument: skip expression */
9650 if (argvars[3].v_type == VAR_UNKNOWN
9651 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009652 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009653 else
9654 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009655 skip = &argvars[4];
9656 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9657 && skip->v_type != VAR_STRING)
9658 {
9659 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009660 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009661 goto theend;
9662 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009663 if (argvars[5].v_type != VAR_UNKNOWN)
9664 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009665 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009666 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009667 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009668 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009669 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009670 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671#ifdef FEAT_RELTIME
9672 if (argvars[6].v_type != VAR_UNKNOWN)
9673 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009674 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009675 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009676 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009677 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009678 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009679 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009680 }
9681#endif
9682 }
9683 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009684
9685 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9686 match_pos, lnum_stop, time_limit);
9687
9688theend:
9689 p_ws = save_p_ws;
9690
9691 return retval;
9692}
9693
9694/*
9695 * "searchpair()" function
9696 */
9697 static void
9698f_searchpair(typval_T *argvars, typval_T *rettv)
9699{
9700 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9701}
9702
9703/*
9704 * "searchpairpos()" function
9705 */
9706 static void
9707f_searchpairpos(typval_T *argvars, typval_T *rettv)
9708{
9709 pos_T match_pos;
9710 int lnum = 0;
9711 int col = 0;
9712
9713 if (rettv_list_alloc(rettv) == FAIL)
9714 return;
9715
9716 if (searchpair_cmn(argvars, &match_pos) > 0)
9717 {
9718 lnum = match_pos.lnum;
9719 col = match_pos.col;
9720 }
9721
9722 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9723 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9724}
9725
9726/*
9727 * Search for a start/middle/end thing.
9728 * Used by searchpair(), see its documentation for the details.
9729 * Returns 0 or -1 for no match,
9730 */
9731 long
9732do_searchpair(
9733 char_u *spat, /* start pattern */
9734 char_u *mpat, /* middle pattern */
9735 char_u *epat, /* end pattern */
9736 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009737 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009738 int flags, /* SP_SETPCMARK and other SP_ values */
9739 pos_T *match_pos,
9740 linenr_T lnum_stop, /* stop at this line if not zero */
9741 long time_limit UNUSED) /* stop after this many msec */
9742{
9743 char_u *save_cpo;
9744 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9745 long retval = 0;
9746 pos_T pos;
9747 pos_T firstpos;
9748 pos_T foundpos;
9749 pos_T save_cursor;
9750 pos_T save_pos;
9751 int n;
9752 int r;
9753 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009754 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009755 int err;
9756 int options = SEARCH_KEEP;
9757 proftime_T tm;
9758
9759 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9760 save_cpo = p_cpo;
9761 p_cpo = empty_option;
9762
9763#ifdef FEAT_RELTIME
9764 /* Set the time limit, if there is one. */
9765 profile_setlimit(time_limit, &tm);
9766#endif
9767
9768 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9769 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009770 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9771 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009772 if (pat2 == NULL || pat3 == NULL)
9773 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009774 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009775 if (*mpat == NUL)
9776 STRCPY(pat3, pat2);
9777 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009778 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009779 spat, epat, mpat);
9780 if (flags & SP_START)
9781 options |= SEARCH_START;
9782
Bram Moolenaar48570482017-10-30 21:48:41 +01009783 if (skip != NULL)
9784 {
9785 /* Empty string means to not use the skip expression. */
9786 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9787 use_skip = skip->vval.v_string != NULL
9788 && *skip->vval.v_string != NUL;
9789 }
9790
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009791 save_cursor = curwin->w_cursor;
9792 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009793 CLEAR_POS(&firstpos);
9794 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009795 pat = pat3;
9796 for (;;)
9797 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009798 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009799 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009800 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009801 /* didn't find it or found the first match again: FAIL */
9802 break;
9803
9804 if (firstpos.lnum == 0)
9805 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009806 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009807 {
9808 /* Found the same position again. Can happen with a pattern that
9809 * has "\zs" at the end and searching backwards. Advance one
9810 * character and try again. */
9811 if (dir == BACKWARD)
9812 decl(&pos);
9813 else
9814 incl(&pos);
9815 }
9816 foundpos = pos;
9817
9818 /* clear the start flag to avoid getting stuck here */
9819 options &= ~SEARCH_START;
9820
9821 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009822 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009823 {
9824 save_pos = curwin->w_cursor;
9825 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009826 err = FALSE;
9827 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009828 curwin->w_cursor = save_pos;
9829 if (err)
9830 {
9831 /* Evaluating {skip} caused an error, break here. */
9832 curwin->w_cursor = save_cursor;
9833 retval = -1;
9834 break;
9835 }
9836 if (r)
9837 continue;
9838 }
9839
9840 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9841 {
9842 /* Found end when searching backwards or start when searching
9843 * forward: nested pair. */
9844 ++nest;
9845 pat = pat2; /* nested, don't search for middle */
9846 }
9847 else
9848 {
9849 /* Found end when searching forward or start when searching
9850 * backward: end of (nested) pair; or found middle in outer pair. */
9851 if (--nest == 1)
9852 pat = pat3; /* outer level, search for middle */
9853 }
9854
9855 if (nest == 0)
9856 {
9857 /* Found the match: return matchcount or line number. */
9858 if (flags & SP_RETCOUNT)
9859 ++retval;
9860 else
9861 retval = pos.lnum;
9862 if (flags & SP_SETPCMARK)
9863 setpcmark();
9864 curwin->w_cursor = pos;
9865 if (!(flags & SP_REPEAT))
9866 break;
9867 nest = 1; /* search for next unmatched */
9868 }
9869 }
9870
9871 if (match_pos != NULL)
9872 {
9873 /* Store the match cursor position */
9874 match_pos->lnum = curwin->w_cursor.lnum;
9875 match_pos->col = curwin->w_cursor.col + 1;
9876 }
9877
9878 /* If 'n' flag is used or search failed: restore cursor position. */
9879 if ((flags & SP_NOMOVE) || retval == 0)
9880 curwin->w_cursor = save_cursor;
9881
9882theend:
9883 vim_free(pat2);
9884 vim_free(pat3);
9885 if (p_cpo == empty_option)
9886 p_cpo = save_cpo;
9887 else
9888 /* Darn, evaluating the {skip} expression changed the value. */
9889 free_string_option(save_cpo);
9890
9891 return retval;
9892}
9893
9894/*
9895 * "searchpos()" function
9896 */
9897 static void
9898f_searchpos(typval_T *argvars, typval_T *rettv)
9899{
9900 pos_T match_pos;
9901 int lnum = 0;
9902 int col = 0;
9903 int n;
9904 int flags = 0;
9905
9906 if (rettv_list_alloc(rettv) == FAIL)
9907 return;
9908
9909 n = search_cmn(argvars, &match_pos, &flags);
9910 if (n > 0)
9911 {
9912 lnum = match_pos.lnum;
9913 col = match_pos.col;
9914 }
9915
9916 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9917 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9918 if (flags & SP_SUBPAT)
9919 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9920}
9921
9922 static void
9923f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9924{
9925#ifdef FEAT_CLIENTSERVER
9926 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009927 char_u *server = tv_get_string_chk(&argvars[0]);
9928 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009929
9930 rettv->vval.v_number = -1;
9931 if (server == NULL || reply == NULL)
9932 return;
9933 if (check_restricted() || check_secure())
9934 return;
9935# ifdef FEAT_X11
9936 if (check_connection() == FAIL)
9937 return;
9938# endif
9939
9940 if (serverSendReply(server, reply) < 0)
9941 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009942 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009943 return;
9944 }
9945 rettv->vval.v_number = 0;
9946#else
9947 rettv->vval.v_number = -1;
9948#endif
9949}
9950
9951 static void
9952f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9953{
9954 char_u *r = NULL;
9955
9956#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009957# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009958 r = serverGetVimNames();
9959# else
9960 make_connection();
9961 if (X_DISPLAY != NULL)
9962 r = serverGetVimNames(X_DISPLAY);
9963# endif
9964#endif
9965 rettv->v_type = VAR_STRING;
9966 rettv->vval.v_string = r;
9967}
9968
9969/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009970 * "setbufline()" function
9971 */
9972 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009973f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009974{
9975 linenr_T lnum;
9976 buf_T *buf;
9977
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009978 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009979 if (buf == NULL)
9980 rettv->vval.v_number = 1; /* FAIL */
9981 else
9982 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009983 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009984 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009985 }
9986}
9987
9988/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009989 * "setbufvar()" function
9990 */
9991 static void
9992f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9993{
9994 buf_T *buf;
9995 char_u *varname, *bufvarname;
9996 typval_T *varp;
9997 char_u nbuf[NUMBUFLEN];
9998
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009999 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010000 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010001 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10002 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010003 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010004 varp = &argvars[2];
10005
10006 if (buf != NULL && varname != NULL && varp != NULL)
10007 {
10008 if (*varname == '&')
10009 {
10010 long numval;
10011 char_u *strval;
10012 int error = FALSE;
10013 aco_save_T aco;
10014
10015 /* set curbuf to be our buf, temporarily */
10016 aucmd_prepbuf(&aco, buf);
10017
10018 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010019 numval = (long)tv_get_number_chk(varp, &error);
10020 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010021 if (!error && strval != NULL)
10022 set_option_value(varname, numval, strval, OPT_LOCAL);
10023
10024 /* reset notion of buffer */
10025 aucmd_restbuf(&aco);
10026 }
10027 else
10028 {
10029 buf_T *save_curbuf = curbuf;
10030
Bram Moolenaar964b3742019-05-24 18:54:09 +020010031 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010032 if (bufvarname != NULL)
10033 {
10034 curbuf = buf;
10035 STRCPY(bufvarname, "b:");
10036 STRCPY(bufvarname + 2, varname);
10037 set_var(bufvarname, varp, TRUE);
10038 vim_free(bufvarname);
10039 curbuf = save_curbuf;
10040 }
10041 }
10042 }
10043}
10044
10045 static void
10046f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10047{
10048 dict_T *d;
10049 dictitem_T *di;
10050 char_u *csearch;
10051
10052 if (argvars[0].v_type != VAR_DICT)
10053 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010054 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010055 return;
10056 }
10057
10058 if ((d = argvars[0].vval.v_dict) != NULL)
10059 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010060 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010061 if (csearch != NULL)
10062 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010063 if (enc_utf8)
10064 {
10065 int pcc[MAX_MCO];
10066 int c = utfc_ptr2char(csearch, pcc);
10067
10068 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10069 }
10070 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010071 set_last_csearch(PTR2CHAR(csearch),
10072 csearch, MB_PTR2LEN(csearch));
10073 }
10074
10075 di = dict_find(d, (char_u *)"forward", -1);
10076 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010077 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010078 ? FORWARD : BACKWARD);
10079
10080 di = dict_find(d, (char_u *)"until", -1);
10081 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010082 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010083 }
10084}
10085
10086/*
10087 * "setcmdpos()" function
10088 */
10089 static void
10090f_setcmdpos(typval_T *argvars, typval_T *rettv)
10091{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010092 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010093
10094 if (pos >= 0)
10095 rettv->vval.v_number = set_cmdline_pos(pos);
10096}
10097
10098/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010099 * "setenv()" function
10100 */
10101 static void
10102f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10103{
10104 char_u namebuf[NUMBUFLEN];
10105 char_u valbuf[NUMBUFLEN];
10106 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10107
10108 if (argvars[1].v_type == VAR_SPECIAL
10109 && argvars[1].vval.v_number == VVAL_NULL)
10110 vim_unsetenv(name);
10111 else
10112 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10113}
10114
10115/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010116 * "setfperm({fname}, {mode})" function
10117 */
10118 static void
10119f_setfperm(typval_T *argvars, typval_T *rettv)
10120{
10121 char_u *fname;
10122 char_u modebuf[NUMBUFLEN];
10123 char_u *mode_str;
10124 int i;
10125 int mask;
10126 int mode = 0;
10127
10128 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010129 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010130 if (fname == NULL)
10131 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010132 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010133 if (mode_str == NULL)
10134 return;
10135 if (STRLEN(mode_str) != 9)
10136 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010137 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010138 return;
10139 }
10140
10141 mask = 1;
10142 for (i = 8; i >= 0; --i)
10143 {
10144 if (mode_str[i] != '-')
10145 mode |= mask;
10146 mask = mask << 1;
10147 }
10148 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10149}
10150
10151/*
10152 * "setline()" function
10153 */
10154 static void
10155f_setline(typval_T *argvars, typval_T *rettv)
10156{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010157 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010158
Bram Moolenaarca851592018-06-06 21:04:07 +020010159 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010160}
10161
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010162/*
10163 * Used by "setqflist()" and "setloclist()" functions
10164 */
10165 static void
10166set_qf_ll_list(
10167 win_T *wp UNUSED,
10168 typval_T *list_arg UNUSED,
10169 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010170 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010171 typval_T *rettv)
10172{
10173#ifdef FEAT_QUICKFIX
10174 static char *e_invact = N_("E927: Invalid action: '%s'");
10175 char_u *act;
10176 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010177 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010178#endif
10179
10180 rettv->vval.v_number = -1;
10181
10182#ifdef FEAT_QUICKFIX
10183 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010184 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010185 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010186 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010187 else
10188 {
10189 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010190 dict_T *d = NULL;
10191 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010192
10193 if (action_arg->v_type == VAR_STRING)
10194 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010195 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010196 if (act == NULL)
10197 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010198 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10199 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010200 action = *act;
10201 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010202 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010203 }
10204 else if (action_arg->v_type == VAR_UNKNOWN)
10205 action = ' ';
10206 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010207 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010208
Bram Moolenaard823fa92016-08-12 16:29:27 +020010209 if (action_arg->v_type != VAR_UNKNOWN
10210 && what_arg->v_type != VAR_UNKNOWN)
10211 {
10212 if (what_arg->v_type == VAR_DICT)
10213 d = what_arg->vval.v_dict;
10214 else
10215 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010216 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010217 valid_dict = FALSE;
10218 }
10219 }
10220
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010221 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010222 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010223 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10224 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010225 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010226 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010227 }
10228#endif
10229}
10230
10231/*
10232 * "setloclist()" function
10233 */
10234 static void
10235f_setloclist(typval_T *argvars, typval_T *rettv)
10236{
10237 win_T *win;
10238
10239 rettv->vval.v_number = -1;
10240
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010241 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010242 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010243 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244}
10245
10246/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010247 * "setpos()" function
10248 */
10249 static void
10250f_setpos(typval_T *argvars, typval_T *rettv)
10251{
10252 pos_T pos;
10253 int fnum;
10254 char_u *name;
10255 colnr_T curswant = -1;
10256
10257 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010258 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010259 if (name != NULL)
10260 {
10261 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10262 {
10263 if (--pos.col < 0)
10264 pos.col = 0;
10265 if (name[0] == '.' && name[1] == NUL)
10266 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010267 /* set cursor; "fnum" is ignored */
10268 curwin->w_cursor = pos;
10269 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010270 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010271 curwin->w_curswant = curswant - 1;
10272 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010273 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010274 check_cursor();
10275 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010276 }
10277 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10278 {
10279 /* set mark */
10280 if (setmark_pos(name[1], &pos, fnum) == OK)
10281 rettv->vval.v_number = 0;
10282 }
10283 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010284 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010285 }
10286 }
10287}
10288
10289/*
10290 * "setqflist()" function
10291 */
10292 static void
10293f_setqflist(typval_T *argvars, typval_T *rettv)
10294{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010295 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296}
10297
10298/*
10299 * "setreg()" function
10300 */
10301 static void
10302f_setreg(typval_T *argvars, typval_T *rettv)
10303{
10304 int regname;
10305 char_u *strregname;
10306 char_u *stropt;
10307 char_u *strval;
10308 int append;
10309 char_u yank_type;
10310 long block_len;
10311
10312 block_len = -1;
10313 yank_type = MAUTO;
10314 append = FALSE;
10315
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010316 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010317 rettv->vval.v_number = 1; /* FAIL is default */
10318
10319 if (strregname == NULL)
10320 return; /* type error; errmsg already given */
10321 regname = *strregname;
10322 if (regname == 0 || regname == '@')
10323 regname = '"';
10324
10325 if (argvars[2].v_type != VAR_UNKNOWN)
10326 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010327 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010328 if (stropt == NULL)
10329 return; /* type error */
10330 for (; *stropt != NUL; ++stropt)
10331 switch (*stropt)
10332 {
10333 case 'a': case 'A': /* append */
10334 append = TRUE;
10335 break;
10336 case 'v': case 'c': /* character-wise selection */
10337 yank_type = MCHAR;
10338 break;
10339 case 'V': case 'l': /* line-wise selection */
10340 yank_type = MLINE;
10341 break;
10342 case 'b': case Ctrl_V: /* block-wise selection */
10343 yank_type = MBLOCK;
10344 if (VIM_ISDIGIT(stropt[1]))
10345 {
10346 ++stropt;
10347 block_len = getdigits(&stropt) - 1;
10348 --stropt;
10349 }
10350 break;
10351 }
10352 }
10353
10354 if (argvars[1].v_type == VAR_LIST)
10355 {
10356 char_u **lstval;
10357 char_u **allocval;
10358 char_u buf[NUMBUFLEN];
10359 char_u **curval;
10360 char_u **curallocval;
10361 list_T *ll = argvars[1].vval.v_list;
10362 listitem_T *li;
10363 int len;
10364
10365 /* If the list is NULL handle like an empty list. */
10366 len = ll == NULL ? 0 : ll->lv_len;
10367
10368 /* First half: use for pointers to result lines; second half: use for
10369 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010370 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010371 if (lstval == NULL)
10372 return;
10373 curval = lstval;
10374 allocval = lstval + len + 2;
10375 curallocval = allocval;
10376
10377 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10378 li = li->li_next)
10379 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010380 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010381 if (strval == NULL)
10382 goto free_lstval;
10383 if (strval == buf)
10384 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010385 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010386 * overwrite the string. */
10387 strval = vim_strsave(buf);
10388 if (strval == NULL)
10389 goto free_lstval;
10390 *curallocval++ = strval;
10391 }
10392 *curval++ = strval;
10393 }
10394 *curval++ = NULL;
10395
10396 write_reg_contents_lst(regname, lstval, -1,
10397 append, yank_type, block_len);
10398free_lstval:
10399 while (curallocval > allocval)
10400 vim_free(*--curallocval);
10401 vim_free(lstval);
10402 }
10403 else
10404 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010405 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010406 if (strval == NULL)
10407 return;
10408 write_reg_contents_ex(regname, strval, -1,
10409 append, yank_type, block_len);
10410 }
10411 rettv->vval.v_number = 0;
10412}
10413
10414/*
10415 * "settabvar()" function
10416 */
10417 static void
10418f_settabvar(typval_T *argvars, typval_T *rettv)
10419{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010420 tabpage_T *save_curtab;
10421 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010422 char_u *varname, *tabvarname;
10423 typval_T *varp;
10424
10425 rettv->vval.v_number = 0;
10426
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010427 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010428 return;
10429
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010430 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10431 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010432 varp = &argvars[2];
10433
Bram Moolenaar4033c552017-09-16 20:54:51 +020010434 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010435 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010436 save_curtab = curtab;
10437 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010438
Bram Moolenaar964b3742019-05-24 18:54:09 +020010439 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010440 if (tabvarname != NULL)
10441 {
10442 STRCPY(tabvarname, "t:");
10443 STRCPY(tabvarname + 2, varname);
10444 set_var(tabvarname, varp, TRUE);
10445 vim_free(tabvarname);
10446 }
10447
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010448 /* Restore current tabpage */
10449 if (valid_tabpage(save_curtab))
10450 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010451 }
10452}
10453
10454/*
10455 * "settabwinvar()" function
10456 */
10457 static void
10458f_settabwinvar(typval_T *argvars, typval_T *rettv)
10459{
10460 setwinvar(argvars, rettv, 1);
10461}
10462
10463/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010464 * "settagstack()" function
10465 */
10466 static void
10467f_settagstack(typval_T *argvars, typval_T *rettv)
10468{
10469 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10470 win_T *wp;
10471 dict_T *d;
10472 int action = 'r';
10473
10474 rettv->vval.v_number = -1;
10475
10476 // first argument: window number or id
10477 wp = find_win_by_nr_or_id(&argvars[0]);
10478 if (wp == NULL)
10479 return;
10480
10481 // second argument: dict with items to set in the tag stack
10482 if (argvars[1].v_type != VAR_DICT)
10483 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010484 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010485 return;
10486 }
10487 d = argvars[1].vval.v_dict;
10488 if (d == NULL)
10489 return;
10490
10491 // third argument: action - 'a' for append and 'r' for replace.
10492 // default is to replace the stack.
10493 if (argvars[2].v_type == VAR_UNKNOWN)
10494 action = 'r';
10495 else if (argvars[2].v_type == VAR_STRING)
10496 {
10497 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010498 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010499 if (actstr == NULL)
10500 return;
10501 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10502 action = *actstr;
10503 else
10504 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010505 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010506 return;
10507 }
10508 }
10509 else
10510 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010511 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010512 return;
10513 }
10514
10515 if (set_tagstack(wp, d, action) == OK)
10516 rettv->vval.v_number = 0;
10517}
10518
10519/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010520 * "setwinvar()" function
10521 */
10522 static void
10523f_setwinvar(typval_T *argvars, typval_T *rettv)
10524{
10525 setwinvar(argvars, rettv, 0);
10526}
10527
10528#ifdef FEAT_CRYPT
10529/*
10530 * "sha256({string})" function
10531 */
10532 static void
10533f_sha256(typval_T *argvars, typval_T *rettv)
10534{
10535 char_u *p;
10536
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010537 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010538 rettv->vval.v_string = vim_strsave(
10539 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10540 rettv->v_type = VAR_STRING;
10541}
10542#endif /* FEAT_CRYPT */
10543
10544/*
10545 * "shellescape({string})" function
10546 */
10547 static void
10548f_shellescape(typval_T *argvars, typval_T *rettv)
10549{
Bram Moolenaar20615522017-06-05 18:46:26 +020010550 int do_special = non_zero_arg(&argvars[1]);
10551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010552 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010553 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010554 rettv->v_type = VAR_STRING;
10555}
10556
10557/*
10558 * shiftwidth() function
10559 */
10560 static void
10561f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10562{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010563 rettv->vval.v_number = 0;
10564
10565 if (argvars[0].v_type != VAR_UNKNOWN)
10566 {
10567 long col;
10568
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010569 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010570 if (col < 0)
10571 return; // type error; errmsg already given
10572#ifdef FEAT_VARTABS
10573 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10574 return;
10575#endif
10576 }
10577
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010578 rettv->vval.v_number = get_sw_value(curbuf);
10579}
10580
10581/*
10582 * "simplify()" function
10583 */
10584 static void
10585f_simplify(typval_T *argvars, typval_T *rettv)
10586{
10587 char_u *p;
10588
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010589 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010590 rettv->vval.v_string = vim_strsave(p);
10591 simplify_filename(rettv->vval.v_string); /* simplify in place */
10592 rettv->v_type = VAR_STRING;
10593}
10594
10595#ifdef FEAT_FLOAT
10596/*
10597 * "sin()" function
10598 */
10599 static void
10600f_sin(typval_T *argvars, typval_T *rettv)
10601{
10602 float_T f = 0.0;
10603
10604 rettv->v_type = VAR_FLOAT;
10605 if (get_float_arg(argvars, &f) == OK)
10606 rettv->vval.v_float = sin(f);
10607 else
10608 rettv->vval.v_float = 0.0;
10609}
10610
10611/*
10612 * "sinh()" function
10613 */
10614 static void
10615f_sinh(typval_T *argvars, typval_T *rettv)
10616{
10617 float_T f = 0.0;
10618
10619 rettv->v_type = VAR_FLOAT;
10620 if (get_float_arg(argvars, &f) == OK)
10621 rettv->vval.v_float = sinh(f);
10622 else
10623 rettv->vval.v_float = 0.0;
10624}
10625#endif
10626
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010627/*
10628 * "soundfold({word})" function
10629 */
10630 static void
10631f_soundfold(typval_T *argvars, typval_T *rettv)
10632{
10633 char_u *s;
10634
10635 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010636 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010637#ifdef FEAT_SPELL
10638 rettv->vval.v_string = eval_soundfold(s);
10639#else
10640 rettv->vval.v_string = vim_strsave(s);
10641#endif
10642}
10643
10644/*
10645 * "spellbadword()" function
10646 */
10647 static void
10648f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10649{
10650 char_u *word = (char_u *)"";
10651 hlf_T attr = HLF_COUNT;
10652 int len = 0;
10653
10654 if (rettv_list_alloc(rettv) == FAIL)
10655 return;
10656
10657#ifdef FEAT_SPELL
10658 if (argvars[0].v_type == VAR_UNKNOWN)
10659 {
10660 /* Find the start and length of the badly spelled word. */
10661 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10662 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010663 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010664 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010665 curwin->w_set_curswant = TRUE;
10666 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010667 }
10668 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10669 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010670 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010671 int capcol = -1;
10672
10673 if (str != NULL)
10674 {
10675 /* Check the argument for spelling. */
10676 while (*str != NUL)
10677 {
10678 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10679 if (attr != HLF_COUNT)
10680 {
10681 word = str;
10682 break;
10683 }
10684 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010685 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010686 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010687 }
10688 }
10689 }
10690#endif
10691
10692 list_append_string(rettv->vval.v_list, word, len);
10693 list_append_string(rettv->vval.v_list, (char_u *)(
10694 attr == HLF_SPB ? "bad" :
10695 attr == HLF_SPR ? "rare" :
10696 attr == HLF_SPL ? "local" :
10697 attr == HLF_SPC ? "caps" :
10698 ""), -1);
10699}
10700
10701/*
10702 * "spellsuggest()" function
10703 */
10704 static void
10705f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10706{
10707#ifdef FEAT_SPELL
10708 char_u *str;
10709 int typeerr = FALSE;
10710 int maxcount;
10711 garray_T ga;
10712 int i;
10713 listitem_T *li;
10714 int need_capital = FALSE;
10715#endif
10716
10717 if (rettv_list_alloc(rettv) == FAIL)
10718 return;
10719
10720#ifdef FEAT_SPELL
10721 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10722 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010723 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010724 if (argvars[1].v_type != VAR_UNKNOWN)
10725 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010726 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010727 if (maxcount <= 0)
10728 return;
10729 if (argvars[2].v_type != VAR_UNKNOWN)
10730 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010731 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010732 if (typeerr)
10733 return;
10734 }
10735 }
10736 else
10737 maxcount = 25;
10738
10739 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10740
10741 for (i = 0; i < ga.ga_len; ++i)
10742 {
10743 str = ((char_u **)ga.ga_data)[i];
10744
10745 li = listitem_alloc();
10746 if (li == NULL)
10747 vim_free(str);
10748 else
10749 {
10750 li->li_tv.v_type = VAR_STRING;
10751 li->li_tv.v_lock = 0;
10752 li->li_tv.vval.v_string = str;
10753 list_append(rettv->vval.v_list, li);
10754 }
10755 }
10756 ga_clear(&ga);
10757 }
10758#endif
10759}
10760
10761 static void
10762f_split(typval_T *argvars, typval_T *rettv)
10763{
10764 char_u *str;
10765 char_u *end;
10766 char_u *pat = NULL;
10767 regmatch_T regmatch;
10768 char_u patbuf[NUMBUFLEN];
10769 char_u *save_cpo;
10770 int match;
10771 colnr_T col = 0;
10772 int keepempty = FALSE;
10773 int typeerr = FALSE;
10774
10775 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10776 save_cpo = p_cpo;
10777 p_cpo = (char_u *)"";
10778
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010779 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010780 if (argvars[1].v_type != VAR_UNKNOWN)
10781 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010782 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010783 if (pat == NULL)
10784 typeerr = TRUE;
10785 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010786 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010787 }
10788 if (pat == NULL || *pat == NUL)
10789 pat = (char_u *)"[\\x01- ]\\+";
10790
10791 if (rettv_list_alloc(rettv) == FAIL)
10792 return;
10793 if (typeerr)
10794 return;
10795
10796 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10797 if (regmatch.regprog != NULL)
10798 {
10799 regmatch.rm_ic = FALSE;
10800 while (*str != NUL || keepempty)
10801 {
10802 if (*str == NUL)
10803 match = FALSE; /* empty item at the end */
10804 else
10805 match = vim_regexec_nl(&regmatch, str, col);
10806 if (match)
10807 end = regmatch.startp[0];
10808 else
10809 end = str + STRLEN(str);
10810 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10811 && *str != NUL && match && end < regmatch.endp[0]))
10812 {
10813 if (list_append_string(rettv->vval.v_list, str,
10814 (int)(end - str)) == FAIL)
10815 break;
10816 }
10817 if (!match)
10818 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010819 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010820 if (regmatch.endp[0] > str)
10821 col = 0;
10822 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010823 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010824 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010825 str = regmatch.endp[0];
10826 }
10827
10828 vim_regfree(regmatch.regprog);
10829 }
10830
10831 p_cpo = save_cpo;
10832}
10833
10834#ifdef FEAT_FLOAT
10835/*
10836 * "sqrt()" function
10837 */
10838 static void
10839f_sqrt(typval_T *argvars, typval_T *rettv)
10840{
10841 float_T f = 0.0;
10842
10843 rettv->v_type = VAR_FLOAT;
10844 if (get_float_arg(argvars, &f) == OK)
10845 rettv->vval.v_float = sqrt(f);
10846 else
10847 rettv->vval.v_float = 0.0;
10848}
10849
10850/*
10851 * "str2float()" function
10852 */
10853 static void
10854f_str2float(typval_T *argvars, typval_T *rettv)
10855{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010856 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010857 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010858
Bram Moolenaar08243d22017-01-10 16:12:29 +010010859 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010860 p = skipwhite(p + 1);
10861 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010862 if (isneg)
10863 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010864 rettv->v_type = VAR_FLOAT;
10865}
10866#endif
10867
10868/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010869 * "str2list()" function
10870 */
10871 static void
10872f_str2list(typval_T *argvars, typval_T *rettv)
10873{
10874 char_u *p;
10875 int utf8 = FALSE;
10876
10877 if (rettv_list_alloc(rettv) == FAIL)
10878 return;
10879
10880 if (argvars[1].v_type != VAR_UNKNOWN)
10881 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10882
10883 p = tv_get_string(&argvars[0]);
10884
10885 if (has_mbyte || utf8)
10886 {
10887 int (*ptr2len)(char_u *);
10888 int (*ptr2char)(char_u *);
10889
10890 if (utf8 || enc_utf8)
10891 {
10892 ptr2len = utf_ptr2len;
10893 ptr2char = utf_ptr2char;
10894 }
10895 else
10896 {
10897 ptr2len = mb_ptr2len;
10898 ptr2char = mb_ptr2char;
10899 }
10900
10901 for ( ; *p != NUL; p += (*ptr2len)(p))
10902 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10903 }
10904 else
10905 for ( ; *p != NUL; ++p)
10906 list_append_number(rettv->vval.v_list, *p);
10907}
10908
10909/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010910 * "str2nr()" function
10911 */
10912 static void
10913f_str2nr(typval_T *argvars, typval_T *rettv)
10914{
10915 int base = 10;
10916 char_u *p;
10917 varnumber_T n;
10918 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010919 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010920
10921 if (argvars[1].v_type != VAR_UNKNOWN)
10922 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010923 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010924 if (base != 2 && base != 8 && base != 10 && base != 16)
10925 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010926 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010927 return;
10928 }
10929 }
10930
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010931 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010932 isneg = (*p == '-');
10933 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010934 p = skipwhite(p + 1);
10935 switch (base)
10936 {
10937 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10938 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10939 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10940 default: what = 0;
10941 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010942 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10943 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010944 if (isneg)
10945 rettv->vval.v_number = -n;
10946 else
10947 rettv->vval.v_number = n;
10948
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010949}
10950
10951#ifdef HAVE_STRFTIME
10952/*
10953 * "strftime({format}[, {time}])" function
10954 */
10955 static void
10956f_strftime(typval_T *argvars, typval_T *rettv)
10957{
10958 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010959 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010960 struct tm *curtime;
10961 time_t seconds;
10962 char_u *p;
10963
10964 rettv->v_type = VAR_STRING;
10965
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010966 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010967 if (argvars[1].v_type == VAR_UNKNOWN)
10968 seconds = time(NULL);
10969 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010970 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010971 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010972 /* MSVC returns NULL for an invalid value of seconds. */
10973 if (curtime == NULL)
10974 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10975 else
10976 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010977 vimconv_T conv;
10978 char_u *enc;
10979
10980 conv.vc_type = CONV_NONE;
10981 enc = enc_locale();
10982 convert_setup(&conv, p_enc, enc);
10983 if (conv.vc_type != CONV_NONE)
10984 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010985 if (p != NULL)
10986 (void)strftime((char *)result_buf, sizeof(result_buf),
10987 (char *)p, curtime);
10988 else
10989 result_buf[0] = NUL;
10990
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010991 if (conv.vc_type != CONV_NONE)
10992 vim_free(p);
10993 convert_setup(&conv, enc, p_enc);
10994 if (conv.vc_type != CONV_NONE)
10995 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10996 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997 rettv->vval.v_string = vim_strsave(result_buf);
10998
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010999 /* Release conversion descriptors */
11000 convert_setup(&conv, NULL, NULL);
11001 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011002 }
11003}
11004#endif
11005
11006/*
11007 * "strgetchar()" function
11008 */
11009 static void
11010f_strgetchar(typval_T *argvars, typval_T *rettv)
11011{
11012 char_u *str;
11013 int len;
11014 int error = FALSE;
11015 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010011016 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011017
11018 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011019 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011020 if (str == NULL)
11021 return;
11022 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011023 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011024 if (error)
11025 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011026
Bram Moolenaar13505972019-01-24 15:04:48 +010011027 while (charidx >= 0 && byteidx < len)
11028 {
11029 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011030 {
Bram Moolenaar13505972019-01-24 15:04:48 +010011031 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11032 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011033 }
Bram Moolenaar13505972019-01-24 15:04:48 +010011034 --charidx;
11035 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011036 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011037}
11038
11039/*
11040 * "stridx()" function
11041 */
11042 static void
11043f_stridx(typval_T *argvars, typval_T *rettv)
11044{
11045 char_u buf[NUMBUFLEN];
11046 char_u *needle;
11047 char_u *haystack;
11048 char_u *save_haystack;
11049 char_u *pos;
11050 int start_idx;
11051
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011052 needle = tv_get_string_chk(&argvars[1]);
11053 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011054 rettv->vval.v_number = -1;
11055 if (needle == NULL || haystack == NULL)
11056 return; /* type error; errmsg already given */
11057
11058 if (argvars[2].v_type != VAR_UNKNOWN)
11059 {
11060 int error = FALSE;
11061
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011062 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063 if (error || start_idx >= (int)STRLEN(haystack))
11064 return;
11065 if (start_idx >= 0)
11066 haystack += start_idx;
11067 }
11068
11069 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11070 if (pos != NULL)
11071 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11072}
11073
11074/*
11075 * "string()" function
11076 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010011077 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011078f_string(typval_T *argvars, typval_T *rettv)
11079{
11080 char_u *tofree;
11081 char_u numbuf[NUMBUFLEN];
11082
11083 rettv->v_type = VAR_STRING;
11084 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11085 get_copyID());
11086 /* Make a copy if we have a value but it's not in allocated memory. */
11087 if (rettv->vval.v_string != NULL && tofree == NULL)
11088 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11089}
11090
11091/*
11092 * "strlen()" function
11093 */
11094 static void
11095f_strlen(typval_T *argvars, typval_T *rettv)
11096{
11097 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011098 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011099}
11100
11101/*
11102 * "strchars()" function
11103 */
11104 static void
11105f_strchars(typval_T *argvars, typval_T *rettv)
11106{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011107 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011108 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011109 varnumber_T len = 0;
11110 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011111
11112 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011113 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011114 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011115 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011116 else
11117 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011118 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11119 while (*s != NUL)
11120 {
11121 func_mb_ptr2char_adv(&s);
11122 ++len;
11123 }
11124 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011125 }
11126}
11127
11128/*
11129 * "strdisplaywidth()" function
11130 */
11131 static void
11132f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11133{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011134 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011135 int col = 0;
11136
11137 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011138 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011139
11140 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11141}
11142
11143/*
11144 * "strwidth()" function
11145 */
11146 static void
11147f_strwidth(typval_T *argvars, typval_T *rettv)
11148{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011149 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011150
Bram Moolenaar13505972019-01-24 15:04:48 +010011151 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152}
11153
11154/*
11155 * "strcharpart()" function
11156 */
11157 static void
11158f_strcharpart(typval_T *argvars, typval_T *rettv)
11159{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011160 char_u *p;
11161 int nchar;
11162 int nbyte = 0;
11163 int charlen;
11164 int len = 0;
11165 int slen;
11166 int error = FALSE;
11167
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011168 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011169 slen = (int)STRLEN(p);
11170
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011171 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011172 if (!error)
11173 {
11174 if (nchar > 0)
11175 while (nchar > 0 && nbyte < slen)
11176 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011177 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011178 --nchar;
11179 }
11180 else
11181 nbyte = nchar;
11182 if (argvars[2].v_type != VAR_UNKNOWN)
11183 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011184 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011185 while (charlen > 0 && nbyte + len < slen)
11186 {
11187 int off = nbyte + len;
11188
11189 if (off < 0)
11190 len += 1;
11191 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011192 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011193 --charlen;
11194 }
11195 }
11196 else
11197 len = slen - nbyte; /* default: all bytes that are available. */
11198 }
11199
11200 /*
11201 * Only return the overlap between the specified part and the actual
11202 * string.
11203 */
11204 if (nbyte < 0)
11205 {
11206 len += nbyte;
11207 nbyte = 0;
11208 }
11209 else if (nbyte > slen)
11210 nbyte = slen;
11211 if (len < 0)
11212 len = 0;
11213 else if (nbyte + len > slen)
11214 len = slen - nbyte;
11215
11216 rettv->v_type = VAR_STRING;
11217 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011218}
11219
11220/*
11221 * "strpart()" function
11222 */
11223 static void
11224f_strpart(typval_T *argvars, typval_T *rettv)
11225{
11226 char_u *p;
11227 int n;
11228 int len;
11229 int slen;
11230 int error = FALSE;
11231
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011232 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011233 slen = (int)STRLEN(p);
11234
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011235 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011236 if (error)
11237 len = 0;
11238 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011239 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011240 else
11241 len = slen - n; /* default len: all bytes that are available. */
11242
11243 /*
11244 * Only return the overlap between the specified part and the actual
11245 * string.
11246 */
11247 if (n < 0)
11248 {
11249 len += n;
11250 n = 0;
11251 }
11252 else if (n > slen)
11253 n = slen;
11254 if (len < 0)
11255 len = 0;
11256 else if (n + len > slen)
11257 len = slen - n;
11258
11259 rettv->v_type = VAR_STRING;
11260 rettv->vval.v_string = vim_strnsave(p + n, len);
11261}
11262
11263/*
11264 * "strridx()" function
11265 */
11266 static void
11267f_strridx(typval_T *argvars, typval_T *rettv)
11268{
11269 char_u buf[NUMBUFLEN];
11270 char_u *needle;
11271 char_u *haystack;
11272 char_u *rest;
11273 char_u *lastmatch = NULL;
11274 int haystack_len, end_idx;
11275
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011276 needle = tv_get_string_chk(&argvars[1]);
11277 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011278
11279 rettv->vval.v_number = -1;
11280 if (needle == NULL || haystack == NULL)
11281 return; /* type error; errmsg already given */
11282
11283 haystack_len = (int)STRLEN(haystack);
11284 if (argvars[2].v_type != VAR_UNKNOWN)
11285 {
11286 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011287 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011288 if (end_idx < 0)
11289 return; /* can never find a match */
11290 }
11291 else
11292 end_idx = haystack_len;
11293
11294 if (*needle == NUL)
11295 {
11296 /* Empty string matches past the end. */
11297 lastmatch = haystack + end_idx;
11298 }
11299 else
11300 {
11301 for (rest = haystack; *rest != '\0'; ++rest)
11302 {
11303 rest = (char_u *)strstr((char *)rest, (char *)needle);
11304 if (rest == NULL || rest > haystack + end_idx)
11305 break;
11306 lastmatch = rest;
11307 }
11308 }
11309
11310 if (lastmatch == NULL)
11311 rettv->vval.v_number = -1;
11312 else
11313 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11314}
11315
11316/*
11317 * "strtrans()" function
11318 */
11319 static void
11320f_strtrans(typval_T *argvars, typval_T *rettv)
11321{
11322 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011323 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011324}
11325
11326/*
11327 * "submatch()" function
11328 */
11329 static void
11330f_submatch(typval_T *argvars, typval_T *rettv)
11331{
11332 int error = FALSE;
11333 int no;
11334 int retList = 0;
11335
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011336 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011337 if (error)
11338 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011339 if (no < 0 || no >= NSUBEXP)
11340 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011341 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011342 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011343 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011344 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011345 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011346 if (error)
11347 return;
11348
11349 if (retList == 0)
11350 {
11351 rettv->v_type = VAR_STRING;
11352 rettv->vval.v_string = reg_submatch(no);
11353 }
11354 else
11355 {
11356 rettv->v_type = VAR_LIST;
11357 rettv->vval.v_list = reg_submatch_list(no);
11358 }
11359}
11360
11361/*
11362 * "substitute()" function
11363 */
11364 static void
11365f_substitute(typval_T *argvars, typval_T *rettv)
11366{
11367 char_u patbuf[NUMBUFLEN];
11368 char_u subbuf[NUMBUFLEN];
11369 char_u flagsbuf[NUMBUFLEN];
11370
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011371 char_u *str = tv_get_string_chk(&argvars[0]);
11372 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011373 char_u *sub = NULL;
11374 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011375 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011376
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011377 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11378 expr = &argvars[2];
11379 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011380 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011381
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011382 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011383 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11384 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011385 rettv->vval.v_string = NULL;
11386 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011387 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011388}
11389
11390/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011391 * "swapinfo(swap_filename)" function
11392 */
11393 static void
11394f_swapinfo(typval_T *argvars, typval_T *rettv)
11395{
11396 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011397 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011398}
11399
11400/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011401 * "swapname(expr)" function
11402 */
11403 static void
11404f_swapname(typval_T *argvars, typval_T *rettv)
11405{
11406 buf_T *buf;
11407
11408 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011409 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011410 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11411 || buf->b_ml.ml_mfp->mf_fname == NULL)
11412 rettv->vval.v_string = NULL;
11413 else
11414 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11415}
11416
11417/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011418 * "synID(lnum, col, trans)" function
11419 */
11420 static void
11421f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11422{
11423 int id = 0;
11424#ifdef FEAT_SYN_HL
11425 linenr_T lnum;
11426 colnr_T col;
11427 int trans;
11428 int transerr = FALSE;
11429
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011430 lnum = tv_get_lnum(argvars); /* -1 on type error */
11431 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11432 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011433
11434 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11435 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11436 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11437#endif
11438
11439 rettv->vval.v_number = id;
11440}
11441
11442/*
11443 * "synIDattr(id, what [, mode])" function
11444 */
11445 static void
11446f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11447{
11448 char_u *p = NULL;
11449#ifdef FEAT_SYN_HL
11450 int id;
11451 char_u *what;
11452 char_u *mode;
11453 char_u modebuf[NUMBUFLEN];
11454 int modec;
11455
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011456 id = (int)tv_get_number(&argvars[0]);
11457 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011458 if (argvars[2].v_type != VAR_UNKNOWN)
11459 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011460 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011461 modec = TOLOWER_ASC(mode[0]);
11462 if (modec != 't' && modec != 'c' && modec != 'g')
11463 modec = 0; /* replace invalid with current */
11464 }
11465 else
11466 {
11467#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11468 if (USE_24BIT)
11469 modec = 'g';
11470 else
11471#endif
11472 if (t_colors > 1)
11473 modec = 'c';
11474 else
11475 modec = 't';
11476 }
11477
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011478 switch (TOLOWER_ASC(what[0]))
11479 {
11480 case 'b':
11481 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11482 p = highlight_color(id, what, modec);
11483 else /* bold */
11484 p = highlight_has_attr(id, HL_BOLD, modec);
11485 break;
11486
11487 case 'f': /* fg[#] or font */
11488 p = highlight_color(id, what, modec);
11489 break;
11490
11491 case 'i':
11492 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11493 p = highlight_has_attr(id, HL_INVERSE, modec);
11494 else /* italic */
11495 p = highlight_has_attr(id, HL_ITALIC, modec);
11496 break;
11497
11498 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011499 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011500 break;
11501
11502 case 'r': /* reverse */
11503 p = highlight_has_attr(id, HL_INVERSE, modec);
11504 break;
11505
11506 case 's':
11507 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11508 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011509 /* strikeout */
11510 else if (TOLOWER_ASC(what[1]) == 't' &&
11511 TOLOWER_ASC(what[2]) == 'r')
11512 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011513 else /* standout */
11514 p = highlight_has_attr(id, HL_STANDOUT, modec);
11515 break;
11516
11517 case 'u':
11518 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11519 /* underline */
11520 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11521 else
11522 /* undercurl */
11523 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11524 break;
11525 }
11526
11527 if (p != NULL)
11528 p = vim_strsave(p);
11529#endif
11530 rettv->v_type = VAR_STRING;
11531 rettv->vval.v_string = p;
11532}
11533
11534/*
11535 * "synIDtrans(id)" function
11536 */
11537 static void
11538f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11539{
11540 int id;
11541
11542#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011543 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011544
11545 if (id > 0)
11546 id = syn_get_final_id(id);
11547 else
11548#endif
11549 id = 0;
11550
11551 rettv->vval.v_number = id;
11552}
11553
11554/*
11555 * "synconcealed(lnum, col)" function
11556 */
11557 static void
11558f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11559{
11560#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11561 linenr_T lnum;
11562 colnr_T col;
11563 int syntax_flags = 0;
11564 int cchar;
11565 int matchid = 0;
11566 char_u str[NUMBUFLEN];
11567#endif
11568
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011569 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011570
11571#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011572 lnum = tv_get_lnum(argvars); /* -1 on type error */
11573 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011574
11575 vim_memset(str, NUL, sizeof(str));
11576
11577 if (rettv_list_alloc(rettv) != FAIL)
11578 {
11579 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11580 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11581 && curwin->w_p_cole > 0)
11582 {
11583 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11584 syntax_flags = get_syntax_info(&matchid);
11585
11586 /* get the conceal character */
11587 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11588 {
11589 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011590 if (cchar == NUL && curwin->w_p_cole == 1)
11591 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011592 if (cchar != NUL)
11593 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011594 if (has_mbyte)
11595 (*mb_char2bytes)(cchar, str);
11596 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011597 str[0] = cchar;
11598 }
11599 }
11600 }
11601
11602 list_append_number(rettv->vval.v_list,
11603 (syntax_flags & HL_CONCEAL) != 0);
11604 /* -1 to auto-determine strlen */
11605 list_append_string(rettv->vval.v_list, str, -1);
11606 list_append_number(rettv->vval.v_list, matchid);
11607 }
11608#endif
11609}
11610
11611/*
11612 * "synstack(lnum, col)" function
11613 */
11614 static void
11615f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11616{
11617#ifdef FEAT_SYN_HL
11618 linenr_T lnum;
11619 colnr_T col;
11620 int i;
11621 int id;
11622#endif
11623
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011624 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011625
11626#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011627 lnum = tv_get_lnum(argvars); /* -1 on type error */
11628 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011629
11630 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11631 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11632 && rettv_list_alloc(rettv) != FAIL)
11633 {
11634 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11635 for (i = 0; ; ++i)
11636 {
11637 id = syn_get_stack_item(i);
11638 if (id < 0)
11639 break;
11640 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11641 break;
11642 }
11643 }
11644#endif
11645}
11646
11647 static void
11648get_cmd_output_as_rettv(
11649 typval_T *argvars,
11650 typval_T *rettv,
11651 int retlist)
11652{
11653 char_u *res = NULL;
11654 char_u *p;
11655 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011656 int err = FALSE;
11657 FILE *fd;
11658 list_T *list = NULL;
11659 int flags = SHELL_SILENT;
11660
11661 rettv->v_type = VAR_STRING;
11662 rettv->vval.v_string = NULL;
11663 if (check_restricted() || check_secure())
11664 goto errret;
11665
11666 if (argvars[1].v_type != VAR_UNKNOWN)
11667 {
11668 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011669 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011670 * command.
11671 */
11672 if ((infile = vim_tempname('i', TRUE)) == NULL)
11673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011674 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011675 goto errret;
11676 }
11677
11678 fd = mch_fopen((char *)infile, WRITEBIN);
11679 if (fd == NULL)
11680 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011681 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011682 goto errret;
11683 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011684 if (argvars[1].v_type == VAR_NUMBER)
11685 {
11686 linenr_T lnum;
11687 buf_T *buf;
11688
11689 buf = buflist_findnr(argvars[1].vval.v_number);
11690 if (buf == NULL)
11691 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011692 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011693 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011694 goto errret;
11695 }
11696
11697 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11698 {
11699 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11700 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11701 {
11702 err = TRUE;
11703 break;
11704 }
11705 if (putc(NL, fd) == EOF)
11706 {
11707 err = TRUE;
11708 break;
11709 }
11710 }
11711 }
11712 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011713 {
11714 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11715 err = TRUE;
11716 }
11717 else
11718 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011719 size_t len;
11720 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011721
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011722 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011723 if (p == NULL)
11724 {
11725 fclose(fd);
11726 goto errret; /* type error; errmsg already given */
11727 }
11728 len = STRLEN(p);
11729 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11730 err = TRUE;
11731 }
11732 if (fclose(fd) != 0)
11733 err = TRUE;
11734 if (err)
11735 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011736 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011737 goto errret;
11738 }
11739 }
11740
11741 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11742 * echoes typeahead, that messes up the display. */
11743 if (!msg_silent)
11744 flags += SHELL_COOKED;
11745
11746 if (retlist)
11747 {
11748 int len;
11749 listitem_T *li;
11750 char_u *s = NULL;
11751 char_u *start;
11752 char_u *end;
11753 int i;
11754
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011755 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011756 if (res == NULL)
11757 goto errret;
11758
11759 list = list_alloc();
11760 if (list == NULL)
11761 goto errret;
11762
11763 for (i = 0; i < len; ++i)
11764 {
11765 start = res + i;
11766 while (i < len && res[i] != NL)
11767 ++i;
11768 end = res + i;
11769
Bram Moolenaar964b3742019-05-24 18:54:09 +020011770 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011771 if (s == NULL)
11772 goto errret;
11773
11774 for (p = s; start < end; ++p, ++start)
11775 *p = *start == NUL ? NL : *start;
11776 *p = NUL;
11777
11778 li = listitem_alloc();
11779 if (li == NULL)
11780 {
11781 vim_free(s);
11782 goto errret;
11783 }
11784 li->li_tv.v_type = VAR_STRING;
11785 li->li_tv.v_lock = 0;
11786 li->li_tv.vval.v_string = s;
11787 list_append(list, li);
11788 }
11789
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011790 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011791 list = NULL;
11792 }
11793 else
11794 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011795 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011796#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011797 /* translate <CR><NL> into <NL> */
11798 if (res != NULL)
11799 {
11800 char_u *s, *d;
11801
11802 d = res;
11803 for (s = res; *s; ++s)
11804 {
11805 if (s[0] == CAR && s[1] == NL)
11806 ++s;
11807 *d++ = *s;
11808 }
11809 *d = NUL;
11810 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011811#endif
11812 rettv->vval.v_string = res;
11813 res = NULL;
11814 }
11815
11816errret:
11817 if (infile != NULL)
11818 {
11819 mch_remove(infile);
11820 vim_free(infile);
11821 }
11822 if (res != NULL)
11823 vim_free(res);
11824 if (list != NULL)
11825 list_free(list);
11826}
11827
11828/*
11829 * "system()" function
11830 */
11831 static void
11832f_system(typval_T *argvars, typval_T *rettv)
11833{
11834 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11835}
11836
11837/*
11838 * "systemlist()" function
11839 */
11840 static void
11841f_systemlist(typval_T *argvars, typval_T *rettv)
11842{
11843 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11844}
11845
11846/*
11847 * "tabpagebuflist()" function
11848 */
11849 static void
11850f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11851{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011852 tabpage_T *tp;
11853 win_T *wp = NULL;
11854
11855 if (argvars[0].v_type == VAR_UNKNOWN)
11856 wp = firstwin;
11857 else
11858 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011859 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011860 if (tp != NULL)
11861 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11862 }
11863 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11864 {
11865 for (; wp != NULL; wp = wp->w_next)
11866 if (list_append_number(rettv->vval.v_list,
11867 wp->w_buffer->b_fnum) == FAIL)
11868 break;
11869 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011870}
11871
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011872/*
11873 * "tabpagenr()" function
11874 */
11875 static void
11876f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11877{
11878 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011879 char_u *arg;
11880
11881 if (argvars[0].v_type != VAR_UNKNOWN)
11882 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011883 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011884 nr = 0;
11885 if (arg != NULL)
11886 {
11887 if (STRCMP(arg, "$") == 0)
11888 nr = tabpage_index(NULL) - 1;
11889 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011890 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011891 }
11892 }
11893 else
11894 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011895 rettv->vval.v_number = nr;
11896}
11897
11898
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011899/*
11900 * Common code for tabpagewinnr() and winnr().
11901 */
11902 static int
11903get_winnr(tabpage_T *tp, typval_T *argvar)
11904{
11905 win_T *twin;
11906 int nr = 1;
11907 win_T *wp;
11908 char_u *arg;
11909
11910 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11911 if (argvar->v_type != VAR_UNKNOWN)
11912 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011913 int invalid_arg = FALSE;
11914
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011915 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011916 if (arg == NULL)
11917 nr = 0; /* type error; errmsg already given */
11918 else if (STRCMP(arg, "$") == 0)
11919 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11920 else if (STRCMP(arg, "#") == 0)
11921 {
11922 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11923 if (twin == NULL)
11924 nr = 0;
11925 }
11926 else
11927 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011928 long count;
11929 char_u *endp;
11930
11931 // Extract the window count (if specified). e.g. winnr('3j')
11932 count = strtol((char *)arg, (char **)&endp, 10);
11933 if (count <= 0)
11934 count = 1; // if count is not specified, default to 1
11935 if (endp != NULL && *endp != '\0')
11936 {
11937 if (STRCMP(endp, "j") == 0)
11938 twin = win_vert_neighbor(tp, twin, FALSE, count);
11939 else if (STRCMP(endp, "k") == 0)
11940 twin = win_vert_neighbor(tp, twin, TRUE, count);
11941 else if (STRCMP(endp, "h") == 0)
11942 twin = win_horz_neighbor(tp, twin, TRUE, count);
11943 else if (STRCMP(endp, "l") == 0)
11944 twin = win_horz_neighbor(tp, twin, FALSE, count);
11945 else
11946 invalid_arg = TRUE;
11947 }
11948 else
11949 invalid_arg = TRUE;
11950 }
11951
11952 if (invalid_arg)
11953 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011954 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011955 nr = 0;
11956 }
11957 }
11958
11959 if (nr > 0)
11960 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11961 wp != twin; wp = wp->w_next)
11962 {
11963 if (wp == NULL)
11964 {
11965 /* didn't find it in this tabpage */
11966 nr = 0;
11967 break;
11968 }
11969 ++nr;
11970 }
11971 return nr;
11972}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011973
11974/*
11975 * "tabpagewinnr()" function
11976 */
11977 static void
11978f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11979{
11980 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011981 tabpage_T *tp;
11982
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011983 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011984 if (tp == NULL)
11985 nr = 0;
11986 else
11987 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011988 rettv->vval.v_number = nr;
11989}
11990
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011991/*
11992 * "tagfiles()" function
11993 */
11994 static void
11995f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11996{
11997 char_u *fname;
11998 tagname_T tn;
11999 int first;
12000
12001 if (rettv_list_alloc(rettv) == FAIL)
12002 return;
12003 fname = alloc(MAXPATHL);
12004 if (fname == NULL)
12005 return;
12006
12007 for (first = TRUE; ; first = FALSE)
12008 if (get_tagfname(&tn, first, fname) == FAIL
12009 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12010 break;
12011 tagname_free(&tn);
12012 vim_free(fname);
12013}
12014
12015/*
12016 * "taglist()" function
12017 */
12018 static void
12019f_taglist(typval_T *argvars, typval_T *rettv)
12020{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012021 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012022 char_u *tag_pattern;
12023
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012024 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012025
12026 rettv->vval.v_number = FALSE;
12027 if (*tag_pattern == NUL)
12028 return;
12029
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012030 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012031 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012032 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012033 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012034}
12035
12036/*
12037 * "tempname()" function
12038 */
12039 static void
12040f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12041{
12042 static int x = 'A';
12043
12044 rettv->v_type = VAR_STRING;
12045 rettv->vval.v_string = vim_tempname(x, FALSE);
12046
12047 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12048 * names. Skip 'I' and 'O', they are used for shell redirection. */
12049 do
12050 {
12051 if (x == 'Z')
12052 x = '0';
12053 else if (x == '9')
12054 x = 'A';
12055 else
12056 {
12057#ifdef EBCDIC
12058 if (x == 'I')
12059 x = 'J';
12060 else if (x == 'R')
12061 x = 'S';
12062 else
12063#endif
12064 ++x;
12065 }
12066 } while (x == 'I' || x == 'O');
12067}
12068
12069#ifdef FEAT_FLOAT
12070/*
12071 * "tan()" function
12072 */
12073 static void
12074f_tan(typval_T *argvars, typval_T *rettv)
12075{
12076 float_T f = 0.0;
12077
12078 rettv->v_type = VAR_FLOAT;
12079 if (get_float_arg(argvars, &f) == OK)
12080 rettv->vval.v_float = tan(f);
12081 else
12082 rettv->vval.v_float = 0.0;
12083}
12084
12085/*
12086 * "tanh()" function
12087 */
12088 static void
12089f_tanh(typval_T *argvars, typval_T *rettv)
12090{
12091 float_T f = 0.0;
12092
12093 rettv->v_type = VAR_FLOAT;
12094 if (get_float_arg(argvars, &f) == OK)
12095 rettv->vval.v_float = tanh(f);
12096 else
12097 rettv->vval.v_float = 0.0;
12098}
12099#endif
12100
12101/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012102 * Get a callback from "arg". It can be a Funcref or a function name.
12103 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012104 * "cb_name" is not allocated.
12105 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012106 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012107 callback_T
12108get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012109{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012110 callback_T res;
12111
12112 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012113 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12114 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012115 res.cb_partial = arg->vval.v_partial;
12116 ++res.cb_partial->pt_refcount;
12117 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012118 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012119 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012120 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012121 res.cb_partial = NULL;
12122 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12123 {
12124 // Note that we don't make a copy of the string.
12125 res.cb_name = arg->vval.v_string;
12126 func_ref(res.cb_name);
12127 }
12128 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12129 {
12130 res.cb_name = (char_u *)"";
12131 }
12132 else
12133 {
12134 emsg(_("E921: Invalid callback argument"));
12135 res.cb_name = NULL;
12136 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012137 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012138 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012139}
12140
12141/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012142 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012143 */
12144 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012145put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012146{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012147 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012148 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012149 tv->v_type = VAR_PARTIAL;
12150 tv->vval.v_partial = cb->cb_partial;
12151 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012152 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012153 else
12154 {
12155 tv->v_type = VAR_FUNC;
12156 tv->vval.v_string = vim_strsave(cb->cb_name);
12157 func_ref(cb->cb_name);
12158 }
12159}
12160
12161/*
12162 * Make a copy of "src" into "dest", allocating the function name if needed,
12163 * without incrementing the refcount.
12164 */
12165 void
12166set_callback(callback_T *dest, callback_T *src)
12167{
12168 if (src->cb_partial == NULL)
12169 {
12170 // just a function name, make a copy
12171 dest->cb_name = vim_strsave(src->cb_name);
12172 dest->cb_free_name = TRUE;
12173 }
12174 else
12175 {
12176 // cb_name is a pointer into cb_partial
12177 dest->cb_name = src->cb_name;
12178 dest->cb_free_name = FALSE;
12179 }
12180 dest->cb_partial = src->cb_partial;
12181}
12182
12183/*
12184 * Unref/free "callback" returned by get_callback() or set_callback().
12185 */
12186 void
12187free_callback(callback_T *callback)
12188{
12189 if (callback->cb_partial != NULL)
12190 {
12191 partial_unref(callback->cb_partial);
12192 callback->cb_partial = NULL;
12193 }
12194 else if (callback->cb_name != NULL)
12195 func_unref(callback->cb_name);
12196 if (callback->cb_free_name)
12197 {
12198 vim_free(callback->cb_name);
12199 callback->cb_free_name = FALSE;
12200 }
12201 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012202}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012203
12204#ifdef FEAT_TIMERS
12205/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012206 * "timer_info([timer])" function
12207 */
12208 static void
12209f_timer_info(typval_T *argvars, typval_T *rettv)
12210{
12211 timer_T *timer = NULL;
12212
12213 if (rettv_list_alloc(rettv) != OK)
12214 return;
12215 if (argvars[0].v_type != VAR_UNKNOWN)
12216 {
12217 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012218 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012219 else
12220 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012221 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012222 if (timer != NULL)
12223 add_timer_info(rettv, timer);
12224 }
12225 }
12226 else
12227 add_timer_info_all(rettv);
12228}
12229
12230/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012231 * "timer_pause(timer, paused)" function
12232 */
12233 static void
12234f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12235{
12236 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012237 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012238
12239 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012240 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012241 else
12242 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012243 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012244 if (timer != NULL)
12245 timer->tr_paused = paused;
12246 }
12247}
12248
12249/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012250 * "timer_start(time, callback [, options])" function
12251 */
12252 static void
12253f_timer_start(typval_T *argvars, typval_T *rettv)
12254{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012255 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012256 timer_T *timer;
12257 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012258 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012259 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012260
Bram Moolenaar75537a92016-09-05 22:45:28 +020012261 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012262 if (check_secure())
12263 return;
12264 if (argvars[2].v_type != VAR_UNKNOWN)
12265 {
12266 if (argvars[2].v_type != VAR_DICT
12267 || (dict = argvars[2].vval.v_dict) == NULL)
12268 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012269 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012270 return;
12271 }
12272 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012273 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012274 }
12275
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012276 callback = get_callback(&argvars[1]);
12277 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012278 return;
12279
12280 timer = create_timer(msec, repeat);
12281 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012282 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012283 else
12284 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012285 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012286 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012287 }
12288}
12289
12290/*
12291 * "timer_stop(timer)" function
12292 */
12293 static void
12294f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12295{
12296 timer_T *timer;
12297
12298 if (argvars[0].v_type != VAR_NUMBER)
12299 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012300 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012301 return;
12302 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012303 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012304 if (timer != NULL)
12305 stop_timer(timer);
12306}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012307
12308/*
12309 * "timer_stopall()" function
12310 */
12311 static void
12312f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12313{
12314 stop_all_timers();
12315}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012316#endif
12317
12318/*
12319 * "tolower(string)" function
12320 */
12321 static void
12322f_tolower(typval_T *argvars, typval_T *rettv)
12323{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012324 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012325 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012326}
12327
12328/*
12329 * "toupper(string)" function
12330 */
12331 static void
12332f_toupper(typval_T *argvars, typval_T *rettv)
12333{
12334 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012335 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012336}
12337
12338/*
12339 * "tr(string, fromstr, tostr)" function
12340 */
12341 static void
12342f_tr(typval_T *argvars, typval_T *rettv)
12343{
12344 char_u *in_str;
12345 char_u *fromstr;
12346 char_u *tostr;
12347 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012348 int inlen;
12349 int fromlen;
12350 int tolen;
12351 int idx;
12352 char_u *cpstr;
12353 int cplen;
12354 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012355 char_u buf[NUMBUFLEN];
12356 char_u buf2[NUMBUFLEN];
12357 garray_T ga;
12358
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012359 in_str = tv_get_string(&argvars[0]);
12360 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12361 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012362
12363 /* Default return value: empty string. */
12364 rettv->v_type = VAR_STRING;
12365 rettv->vval.v_string = NULL;
12366 if (fromstr == NULL || tostr == NULL)
12367 return; /* type error; errmsg already given */
12368 ga_init2(&ga, (int)sizeof(char), 80);
12369
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012370 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012371 /* not multi-byte: fromstr and tostr must be the same length */
12372 if (STRLEN(fromstr) != STRLEN(tostr))
12373 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012374error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012375 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012376 ga_clear(&ga);
12377 return;
12378 }
12379
12380 /* fromstr and tostr have to contain the same number of chars */
12381 while (*in_str != NUL)
12382 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012383 if (has_mbyte)
12384 {
12385 inlen = (*mb_ptr2len)(in_str);
12386 cpstr = in_str;
12387 cplen = inlen;
12388 idx = 0;
12389 for (p = fromstr; *p != NUL; p += fromlen)
12390 {
12391 fromlen = (*mb_ptr2len)(p);
12392 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12393 {
12394 for (p = tostr; *p != NUL; p += tolen)
12395 {
12396 tolen = (*mb_ptr2len)(p);
12397 if (idx-- == 0)
12398 {
12399 cplen = tolen;
12400 cpstr = p;
12401 break;
12402 }
12403 }
12404 if (*p == NUL) /* tostr is shorter than fromstr */
12405 goto error;
12406 break;
12407 }
12408 ++idx;
12409 }
12410
12411 if (first && cpstr == in_str)
12412 {
12413 /* Check that fromstr and tostr have the same number of
12414 * (multi-byte) characters. Done only once when a character
12415 * of in_str doesn't appear in fromstr. */
12416 first = FALSE;
12417 for (p = tostr; *p != NUL; p += tolen)
12418 {
12419 tolen = (*mb_ptr2len)(p);
12420 --idx;
12421 }
12422 if (idx != 0)
12423 goto error;
12424 }
12425
12426 (void)ga_grow(&ga, cplen);
12427 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12428 ga.ga_len += cplen;
12429
12430 in_str += inlen;
12431 }
12432 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012433 {
12434 /* When not using multi-byte chars we can do it faster. */
12435 p = vim_strchr(fromstr, *in_str);
12436 if (p != NULL)
12437 ga_append(&ga, tostr[p - fromstr]);
12438 else
12439 ga_append(&ga, *in_str);
12440 ++in_str;
12441 }
12442 }
12443
12444 /* add a terminating NUL */
12445 (void)ga_grow(&ga, 1);
12446 ga_append(&ga, NUL);
12447
12448 rettv->vval.v_string = ga.ga_data;
12449}
12450
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012451/*
12452 * "trim({expr})" function
12453 */
12454 static void
12455f_trim(typval_T *argvars, typval_T *rettv)
12456{
12457 char_u buf1[NUMBUFLEN];
12458 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012459 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012460 char_u *mask = NULL;
12461 char_u *tail;
12462 char_u *prev;
12463 char_u *p;
12464 int c1;
12465
12466 rettv->v_type = VAR_STRING;
12467 if (head == NULL)
12468 {
12469 rettv->vval.v_string = NULL;
12470 return;
12471 }
12472
12473 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012474 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012475
12476 while (*head != NUL)
12477 {
12478 c1 = PTR2CHAR(head);
12479 if (mask == NULL)
12480 {
12481 if (c1 > ' ' && c1 != 0xa0)
12482 break;
12483 }
12484 else
12485 {
12486 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12487 if (c1 == PTR2CHAR(p))
12488 break;
12489 if (*p == NUL)
12490 break;
12491 }
12492 MB_PTR_ADV(head);
12493 }
12494
12495 for (tail = head + STRLEN(head); tail > head; tail = prev)
12496 {
12497 prev = tail;
12498 MB_PTR_BACK(head, prev);
12499 c1 = PTR2CHAR(prev);
12500 if (mask == NULL)
12501 {
12502 if (c1 > ' ' && c1 != 0xa0)
12503 break;
12504 }
12505 else
12506 {
12507 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12508 if (c1 == PTR2CHAR(p))
12509 break;
12510 if (*p == NUL)
12511 break;
12512 }
12513 }
12514 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12515}
12516
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012517#ifdef FEAT_FLOAT
12518/*
12519 * "trunc({float})" function
12520 */
12521 static void
12522f_trunc(typval_T *argvars, typval_T *rettv)
12523{
12524 float_T f = 0.0;
12525
12526 rettv->v_type = VAR_FLOAT;
12527 if (get_float_arg(argvars, &f) == OK)
12528 /* trunc() is not in C90, use floor() or ceil() instead. */
12529 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12530 else
12531 rettv->vval.v_float = 0.0;
12532}
12533#endif
12534
12535/*
12536 * "type(expr)" function
12537 */
12538 static void
12539f_type(typval_T *argvars, typval_T *rettv)
12540{
12541 int n = -1;
12542
12543 switch (argvars[0].v_type)
12544 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012545 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12546 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012547 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012548 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12549 case VAR_LIST: n = VAR_TYPE_LIST; break;
12550 case VAR_DICT: n = VAR_TYPE_DICT; break;
12551 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012552 case VAR_SPECIAL:
12553 if (argvars[0].vval.v_number == VVAL_FALSE
12554 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012555 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012556 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012557 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012558 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012559 case VAR_JOB: n = VAR_TYPE_JOB; break;
12560 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012561 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012562 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012563 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012564 n = -1;
12565 break;
12566 }
12567 rettv->vval.v_number = n;
12568}
12569
12570/*
12571 * "undofile(name)" function
12572 */
12573 static void
12574f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12575{
12576 rettv->v_type = VAR_STRING;
12577#ifdef FEAT_PERSISTENT_UNDO
12578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012579 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012580
12581 if (*fname == NUL)
12582 {
12583 /* If there is no file name there will be no undo file. */
12584 rettv->vval.v_string = NULL;
12585 }
12586 else
12587 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012588 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012589
12590 if (ffname != NULL)
12591 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12592 vim_free(ffname);
12593 }
12594 }
12595#else
12596 rettv->vval.v_string = NULL;
12597#endif
12598}
12599
12600/*
12601 * "undotree()" function
12602 */
12603 static void
12604f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12605{
12606 if (rettv_dict_alloc(rettv) == OK)
12607 {
12608 dict_T *dict = rettv->vval.v_dict;
12609 list_T *list;
12610
Bram Moolenaare0be1672018-07-08 16:50:37 +020012611 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12612 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12613 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12614 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12615 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12616 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012617
12618 list = list_alloc();
12619 if (list != NULL)
12620 {
12621 u_eval_tree(curbuf->b_u_oldhead, list);
12622 dict_add_list(dict, "entries", list);
12623 }
12624 }
12625}
12626
12627/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012628 * "virtcol(string)" function
12629 */
12630 static void
12631f_virtcol(typval_T *argvars, typval_T *rettv)
12632{
12633 colnr_T vcol = 0;
12634 pos_T *fp;
12635 int fnum = curbuf->b_fnum;
12636
12637 fp = var2fpos(&argvars[0], FALSE, &fnum);
12638 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12639 && fnum == curbuf->b_fnum)
12640 {
12641 getvvcol(curwin, fp, NULL, NULL, &vcol);
12642 ++vcol;
12643 }
12644
12645 rettv->vval.v_number = vcol;
12646}
12647
12648/*
12649 * "visualmode()" function
12650 */
12651 static void
12652f_visualmode(typval_T *argvars, typval_T *rettv)
12653{
12654 char_u str[2];
12655
12656 rettv->v_type = VAR_STRING;
12657 str[0] = curbuf->b_visual_mode_eval;
12658 str[1] = NUL;
12659 rettv->vval.v_string = vim_strsave(str);
12660
12661 /* A non-zero number or non-empty string argument: reset mode. */
12662 if (non_zero_arg(&argvars[0]))
12663 curbuf->b_visual_mode_eval = NUL;
12664}
12665
12666/*
12667 * "wildmenumode()" function
12668 */
12669 static void
12670f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12671{
12672#ifdef FEAT_WILDMENU
12673 if (wild_menu_showing)
12674 rettv->vval.v_number = 1;
12675#endif
12676}
12677
12678/*
12679 * "winbufnr(nr)" function
12680 */
12681 static void
12682f_winbufnr(typval_T *argvars, typval_T *rettv)
12683{
12684 win_T *wp;
12685
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012686 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012687 if (wp == NULL)
12688 rettv->vval.v_number = -1;
12689 else
12690 rettv->vval.v_number = wp->w_buffer->b_fnum;
12691}
12692
12693/*
12694 * "wincol()" function
12695 */
12696 static void
12697f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12698{
12699 validate_cursor();
12700 rettv->vval.v_number = curwin->w_wcol + 1;
12701}
12702
12703/*
12704 * "winheight(nr)" function
12705 */
12706 static void
12707f_winheight(typval_T *argvars, typval_T *rettv)
12708{
12709 win_T *wp;
12710
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012711 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012712 if (wp == NULL)
12713 rettv->vval.v_number = -1;
12714 else
12715 rettv->vval.v_number = wp->w_height;
12716}
12717
12718/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012719 * "winlayout()" function
12720 */
12721 static void
12722f_winlayout(typval_T *argvars, typval_T *rettv)
12723{
12724 tabpage_T *tp;
12725
12726 if (rettv_list_alloc(rettv) != OK)
12727 return;
12728
12729 if (argvars[0].v_type == VAR_UNKNOWN)
12730 tp = curtab;
12731 else
12732 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012733 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012734 if (tp == NULL)
12735 return;
12736 }
12737
12738 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12739}
12740
12741/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012742 * "winline()" function
12743 */
12744 static void
12745f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12746{
12747 validate_cursor();
12748 rettv->vval.v_number = curwin->w_wrow + 1;
12749}
12750
12751/*
12752 * "winnr()" function
12753 */
12754 static void
12755f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12756{
12757 int nr = 1;
12758
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012759 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012760 rettv->vval.v_number = nr;
12761}
12762
12763/*
12764 * "winrestcmd()" function
12765 */
12766 static void
12767f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12768{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012769 win_T *wp;
12770 int winnr = 1;
12771 garray_T ga;
12772 char_u buf[50];
12773
12774 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012775 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012776 {
12777 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12778 ga_concat(&ga, buf);
12779 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12780 ga_concat(&ga, buf);
12781 ++winnr;
12782 }
12783 ga_append(&ga, NUL);
12784
12785 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012786 rettv->v_type = VAR_STRING;
12787}
12788
12789/*
12790 * "winrestview()" function
12791 */
12792 static void
12793f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12794{
12795 dict_T *dict;
12796
12797 if (argvars[0].v_type != VAR_DICT
12798 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012799 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012800 else
12801 {
12802 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012803 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012804 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012805 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012806 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012807 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012808 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12809 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012810 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012811 curwin->w_set_curswant = FALSE;
12812 }
12813
12814 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012815 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012816#ifdef FEAT_DIFF
12817 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012818 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012819#endif
12820 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012821 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012822 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012823 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012824
12825 check_cursor();
12826 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012827 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012828 changed_window_setting();
12829
12830 if (curwin->w_topline <= 0)
12831 curwin->w_topline = 1;
12832 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12833 curwin->w_topline = curbuf->b_ml.ml_line_count;
12834#ifdef FEAT_DIFF
12835 check_topfill(curwin, TRUE);
12836#endif
12837 }
12838}
12839
12840/*
12841 * "winsaveview()" function
12842 */
12843 static void
12844f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12845{
12846 dict_T *dict;
12847
12848 if (rettv_dict_alloc(rettv) == FAIL)
12849 return;
12850 dict = rettv->vval.v_dict;
12851
Bram Moolenaare0be1672018-07-08 16:50:37 +020012852 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12853 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012854 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012855 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012856 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012857
Bram Moolenaare0be1672018-07-08 16:50:37 +020012858 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012859#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012860 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012861#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012862 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12863 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012864}
12865
12866/*
12867 * "winwidth(nr)" function
12868 */
12869 static void
12870f_winwidth(typval_T *argvars, typval_T *rettv)
12871{
12872 win_T *wp;
12873
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012874 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012875 if (wp == NULL)
12876 rettv->vval.v_number = -1;
12877 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012878 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012879}
12880
12881/*
12882 * "wordcount()" function
12883 */
12884 static void
12885f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12886{
12887 if (rettv_dict_alloc(rettv) == FAIL)
12888 return;
12889 cursor_pos_info(rettv->vval.v_dict);
12890}
12891
12892/*
12893 * "writefile()" function
12894 */
12895 static void
12896f_writefile(typval_T *argvars, typval_T *rettv)
12897{
12898 int binary = FALSE;
12899 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012900#ifdef HAVE_FSYNC
12901 int do_fsync = p_fs;
12902#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012903 char_u *fname;
12904 FILE *fd;
12905 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012906 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012907 list_T *list = NULL;
12908 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012909
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012910 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012911 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012912 return;
12913
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012914 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012915 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012916 list = argvars[0].vval.v_list;
12917 if (list == NULL)
12918 return;
12919 for (li = list->lv_first; li != NULL; li = li->li_next)
12920 if (tv_get_string_chk(&li->li_tv) == NULL)
12921 return;
12922 }
12923 else if (argvars[0].v_type == VAR_BLOB)
12924 {
12925 blob = argvars[0].vval.v_blob;
12926 if (blob == NULL)
12927 return;
12928 }
12929 else
12930 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012931 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012932 return;
12933 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012934
12935 if (argvars[2].v_type != VAR_UNKNOWN)
12936 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012937 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012938
12939 if (arg2 == NULL)
12940 return;
12941 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012942 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012943 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012944 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012945#ifdef HAVE_FSYNC
12946 if (vim_strchr(arg2, 's') != NULL)
12947 do_fsync = TRUE;
12948 else if (vim_strchr(arg2, 'S') != NULL)
12949 do_fsync = FALSE;
12950#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012951 }
12952
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012953 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012954 if (fname == NULL)
12955 return;
12956
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012957 /* Always open the file in binary mode, library functions have a mind of
12958 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012959 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12960 append ? APPENDBIN : WRITEBIN)) == NULL)
12961 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012962 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012963 ret = -1;
12964 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012965 else if (blob)
12966 {
12967 if (write_blob(fd, blob) == FAIL)
12968 ret = -1;
12969#ifdef HAVE_FSYNC
12970 else if (do_fsync)
12971 // Ignore the error, the user wouldn't know what to do about it.
12972 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012973 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012974#endif
12975 fclose(fd);
12976 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012977 else
12978 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012979 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012980 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012981#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012982 else if (do_fsync)
12983 /* Ignore the error, the user wouldn't know what to do about it.
12984 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012985 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012986#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012987 fclose(fd);
12988 }
12989
12990 rettv->vval.v_number = ret;
12991}
12992
12993/*
12994 * "xor(expr, expr)" function
12995 */
12996 static void
12997f_xor(typval_T *argvars, typval_T *rettv)
12998{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012999 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
13000 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013001}
13002
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013003#endif /* FEAT_EVAL */