blob: 7d46f3588662658726800e0022dfda2717bcc109 [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);
Bram Moolenaar91746392019-08-16 22:22:31 +02001116 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001117 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001118 if (global_functions[fi].f_argtype == 0)
1119 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001120 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001121 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001122 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001123 return ERROR_TOOMANY;
1124
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001125 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001126 {
1127 // base value goes last
1128 for (i = 0; i < argcount; ++i)
1129 argv[i] = argvars[i];
1130 argv[argcount] = *basetv;
1131 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001132 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001133 {
1134 // base value goes second
1135 argv[0] = argvars[0];
1136 argv[1] = *basetv;
1137 for (i = 1; i < argcount; ++i)
1138 argv[i + 1] = argvars[i];
1139 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001140 else if (global_functions[fi].f_argtype == FEARG_3)
1141 {
1142 // base value goes third
1143 argv[0] = argvars[0];
1144 argv[1] = argvars[1];
1145 argv[2] = *basetv;
1146 for (i = 2; i < argcount; ++i)
1147 argv[i + 1] = argvars[i];
1148 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001149 else
1150 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001151 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001152 argv[0] = *basetv;
1153 for (i = 0; i < argcount; ++i)
1154 argv[i + 1] = argvars[i];
1155 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001156 argv[argcount + 1].v_type = VAR_UNKNOWN;
1157
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001158 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001159 return ERROR_NONE;
1160}
1161
1162/*
1163 * Return TRUE for a non-zero Number and a non-empty String.
1164 */
1165 static int
1166non_zero_arg(typval_T *argvars)
1167{
1168 return ((argvars[0].v_type == VAR_NUMBER
1169 && argvars[0].vval.v_number != 0)
1170 || (argvars[0].v_type == VAR_SPECIAL
1171 && argvars[0].vval.v_number == VVAL_TRUE)
1172 || (argvars[0].v_type == VAR_STRING
1173 && argvars[0].vval.v_string != NULL
1174 && *argvars[0].vval.v_string != NUL));
1175}
1176
1177/*
1178 * Get the lnum from the first argument.
1179 * Also accepts ".", "$", etc., but that only works for the current buffer.
1180 * Returns -1 on error.
1181 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001182 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001183tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001184{
1185 typval_T rettv;
1186 linenr_T lnum;
1187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001188 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001189 if (lnum == 0) /* no valid number, try using line() */
1190 {
1191 rettv.v_type = VAR_NUMBER;
1192 f_line(argvars, &rettv);
1193 lnum = (linenr_T)rettv.vval.v_number;
1194 clear_tv(&rettv);
1195 }
1196 return lnum;
1197}
1198
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001199/*
1200 * Get the lnum from the first argument.
1201 * Also accepts "$", then "buf" is used.
1202 * Returns 0 on error.
1203 */
1204 static linenr_T
1205tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1206{
1207 if (argvars[0].v_type == VAR_STRING
1208 && argvars[0].vval.v_string != NULL
1209 && argvars[0].vval.v_string[0] == '$'
1210 && buf != NULL)
1211 return buf->b_ml.ml_line_count;
1212 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1213}
1214
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001215#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001216/*
1217 * Get the float value of "argvars[0]" into "f".
1218 * Returns FAIL when the argument is not a Number or Float.
1219 */
1220 static int
1221get_float_arg(typval_T *argvars, float_T *f)
1222{
1223 if (argvars[0].v_type == VAR_FLOAT)
1224 {
1225 *f = argvars[0].vval.v_float;
1226 return OK;
1227 }
1228 if (argvars[0].v_type == VAR_NUMBER)
1229 {
1230 *f = (float_T)argvars[0].vval.v_number;
1231 return OK;
1232 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001233 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001234 return FAIL;
1235}
1236
1237/*
1238 * "abs(expr)" function
1239 */
1240 static void
1241f_abs(typval_T *argvars, typval_T *rettv)
1242{
1243 if (argvars[0].v_type == VAR_FLOAT)
1244 {
1245 rettv->v_type = VAR_FLOAT;
1246 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1247 }
1248 else
1249 {
1250 varnumber_T n;
1251 int error = FALSE;
1252
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001253 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254 if (error)
1255 rettv->vval.v_number = -1;
1256 else if (n > 0)
1257 rettv->vval.v_number = n;
1258 else
1259 rettv->vval.v_number = -n;
1260 }
1261}
1262
1263/*
1264 * "acos()" function
1265 */
1266 static void
1267f_acos(typval_T *argvars, typval_T *rettv)
1268{
1269 float_T f = 0.0;
1270
1271 rettv->v_type = VAR_FLOAT;
1272 if (get_float_arg(argvars, &f) == OK)
1273 rettv->vval.v_float = acos(f);
1274 else
1275 rettv->vval.v_float = 0.0;
1276}
1277#endif
1278
1279/*
1280 * "add(list, item)" function
1281 */
1282 static void
1283f_add(typval_T *argvars, typval_T *rettv)
1284{
1285 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001286 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001287
1288 rettv->vval.v_number = 1; /* Default: Failed */
1289 if (argvars[0].v_type == VAR_LIST)
1290 {
1291 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001292 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 (char_u *)N_("add() argument"), TRUE)
1294 && list_append_tv(l, &argvars[1]) == OK)
1295 copy_tv(&argvars[0], rettv);
1296 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001297 else if (argvars[0].v_type == VAR_BLOB)
1298 {
1299 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001300 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001301 (char_u *)N_("add() argument"), TRUE))
1302 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001303 int error = FALSE;
1304 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1305
1306 if (!error)
1307 {
1308 ga_append(&b->bv_ga, (int)n);
1309 copy_tv(&argvars[0], rettv);
1310 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001311 }
1312 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001314 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001315}
1316
1317/*
1318 * "and(expr, expr)" function
1319 */
1320 static void
1321f_and(typval_T *argvars, typval_T *rettv)
1322{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001323 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1324 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001325}
1326
1327/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001328 * If there is a window for "curbuf", make it the current window.
1329 */
1330 static void
1331find_win_for_curbuf(void)
1332{
1333 wininfo_T *wip;
1334
1335 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1336 {
1337 if (wip->wi_win != NULL)
1338 {
1339 curwin = wip->wi_win;
1340 break;
1341 }
1342 }
1343}
1344
1345/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001346 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347 */
1348 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001349set_buffer_lines(
1350 buf_T *buf,
1351 linenr_T lnum_arg,
1352 int append,
1353 typval_T *lines,
1354 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001355{
Bram Moolenaarca851592018-06-06 21:04:07 +02001356 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1357 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 list_T *l = NULL;
1359 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001361 linenr_T append_lnum;
1362 buf_T *curbuf_save = NULL;
1363 win_T *curwin_save = NULL;
1364 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001365
Bram Moolenaarca851592018-06-06 21:04:07 +02001366 /* When using the current buffer ml_mfp will be set if needed. Useful when
1367 * setline() is used on startup. For other buffers the buffer must be
1368 * loaded. */
1369 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001370 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001371 rettv->vval.v_number = 1; /* FAIL */
1372 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001373 }
1374
Bram Moolenaarca851592018-06-06 21:04:07 +02001375 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001377 curbuf_save = curbuf;
1378 curwin_save = curwin;
1379 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001380 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001381 }
1382
1383 if (append)
1384 // appendbufline() uses the line number below which we insert
1385 append_lnum = lnum - 1;
1386 else
1387 // setbufline() uses the line number above which we insert, we only
1388 // append if it's below the last line
1389 append_lnum = curbuf->b_ml.ml_line_count;
1390
1391 if (lines->v_type == VAR_LIST)
1392 {
1393 l = lines->vval.v_list;
1394 li = l->lv_first;
1395 }
1396 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001397 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001398
1399 /* default result is zero == OK */
1400 for (;;)
1401 {
1402 if (l != NULL)
1403 {
1404 /* list argument, get next string */
1405 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001406 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001407 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001408 li = li->li_next;
1409 }
1410
Bram Moolenaarca851592018-06-06 21:04:07 +02001411 rettv->vval.v_number = 1; /* FAIL */
1412 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1413 break;
1414
1415 /* When coming here from Insert mode, sync undo, so that this can be
1416 * undone separately from what was previously inserted. */
1417 if (u_sync_once == 2)
1418 {
1419 u_sync_once = 1; /* notify that u_sync() was called */
1420 u_sync(TRUE);
1421 }
1422
1423 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1424 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001425 // Existing line, replace it.
1426 // Removes any existing text properties.
1427 if (u_savesub(lnum) == OK && ml_replace_len(
1428 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001429 {
1430 changed_bytes(lnum, 0);
1431 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1432 check_cursor_col();
1433 rettv->vval.v_number = 0; /* OK */
1434 }
1435 }
1436 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1437 {
1438 /* append the line */
1439 ++added;
1440 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1441 rettv->vval.v_number = 0; /* OK */
1442 }
1443
1444 if (l == NULL) /* only one string argument */
1445 break;
1446 ++lnum;
1447 }
1448
1449 if (added > 0)
1450 {
1451 win_T *wp;
1452 tabpage_T *tp;
1453
1454 appended_lines_mark(append_lnum, added);
1455 FOR_ALL_TAB_WINDOWS(tp, wp)
1456 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1457 wp->w_cursor.lnum += added;
1458 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001459 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001460 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001461
1462 if (!is_curbuf)
1463 {
1464 curbuf = curbuf_save;
1465 curwin = curwin_save;
1466 }
1467}
1468
1469/*
1470 * "append(lnum, string/list)" function
1471 */
1472 static void
1473f_append(typval_T *argvars, typval_T *rettv)
1474{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001475 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001476
1477 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1478}
1479
1480/*
1481 * "appendbufline(buf, lnum, string/list)" function
1482 */
1483 static void
1484f_appendbufline(typval_T *argvars, typval_T *rettv)
1485{
1486 linenr_T lnum;
1487 buf_T *buf;
1488
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001489 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001490 if (buf == NULL)
1491 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001492 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001493 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001494 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001495 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1496 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497}
1498
1499/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001500 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 */
1502 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001503f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001504{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001505 win_T *wp;
1506
1507 if (argvars[0].v_type == VAR_UNKNOWN)
1508 // use the current window
1509 rettv->vval.v_number = ARGCOUNT;
1510 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001511 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001512 // use the global argument list
1513 rettv->vval.v_number = GARGCOUNT;
1514 else
1515 {
1516 // use the argument list of the specified window
1517 wp = find_win_by_nr_or_id(&argvars[0]);
1518 if (wp != NULL)
1519 rettv->vval.v_number = WARGCOUNT(wp);
1520 else
1521 rettv->vval.v_number = -1;
1522 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001523}
1524
1525/*
1526 * "argidx()" function
1527 */
1528 static void
1529f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1530{
1531 rettv->vval.v_number = curwin->w_arg_idx;
1532}
1533
1534/*
1535 * "arglistid()" function
1536 */
1537 static void
1538f_arglistid(typval_T *argvars, typval_T *rettv)
1539{
1540 win_T *wp;
1541
1542 rettv->vval.v_number = -1;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02001543 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001544 if (wp != NULL)
1545 rettv->vval.v_number = wp->w_alist->id;
1546}
1547
1548/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001549 * Get the argument list for a given window
1550 */
1551 static void
1552get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1553{
1554 int idx;
1555
1556 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1557 for (idx = 0; idx < argcount; ++idx)
1558 list_append_string(rettv->vval.v_list,
1559 alist_name(&arglist[idx]), -1);
1560}
1561
1562/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001563 * "argv(nr)" function
1564 */
1565 static void
1566f_argv(typval_T *argvars, typval_T *rettv)
1567{
1568 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001569 aentry_T *arglist = NULL;
1570 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001571
1572 if (argvars[0].v_type != VAR_UNKNOWN)
1573 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001574 if (argvars[1].v_type == VAR_UNKNOWN)
1575 {
1576 arglist = ARGLIST;
1577 argcount = ARGCOUNT;
1578 }
1579 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001580 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001581 {
1582 arglist = GARGLIST;
1583 argcount = GARGCOUNT;
1584 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001585 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001586 {
1587 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1588
1589 if (wp != NULL)
1590 {
1591 /* Use the argument list of the specified window */
1592 arglist = WARGLIST(wp);
1593 argcount = WARGCOUNT(wp);
1594 }
1595 }
1596
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001598 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001599 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001600 if (arglist != NULL && idx >= 0 && idx < argcount)
1601 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1602 else if (idx == -1)
1603 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001604 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001605 else
1606 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607}
1608
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609#ifdef FEAT_FLOAT
1610/*
1611 * "asin()" function
1612 */
1613 static void
1614f_asin(typval_T *argvars, typval_T *rettv)
1615{
1616 float_T f = 0.0;
1617
1618 rettv->v_type = VAR_FLOAT;
1619 if (get_float_arg(argvars, &f) == OK)
1620 rettv->vval.v_float = asin(f);
1621 else
1622 rettv->vval.v_float = 0.0;
1623}
1624
1625/*
1626 * "atan()" function
1627 */
1628 static void
1629f_atan(typval_T *argvars, typval_T *rettv)
1630{
1631 float_T f = 0.0;
1632
1633 rettv->v_type = VAR_FLOAT;
1634 if (get_float_arg(argvars, &f) == OK)
1635 rettv->vval.v_float = atan(f);
1636 else
1637 rettv->vval.v_float = 0.0;
1638}
1639
1640/*
1641 * "atan2()" function
1642 */
1643 static void
1644f_atan2(typval_T *argvars, typval_T *rettv)
1645{
1646 float_T fx = 0.0, fy = 0.0;
1647
1648 rettv->v_type = VAR_FLOAT;
1649 if (get_float_arg(argvars, &fx) == OK
1650 && get_float_arg(&argvars[1], &fy) == OK)
1651 rettv->vval.v_float = atan2(fx, fy);
1652 else
1653 rettv->vval.v_float = 0.0;
1654}
1655#endif
1656
1657/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001658 * "balloon_show()" function
1659 */
1660#ifdef FEAT_BEVAL
1661 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001662f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1663{
1664 rettv->v_type = VAR_STRING;
1665 if (balloonEval != NULL)
1666 {
1667 if (balloonEval->msg == NULL)
1668 rettv->vval.v_string = NULL;
1669 else
1670 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1671 }
1672}
1673
1674 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001675f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1676{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001677 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001678 {
1679 if (argvars[0].v_type == VAR_LIST
1680# ifdef FEAT_GUI
1681 && !gui.in_use
1682# endif
1683 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001684 {
1685 list_T *l = argvars[0].vval.v_list;
1686
1687 // empty list removes the balloon
1688 post_balloon(balloonEval, NULL,
1689 l == NULL || l->lv_len == 0 ? NULL : l);
1690 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001691 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001692 {
1693 char_u *mesg = tv_get_string_chk(&argvars[0]);
1694
1695 if (mesg != NULL)
1696 // empty string removes the balloon
1697 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1698 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001699 }
1700}
1701
Bram Moolenaar669a8282017-11-19 20:13:05 +01001702# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001703 static void
1704f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1705{
1706 if (rettv_list_alloc(rettv) == OK)
1707 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001708 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001709
1710 if (msg != NULL)
1711 {
1712 pumitem_T *array;
1713 int size = split_message(msg, &array);
1714 int i;
1715
1716 /* Skip the first and last item, they are always empty. */
1717 for (i = 1; i < size - 1; ++i)
1718 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001719 while (size > 0)
1720 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001721 vim_free(array);
1722 }
1723 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001724}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001725# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001726#endif
1727
1728/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001729 * "browse(save, title, initdir, default)" function
1730 */
1731 static void
1732f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1733{
1734#ifdef FEAT_BROWSE
1735 int save;
1736 char_u *title;
1737 char_u *initdir;
1738 char_u *defname;
1739 char_u buf[NUMBUFLEN];
1740 char_u buf2[NUMBUFLEN];
1741 int error = FALSE;
1742
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001743 save = (int)tv_get_number_chk(&argvars[0], &error);
1744 title = tv_get_string_chk(&argvars[1]);
1745 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1746 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001747
1748 if (error || title == NULL || initdir == NULL || defname == NULL)
1749 rettv->vval.v_string = NULL;
1750 else
1751 rettv->vval.v_string =
1752 do_browse(save ? BROWSE_SAVE : 0,
1753 title, defname, NULL, initdir, NULL, curbuf);
1754#else
1755 rettv->vval.v_string = NULL;
1756#endif
1757 rettv->v_type = VAR_STRING;
1758}
1759
1760/*
1761 * "browsedir(title, initdir)" function
1762 */
1763 static void
1764f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1765{
1766#ifdef FEAT_BROWSE
1767 char_u *title;
1768 char_u *initdir;
1769 char_u buf[NUMBUFLEN];
1770
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001771 title = tv_get_string_chk(&argvars[0]);
1772 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773
1774 if (title == NULL || initdir == NULL)
1775 rettv->vval.v_string = NULL;
1776 else
1777 rettv->vval.v_string = do_browse(BROWSE_DIR,
1778 title, NULL, NULL, initdir, NULL, curbuf);
1779#else
1780 rettv->vval.v_string = NULL;
1781#endif
1782 rettv->v_type = VAR_STRING;
1783}
1784
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001785/*
1786 * Find a buffer by number or exact name.
1787 */
1788 static buf_T *
1789find_buffer(typval_T *avar)
1790{
1791 buf_T *buf = NULL;
1792
1793 if (avar->v_type == VAR_NUMBER)
1794 buf = buflist_findnr((int)avar->vval.v_number);
1795 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1796 {
1797 buf = buflist_findname_exp(avar->vval.v_string);
1798 if (buf == NULL)
1799 {
1800 /* No full path name match, try a match with a URL or a "nofile"
1801 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001802 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001803 if (buf->b_fname != NULL
1804 && (path_with_url(buf->b_fname)
1805#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001806 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001807#endif
1808 )
1809 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1810 break;
1811 }
1812 }
1813 return buf;
1814}
1815
1816/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001817 * "bufadd(expr)" function
1818 */
1819 static void
1820f_bufadd(typval_T *argvars, typval_T *rettv)
1821{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001822 char_u *name = tv_get_string(&argvars[0]);
1823
1824 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001825}
1826
1827/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828 * "bufexists(expr)" function
1829 */
1830 static void
1831f_bufexists(typval_T *argvars, typval_T *rettv)
1832{
1833 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1834}
1835
1836/*
1837 * "buflisted(expr)" function
1838 */
1839 static void
1840f_buflisted(typval_T *argvars, typval_T *rettv)
1841{
1842 buf_T *buf;
1843
1844 buf = find_buffer(&argvars[0]);
1845 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1846}
1847
1848/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001849 * "bufload(expr)" function
1850 */
1851 static void
1852f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1853{
1854 buf_T *buf = get_buf_arg(&argvars[0]);
1855
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001856 if (buf != NULL)
1857 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001858}
1859
1860/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001861 * "bufloaded(expr)" function
1862 */
1863 static void
1864f_bufloaded(typval_T *argvars, typval_T *rettv)
1865{
1866 buf_T *buf;
1867
1868 buf = find_buffer(&argvars[0]);
1869 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1870}
1871
1872 buf_T *
1873buflist_find_by_name(char_u *name, int curtab_only)
1874{
1875 int save_magic;
1876 char_u *save_cpo;
1877 buf_T *buf;
1878
1879 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1880 save_magic = p_magic;
1881 p_magic = TRUE;
1882 save_cpo = p_cpo;
1883 p_cpo = (char_u *)"";
1884
1885 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1886 TRUE, FALSE, curtab_only));
1887
1888 p_magic = save_magic;
1889 p_cpo = save_cpo;
1890 return buf;
1891}
1892
1893/*
1894 * Get buffer by number or pattern.
1895 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001896 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001897tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001898{
1899 char_u *name = tv->vval.v_string;
1900 buf_T *buf;
1901
1902 if (tv->v_type == VAR_NUMBER)
1903 return buflist_findnr((int)tv->vval.v_number);
1904 if (tv->v_type != VAR_STRING)
1905 return NULL;
1906 if (name == NULL || *name == NUL)
1907 return curbuf;
1908 if (name[0] == '$' && name[1] == NUL)
1909 return lastbuf;
1910
1911 buf = buflist_find_by_name(name, curtab_only);
1912
1913 /* If not found, try expanding the name, like done for bufexists(). */
1914 if (buf == NULL)
1915 buf = find_buffer(tv);
1916
1917 return buf;
1918}
1919
1920/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001921 * Get the buffer from "arg" and give an error and return NULL if it is not
1922 * valid.
1923 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001924 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001925get_buf_arg(typval_T *arg)
1926{
1927 buf_T *buf;
1928
1929 ++emsg_off;
1930 buf = tv_get_buf(arg, FALSE);
1931 --emsg_off;
1932 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001933 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001934 return buf;
1935}
1936
1937/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001938 * "bufname(expr)" function
1939 */
1940 static void
1941f_bufname(typval_T *argvars, typval_T *rettv)
1942{
1943 buf_T *buf;
1944
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001945 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001946 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001947 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001948 rettv->v_type = VAR_STRING;
1949 if (buf != NULL && buf->b_fname != NULL)
1950 rettv->vval.v_string = vim_strsave(buf->b_fname);
1951 else
1952 rettv->vval.v_string = NULL;
1953 --emsg_off;
1954}
1955
1956/*
1957 * "bufnr(expr)" function
1958 */
1959 static void
1960f_bufnr(typval_T *argvars, typval_T *rettv)
1961{
1962 buf_T *buf;
1963 int error = FALSE;
1964 char_u *name;
1965
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001966 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001967 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001968 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001969 --emsg_off;
1970
1971 /* If the buffer isn't found and the second argument is not zero create a
1972 * new buffer. */
1973 if (buf == NULL
1974 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001975 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001977 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 && !error)
1979 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1980
1981 if (buf != NULL)
1982 rettv->vval.v_number = buf->b_fnum;
1983 else
1984 rettv->vval.v_number = -1;
1985}
1986
1987 static void
1988buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1989{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001990 win_T *wp;
1991 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001992 buf_T *buf;
1993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001994 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001996 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001997 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001998 {
1999 ++winnr;
2000 if (wp->w_buffer == buf)
2001 break;
2002 }
2003 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004 --emsg_off;
2005}
2006
2007/*
2008 * "bufwinid(nr)" function
2009 */
2010 static void
2011f_bufwinid(typval_T *argvars, typval_T *rettv)
2012{
2013 buf_win_common(argvars, rettv, FALSE);
2014}
2015
2016/*
2017 * "bufwinnr(nr)" function
2018 */
2019 static void
2020f_bufwinnr(typval_T *argvars, typval_T *rettv)
2021{
2022 buf_win_common(argvars, rettv, TRUE);
2023}
2024
2025/*
2026 * "byte2line(byte)" function
2027 */
2028 static void
2029f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2030{
2031#ifndef FEAT_BYTEOFF
2032 rettv->vval.v_number = -1;
2033#else
2034 long boff = 0;
2035
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002036 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002037 if (boff < 0)
2038 rettv->vval.v_number = -1;
2039 else
2040 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2041 (linenr_T)0, &boff);
2042#endif
2043}
2044
2045 static void
2046byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2047{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002048 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049 char_u *str;
2050 varnumber_T idx;
2051
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002052 str = tv_get_string_chk(&argvars[0]);
2053 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002054 rettv->vval.v_number = -1;
2055 if (str == NULL || idx < 0)
2056 return;
2057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058 t = str;
2059 for ( ; idx > 0; idx--)
2060 {
2061 if (*t == NUL) /* EOL reached */
2062 return;
2063 if (enc_utf8 && comp)
2064 t += utf_ptr2len(t);
2065 else
2066 t += (*mb_ptr2len)(t);
2067 }
2068 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002069}
2070
2071/*
2072 * "byteidx()" function
2073 */
2074 static void
2075f_byteidx(typval_T *argvars, typval_T *rettv)
2076{
2077 byteidx(argvars, rettv, FALSE);
2078}
2079
2080/*
2081 * "byteidxcomp()" function
2082 */
2083 static void
2084f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2085{
2086 byteidx(argvars, rettv, TRUE);
2087}
2088
2089/*
2090 * "call(func, arglist [, dict])" function
2091 */
2092 static void
2093f_call(typval_T *argvars, typval_T *rettv)
2094{
2095 char_u *func;
2096 partial_T *partial = NULL;
2097 dict_T *selfdict = NULL;
2098
2099 if (argvars[1].v_type != VAR_LIST)
2100 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002101 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002102 return;
2103 }
2104 if (argvars[1].vval.v_list == NULL)
2105 return;
2106
2107 if (argvars[0].v_type == VAR_FUNC)
2108 func = argvars[0].vval.v_string;
2109 else if (argvars[0].v_type == VAR_PARTIAL)
2110 {
2111 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002112 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002113 }
2114 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002115 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002116 if (*func == NUL)
2117 return; /* type error or empty name */
2118
2119 if (argvars[2].v_type != VAR_UNKNOWN)
2120 {
2121 if (argvars[2].v_type != VAR_DICT)
2122 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002123 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002124 return;
2125 }
2126 selfdict = argvars[2].vval.v_dict;
2127 }
2128
2129 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2130}
2131
2132#ifdef FEAT_FLOAT
2133/*
2134 * "ceil({float})" function
2135 */
2136 static void
2137f_ceil(typval_T *argvars, typval_T *rettv)
2138{
2139 float_T f = 0.0;
2140
2141 rettv->v_type = VAR_FLOAT;
2142 if (get_float_arg(argvars, &f) == OK)
2143 rettv->vval.v_float = ceil(f);
2144 else
2145 rettv->vval.v_float = 0.0;
2146}
2147#endif
2148
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002149/*
2150 * "changenr()" function
2151 */
2152 static void
2153f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2154{
2155 rettv->vval.v_number = curbuf->b_u_seq_cur;
2156}
2157
2158/*
2159 * "char2nr(string)" function
2160 */
2161 static void
2162f_char2nr(typval_T *argvars, typval_T *rettv)
2163{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 if (has_mbyte)
2165 {
2166 int utf8 = 0;
2167
2168 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002169 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002170
2171 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002172 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002174 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 }
2176 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002177 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178}
2179
2180/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002181 * "chdir(dir)" function
2182 */
2183 static void
2184f_chdir(typval_T *argvars, typval_T *rettv)
2185{
2186 char_u *cwd;
2187 cdscope_T scope = CDSCOPE_GLOBAL;
2188
2189 rettv->v_type = VAR_STRING;
2190 rettv->vval.v_string = NULL;
2191
2192 if (argvars[0].v_type != VAR_STRING)
2193 return;
2194
2195 // Return the current directory
2196 cwd = alloc(MAXPATHL);
2197 if (cwd != NULL)
2198 {
2199 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2200 {
2201#ifdef BACKSLASH_IN_FILENAME
2202 slash_adjust(cwd);
2203#endif
2204 rettv->vval.v_string = vim_strsave(cwd);
2205 }
2206 vim_free(cwd);
2207 }
2208
2209 if (curwin->w_localdir != NULL)
2210 scope = CDSCOPE_WINDOW;
2211 else if (curtab->tp_localdir != NULL)
2212 scope = CDSCOPE_TABPAGE;
2213
2214 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2215 // Directory change failed
2216 VIM_CLEAR(rettv->vval.v_string);
2217}
2218
2219/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002220 * "cindent(lnum)" function
2221 */
2222 static void
2223f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2224{
2225#ifdef FEAT_CINDENT
2226 pos_T pos;
2227 linenr_T lnum;
2228
2229 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002230 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002231 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2232 {
2233 curwin->w_cursor.lnum = lnum;
2234 rettv->vval.v_number = get_c_indent();
2235 curwin->w_cursor = pos;
2236 }
2237 else
2238#endif
2239 rettv->vval.v_number = -1;
2240}
2241
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002242 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002243get_optional_window(typval_T *argvars, int idx)
2244{
2245 win_T *win = curwin;
2246
2247 if (argvars[idx].v_type != VAR_UNKNOWN)
2248 {
2249 win = find_win_by_nr_or_id(&argvars[idx]);
2250 if (win == NULL)
2251 {
2252 emsg(_(e_invalwindow));
2253 return NULL;
2254 }
2255 }
2256 return win;
2257}
2258
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002260 * "col(string)" function
2261 */
2262 static void
2263f_col(typval_T *argvars, typval_T *rettv)
2264{
2265 colnr_T col = 0;
2266 pos_T *fp;
2267 int fnum = curbuf->b_fnum;
2268
2269 fp = var2fpos(&argvars[0], FALSE, &fnum);
2270 if (fp != NULL && fnum == curbuf->b_fnum)
2271 {
2272 if (fp->col == MAXCOL)
2273 {
2274 /* '> can be MAXCOL, get the length of the line then */
2275 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2276 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2277 else
2278 col = MAXCOL;
2279 }
2280 else
2281 {
2282 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002283 /* col(".") when the cursor is on the NUL at the end of the line
2284 * because of "coladd" can be seen as an extra column. */
2285 if (virtual_active() && fp == &curwin->w_cursor)
2286 {
2287 char_u *p = ml_get_cursor();
2288
2289 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2290 curwin->w_virtcol - curwin->w_cursor.coladd))
2291 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 int l;
2293
2294 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2295 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296 }
2297 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002298 }
2299 }
2300 rettv->vval.v_number = col;
2301}
2302
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303/*
2304 * "confirm(message, buttons[, default [, type]])" function
2305 */
2306 static void
2307f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2308{
2309#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2310 char_u *message;
2311 char_u *buttons = NULL;
2312 char_u buf[NUMBUFLEN];
2313 char_u buf2[NUMBUFLEN];
2314 int def = 1;
2315 int type = VIM_GENERIC;
2316 char_u *typestr;
2317 int error = FALSE;
2318
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002319 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002320 if (message == NULL)
2321 error = TRUE;
2322 if (argvars[1].v_type != VAR_UNKNOWN)
2323 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002324 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002325 if (buttons == NULL)
2326 error = TRUE;
2327 if (argvars[2].v_type != VAR_UNKNOWN)
2328 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002329 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002330 if (argvars[3].v_type != VAR_UNKNOWN)
2331 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002332 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002333 if (typestr == NULL)
2334 error = TRUE;
2335 else
2336 {
2337 switch (TOUPPER_ASC(*typestr))
2338 {
2339 case 'E': type = VIM_ERROR; break;
2340 case 'Q': type = VIM_QUESTION; break;
2341 case 'I': type = VIM_INFO; break;
2342 case 'W': type = VIM_WARNING; break;
2343 case 'G': type = VIM_GENERIC; break;
2344 }
2345 }
2346 }
2347 }
2348 }
2349
2350 if (buttons == NULL || *buttons == NUL)
2351 buttons = (char_u *)_("&Ok");
2352
2353 if (!error)
2354 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2355 def, NULL, FALSE);
2356#endif
2357}
2358
2359/*
2360 * "copy()" function
2361 */
2362 static void
2363f_copy(typval_T *argvars, typval_T *rettv)
2364{
2365 item_copy(&argvars[0], rettv, FALSE, 0);
2366}
2367
2368#ifdef FEAT_FLOAT
2369/*
2370 * "cos()" function
2371 */
2372 static void
2373f_cos(typval_T *argvars, typval_T *rettv)
2374{
2375 float_T f = 0.0;
2376
2377 rettv->v_type = VAR_FLOAT;
2378 if (get_float_arg(argvars, &f) == OK)
2379 rettv->vval.v_float = cos(f);
2380 else
2381 rettv->vval.v_float = 0.0;
2382}
2383
2384/*
2385 * "cosh()" function
2386 */
2387 static void
2388f_cosh(typval_T *argvars, typval_T *rettv)
2389{
2390 float_T f = 0.0;
2391
2392 rettv->v_type = VAR_FLOAT;
2393 if (get_float_arg(argvars, &f) == OK)
2394 rettv->vval.v_float = cosh(f);
2395 else
2396 rettv->vval.v_float = 0.0;
2397}
2398#endif
2399
2400/*
2401 * "count()" function
2402 */
2403 static void
2404f_count(typval_T *argvars, typval_T *rettv)
2405{
2406 long n = 0;
2407 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002408 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002409
Bram Moolenaar9966b212017-07-28 16:46:57 +02002410 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002411 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002412
2413 if (argvars[0].v_type == VAR_STRING)
2414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002415 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002416 char_u *p = argvars[0].vval.v_string;
2417 char_u *next;
2418
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002419 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002420 {
2421 if (ic)
2422 {
2423 size_t len = STRLEN(expr);
2424
2425 while (*p != NUL)
2426 {
2427 if (MB_STRNICMP(p, expr, len) == 0)
2428 {
2429 ++n;
2430 p += len;
2431 }
2432 else
2433 MB_PTR_ADV(p);
2434 }
2435 }
2436 else
2437 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2438 != NULL)
2439 {
2440 ++n;
2441 p = next + STRLEN(expr);
2442 }
2443 }
2444
2445 }
2446 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447 {
2448 listitem_T *li;
2449 list_T *l;
2450 long idx;
2451
2452 if ((l = argvars[0].vval.v_list) != NULL)
2453 {
2454 li = l->lv_first;
2455 if (argvars[2].v_type != VAR_UNKNOWN)
2456 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457 if (argvars[3].v_type != VAR_UNKNOWN)
2458 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002459 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 if (!error)
2461 {
2462 li = list_find(l, idx);
2463 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002464 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 }
2466 }
2467 if (error)
2468 li = NULL;
2469 }
2470
2471 for ( ; li != NULL; li = li->li_next)
2472 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2473 ++n;
2474 }
2475 }
2476 else if (argvars[0].v_type == VAR_DICT)
2477 {
2478 int todo;
2479 dict_T *d;
2480 hashitem_T *hi;
2481
2482 if ((d = argvars[0].vval.v_dict) != NULL)
2483 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002484 if (argvars[2].v_type != VAR_UNKNOWN)
2485 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002486 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002487 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002488 }
2489
2490 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2491 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2492 {
2493 if (!HASHITEM_EMPTY(hi))
2494 {
2495 --todo;
2496 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2497 ++n;
2498 }
2499 }
2500 }
2501 }
2502 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002503 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002504 rettv->vval.v_number = n;
2505}
2506
2507/*
2508 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2509 *
2510 * Checks the existence of a cscope connection.
2511 */
2512 static void
2513f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2514{
2515#ifdef FEAT_CSCOPE
2516 int num = 0;
2517 char_u *dbpath = NULL;
2518 char_u *prepend = NULL;
2519 char_u buf[NUMBUFLEN];
2520
2521 if (argvars[0].v_type != VAR_UNKNOWN
2522 && argvars[1].v_type != VAR_UNKNOWN)
2523 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002524 num = (int)tv_get_number(&argvars[0]);
2525 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002527 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528 }
2529
2530 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2531#endif
2532}
2533
2534/*
2535 * "cursor(lnum, col)" function, or
2536 * "cursor(list)"
2537 *
2538 * Moves the cursor to the specified line and column.
2539 * Returns 0 when the position could be set, -1 otherwise.
2540 */
2541 static void
2542f_cursor(typval_T *argvars, typval_T *rettv)
2543{
2544 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002545 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002546 int set_curswant = TRUE;
2547
2548 rettv->vval.v_number = -1;
2549 if (argvars[1].v_type == VAR_UNKNOWN)
2550 {
2551 pos_T pos;
2552 colnr_T curswant = -1;
2553
2554 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2555 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002556 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002557 return;
2558 }
2559 line = pos.lnum;
2560 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002562 if (curswant >= 0)
2563 {
2564 curwin->w_curswant = curswant - 1;
2565 set_curswant = FALSE;
2566 }
2567 }
2568 else
2569 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002570 line = tv_get_lnum(argvars);
2571 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002572 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002573 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002575 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002576 return; /* type error; errmsg already given */
2577 if (line > 0)
2578 curwin->w_cursor.lnum = line;
2579 if (col > 0)
2580 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002581 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582
2583 /* Make sure the cursor is in a valid position. */
2584 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002585 /* Correct cursor for multi-byte character. */
2586 if (has_mbyte)
2587 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002588
2589 curwin->w_set_curswant = set_curswant;
2590 rettv->vval.v_number = 0;
2591}
2592
Bram Moolenaar4f974752019-02-17 17:44:42 +01002593#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002594/*
2595 * "debugbreak()" function
2596 */
2597 static void
2598f_debugbreak(typval_T *argvars, typval_T *rettv)
2599{
2600 int pid;
2601
2602 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002603 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002604 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002605 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002606 else
2607 {
2608 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2609
2610 if (hProcess != NULL)
2611 {
2612 DebugBreakProcess(hProcess);
2613 CloseHandle(hProcess);
2614 rettv->vval.v_number = OK;
2615 }
2616 }
2617}
2618#endif
2619
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620/*
2621 * "deepcopy()" function
2622 */
2623 static void
2624f_deepcopy(typval_T *argvars, typval_T *rettv)
2625{
2626 int noref = 0;
2627 int copyID;
2628
2629 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002630 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002631 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002632 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002633 else
2634 {
2635 copyID = get_copyID();
2636 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2637 }
2638}
2639
2640/*
2641 * "delete()" function
2642 */
2643 static void
2644f_delete(typval_T *argvars, typval_T *rettv)
2645{
2646 char_u nbuf[NUMBUFLEN];
2647 char_u *name;
2648 char_u *flags;
2649
2650 rettv->vval.v_number = -1;
2651 if (check_restricted() || check_secure())
2652 return;
2653
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002654 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655 if (name == NULL || *name == NUL)
2656 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002657 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002658 return;
2659 }
2660
2661 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002662 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663 else
2664 flags = (char_u *)"";
2665
2666 if (*flags == NUL)
2667 /* delete a file */
2668 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2669 else if (STRCMP(flags, "d") == 0)
2670 /* delete an empty directory */
2671 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2672 else if (STRCMP(flags, "rf") == 0)
2673 /* delete a directory recursively */
2674 rettv->vval.v_number = delete_recursive(name);
2675 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002676 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677}
2678
2679/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002680 * "deletebufline()" function
2681 */
2682 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002683f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002684{
2685 buf_T *buf;
2686 linenr_T first, last;
2687 linenr_T lnum;
2688 long count;
2689 int is_curbuf;
2690 buf_T *curbuf_save = NULL;
2691 win_T *curwin_save = NULL;
2692 tabpage_T *tp;
2693 win_T *wp;
2694
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002695 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002696 if (buf == NULL)
2697 {
2698 rettv->vval.v_number = 1; /* FAIL */
2699 return;
2700 }
2701 is_curbuf = buf == curbuf;
2702
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002703 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002704 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002705 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002706 else
2707 last = first;
2708
2709 if (buf->b_ml.ml_mfp == NULL || first < 1
2710 || first > buf->b_ml.ml_line_count || last < first)
2711 {
2712 rettv->vval.v_number = 1; /* FAIL */
2713 return;
2714 }
2715
2716 if (!is_curbuf)
2717 {
2718 curbuf_save = curbuf;
2719 curwin_save = curwin;
2720 curbuf = buf;
2721 find_win_for_curbuf();
2722 }
2723 if (last > curbuf->b_ml.ml_line_count)
2724 last = curbuf->b_ml.ml_line_count;
2725 count = last - first + 1;
2726
2727 // When coming here from Insert mode, sync undo, so that this can be
2728 // undone separately from what was previously inserted.
2729 if (u_sync_once == 2)
2730 {
2731 u_sync_once = 1; // notify that u_sync() was called
2732 u_sync(TRUE);
2733 }
2734
2735 if (u_save(first - 1, last + 1) == FAIL)
2736 {
2737 rettv->vval.v_number = 1; /* FAIL */
2738 return;
2739 }
2740
2741 for (lnum = first; lnum <= last; ++lnum)
2742 ml_delete(first, TRUE);
2743
2744 FOR_ALL_TAB_WINDOWS(tp, wp)
2745 if (wp->w_buffer == buf)
2746 {
2747 if (wp->w_cursor.lnum > last)
2748 wp->w_cursor.lnum -= count;
2749 else if (wp->w_cursor.lnum> first)
2750 wp->w_cursor.lnum = first;
2751 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2752 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2753 }
2754 check_cursor_col();
2755 deleted_lines_mark(first, count);
2756
2757 if (!is_curbuf)
2758 {
2759 curbuf = curbuf_save;
2760 curwin = curwin_save;
2761 }
2762}
2763
2764/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002765 * "did_filetype()" function
2766 */
2767 static void
2768f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2769{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002771}
2772
2773/*
2774 * "diff_filler()" function
2775 */
2776 static void
2777f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2778{
2779#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002780 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002781#endif
2782}
2783
2784/*
2785 * "diff_hlID()" function
2786 */
2787 static void
2788f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2789{
2790#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002791 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002793 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002794 static int fnum = 0;
2795 static int change_start = 0;
2796 static int change_end = 0;
2797 static hlf_T hlID = (hlf_T)0;
2798 int filler_lines;
2799 int col;
2800
2801 if (lnum < 0) /* ignore type error in {lnum} arg */
2802 lnum = 0;
2803 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002804 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002805 || fnum != curbuf->b_fnum)
2806 {
2807 /* New line, buffer, change: need to get the values. */
2808 filler_lines = diff_check(curwin, lnum);
2809 if (filler_lines < 0)
2810 {
2811 if (filler_lines == -1)
2812 {
2813 change_start = MAXCOL;
2814 change_end = -1;
2815 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2816 hlID = HLF_ADD; /* added line */
2817 else
2818 hlID = HLF_CHD; /* changed line */
2819 }
2820 else
2821 hlID = HLF_ADD; /* added line */
2822 }
2823 else
2824 hlID = (hlf_T)0;
2825 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002826 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002827 fnum = curbuf->b_fnum;
2828 }
2829
2830 if (hlID == HLF_CHD || hlID == HLF_TXD)
2831 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002832 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002833 if (col >= change_start && col <= change_end)
2834 hlID = HLF_TXD; /* changed text */
2835 else
2836 hlID = HLF_CHD; /* changed line */
2837 }
2838 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2839#endif
2840}
2841
2842/*
2843 * "empty({expr})" function
2844 */
2845 static void
2846f_empty(typval_T *argvars, typval_T *rettv)
2847{
2848 int n = FALSE;
2849
2850 switch (argvars[0].v_type)
2851 {
2852 case VAR_STRING:
2853 case VAR_FUNC:
2854 n = argvars[0].vval.v_string == NULL
2855 || *argvars[0].vval.v_string == NUL;
2856 break;
2857 case VAR_PARTIAL:
2858 n = FALSE;
2859 break;
2860 case VAR_NUMBER:
2861 n = argvars[0].vval.v_number == 0;
2862 break;
2863 case VAR_FLOAT:
2864#ifdef FEAT_FLOAT
2865 n = argvars[0].vval.v_float == 0.0;
2866 break;
2867#endif
2868 case VAR_LIST:
2869 n = argvars[0].vval.v_list == NULL
2870 || argvars[0].vval.v_list->lv_first == NULL;
2871 break;
2872 case VAR_DICT:
2873 n = argvars[0].vval.v_dict == NULL
2874 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2875 break;
2876 case VAR_SPECIAL:
2877 n = argvars[0].vval.v_number != VVAL_TRUE;
2878 break;
2879
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002880 case VAR_BLOB:
2881 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002882 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2883 break;
2884
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002885 case VAR_JOB:
2886#ifdef FEAT_JOB_CHANNEL
2887 n = argvars[0].vval.v_job == NULL
2888 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2889 break;
2890#endif
2891 case VAR_CHANNEL:
2892#ifdef FEAT_JOB_CHANNEL
2893 n = argvars[0].vval.v_channel == NULL
2894 || !channel_is_open(argvars[0].vval.v_channel);
2895 break;
2896#endif
2897 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002898 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002899 n = TRUE;
2900 break;
2901 }
2902
2903 rettv->vval.v_number = n;
2904}
2905
2906/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002907 * "environ()" function
2908 */
2909 static void
2910f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2911{
2912#if !defined(AMIGA)
2913 int i = 0;
2914 char_u *entry, *value;
2915# ifdef MSWIN
2916 extern wchar_t **_wenviron;
2917# else
2918 extern char **environ;
2919# endif
2920
2921 if (rettv_dict_alloc(rettv) != OK)
2922 return;
2923
2924# ifdef MSWIN
2925 if (*_wenviron == NULL)
2926 return;
2927# else
2928 if (*environ == NULL)
2929 return;
2930# endif
2931
2932 for (i = 0; ; ++i)
2933 {
2934# ifdef MSWIN
2935 short_u *p;
2936
2937 if ((p = (short_u *)_wenviron[i]) == NULL)
2938 return;
2939 entry = utf16_to_enc(p, NULL);
2940# else
2941 if ((entry = (char_u *)environ[i]) == NULL)
2942 return;
2943 entry = vim_strsave(entry);
2944# endif
2945 if (entry == NULL) // out of memory
2946 return;
2947 if ((value = vim_strchr(entry, '=')) == NULL)
2948 {
2949 vim_free(entry);
2950 continue;
2951 }
2952 *value++ = NUL;
2953 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2954 vim_free(entry);
2955 }
2956#endif
2957}
2958
2959/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002960 * "escape({string}, {chars})" function
2961 */
2962 static void
2963f_escape(typval_T *argvars, typval_T *rettv)
2964{
2965 char_u buf[NUMBUFLEN];
2966
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002967 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2968 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002969 rettv->v_type = VAR_STRING;
2970}
2971
2972/*
2973 * "eval()" function
2974 */
2975 static void
2976f_eval(typval_T *argvars, typval_T *rettv)
2977{
2978 char_u *s, *p;
2979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002980 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002981 if (s != NULL)
2982 s = skipwhite(s);
2983
2984 p = s;
2985 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2986 {
2987 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002988 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 need_clr_eos = FALSE;
2990 rettv->v_type = VAR_NUMBER;
2991 rettv->vval.v_number = 0;
2992 }
2993 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002994 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002995}
2996
2997/*
2998 * "eventhandler()" function
2999 */
3000 static void
3001f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3002{
3003 rettv->vval.v_number = vgetc_busy;
3004}
3005
3006/*
3007 * "executable()" function
3008 */
3009 static void
3010f_executable(typval_T *argvars, typval_T *rettv)
3011{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003012 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003013
3014 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003015 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016}
3017
3018static garray_T redir_execute_ga;
3019
3020/*
3021 * Append "value[value_len]" to the execute() output.
3022 */
3023 void
3024execute_redir_str(char_u *value, int value_len)
3025{
3026 int len;
3027
3028 if (value_len == -1)
3029 len = (int)STRLEN(value); /* Append the entire string */
3030 else
3031 len = value_len; /* Append only "value_len" characters */
3032 if (ga_grow(&redir_execute_ga, len) == OK)
3033 {
3034 mch_memmove((char *)redir_execute_ga.ga_data
3035 + redir_execute_ga.ga_len, value, len);
3036 redir_execute_ga.ga_len += len;
3037 }
3038}
3039
3040/*
3041 * Get next line from a list.
3042 * Called by do_cmdline() to get the next line.
3043 * Returns allocated string, or NULL for end of function.
3044 */
3045
3046 static char_u *
3047get_list_line(
3048 int c UNUSED,
3049 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003050 int indent UNUSED,
3051 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003052{
3053 listitem_T **p = (listitem_T **)cookie;
3054 listitem_T *item = *p;
3055 char_u buf[NUMBUFLEN];
3056 char_u *s;
3057
3058 if (item == NULL)
3059 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003060 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003061 *p = item->li_next;
3062 return s == NULL ? NULL : vim_strsave(s);
3063}
3064
3065/*
3066 * "execute()" function
3067 */
3068 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003069execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003070{
3071 char_u *cmd = NULL;
3072 list_T *list = NULL;
3073 int save_msg_silent = msg_silent;
3074 int save_emsg_silent = emsg_silent;
3075 int save_emsg_noredir = emsg_noredir;
3076 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003077 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003078 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003079 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003080 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003081
3082 rettv->vval.v_string = NULL;
3083 rettv->v_type = VAR_STRING;
3084
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003085 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003086 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003087 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003088 if (list == NULL || list->lv_first == NULL)
3089 /* empty list, no commands, empty output */
3090 return;
3091 ++list->lv_refcount;
3092 }
3093 else
3094 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003095 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 if (cmd == NULL)
3097 return;
3098 }
3099
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003100 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003101 {
3102 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003103 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003104
3105 if (s == NULL)
3106 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003107 if (*s == NUL)
3108 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003109 if (STRNCMP(s, "silent", 6) == 0)
3110 ++msg_silent;
3111 if (STRCMP(s, "silent!") == 0)
3112 {
3113 emsg_silent = TRUE;
3114 emsg_noredir = TRUE;
3115 }
3116 }
3117 else
3118 ++msg_silent;
3119
3120 if (redir_execute)
3121 save_ga = redir_execute_ga;
3122 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3123 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003124 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003125 if (!echo_output)
3126 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003127
3128 if (cmd != NULL)
3129 do_cmdline_cmd(cmd);
3130 else
3131 {
3132 listitem_T *item = list->lv_first;
3133
3134 do_cmdline(NULL, get_list_line, (void *)&item,
3135 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3136 --list->lv_refcount;
3137 }
3138
Bram Moolenaard297f352017-01-29 20:31:21 +01003139 /* Need to append a NUL to the result. */
3140 if (ga_grow(&redir_execute_ga, 1) == OK)
3141 {
3142 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3143 rettv->vval.v_string = redir_execute_ga.ga_data;
3144 }
3145 else
3146 {
3147 ga_clear(&redir_execute_ga);
3148 rettv->vval.v_string = NULL;
3149 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003150 msg_silent = save_msg_silent;
3151 emsg_silent = save_emsg_silent;
3152 emsg_noredir = save_emsg_noredir;
3153
3154 redir_execute = save_redir_execute;
3155 if (redir_execute)
3156 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003157 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003159 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003160 if (echo_output)
3161 // When not working silently: put it in column zero. A following
3162 // "echon" will overwrite the message, unavoidably.
3163 msg_col = 0;
3164 else
3165 // When working silently: Put it back where it was, since nothing
3166 // should have been written.
3167 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003168}
3169
3170/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003171 * "execute()" function
3172 */
3173 static void
3174f_execute(typval_T *argvars, typval_T *rettv)
3175{
3176 execute_common(argvars, rettv, 0);
3177}
3178
3179/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003180 * "exepath()" function
3181 */
3182 static void
3183f_exepath(typval_T *argvars, typval_T *rettv)
3184{
3185 char_u *p = NULL;
3186
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003187 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003188 rettv->v_type = VAR_STRING;
3189 rettv->vval.v_string = p;
3190}
3191
3192/*
3193 * "exists()" function
3194 */
3195 static void
3196f_exists(typval_T *argvars, typval_T *rettv)
3197{
3198 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003199 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003200
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003201 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003202 if (*p == '$') /* environment variable */
3203 {
3204 /* first try "normal" environment variables (fast) */
3205 if (mch_getenv(p + 1) != NULL)
3206 n = TRUE;
3207 else
3208 {
3209 /* try expanding things like $VIM and ${HOME} */
3210 p = expand_env_save(p);
3211 if (p != NULL && *p != '$')
3212 n = TRUE;
3213 vim_free(p);
3214 }
3215 }
3216 else if (*p == '&' || *p == '+') /* option */
3217 {
3218 n = (get_option_tv(&p, NULL, TRUE) == OK);
3219 if (*skipwhite(p) != NUL)
3220 n = FALSE; /* trailing garbage */
3221 }
3222 else if (*p == '*') /* internal or user defined function */
3223 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003224 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003225 }
3226 else if (*p == ':')
3227 {
3228 n = cmd_exists(p + 1);
3229 }
3230 else if (*p == '#')
3231 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003232 if (p[1] == '#')
3233 n = autocmd_supported(p + 2);
3234 else
3235 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003236 }
3237 else /* internal variable */
3238 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003239 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003240 }
3241
3242 rettv->vval.v_number = n;
3243}
3244
3245#ifdef FEAT_FLOAT
3246/*
3247 * "exp()" function
3248 */
3249 static void
3250f_exp(typval_T *argvars, typval_T *rettv)
3251{
3252 float_T f = 0.0;
3253
3254 rettv->v_type = VAR_FLOAT;
3255 if (get_float_arg(argvars, &f) == OK)
3256 rettv->vval.v_float = exp(f);
3257 else
3258 rettv->vval.v_float = 0.0;
3259}
3260#endif
3261
3262/*
3263 * "expand()" function
3264 */
3265 static void
3266f_expand(typval_T *argvars, typval_T *rettv)
3267{
3268 char_u *s;
3269 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003270 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003271 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3272 expand_T xpc;
3273 int error = FALSE;
3274 char_u *result;
3275
3276 rettv->v_type = VAR_STRING;
3277 if (argvars[1].v_type != VAR_UNKNOWN
3278 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003279 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003280 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003281 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003283 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003284 if (*s == '%' || *s == '#' || *s == '<')
3285 {
3286 ++emsg_off;
3287 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3288 --emsg_off;
3289 if (rettv->v_type == VAR_LIST)
3290 {
3291 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3292 list_append_string(rettv->vval.v_list, result, -1);
3293 else
3294 vim_free(result);
3295 }
3296 else
3297 rettv->vval.v_string = result;
3298 }
3299 else
3300 {
3301 /* When the optional second argument is non-zero, don't remove matches
3302 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3303 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003304 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003305 options |= WILD_KEEP_ALL;
3306 if (!error)
3307 {
3308 ExpandInit(&xpc);
3309 xpc.xp_context = EXPAND_FILES;
3310 if (p_wic)
3311 options += WILD_ICASE;
3312 if (rettv->v_type == VAR_STRING)
3313 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3314 options, WILD_ALL);
3315 else if (rettv_list_alloc(rettv) != FAIL)
3316 {
3317 int i;
3318
3319 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3320 for (i = 0; i < xpc.xp_numfiles; i++)
3321 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3322 ExpandCleanup(&xpc);
3323 }
3324 }
3325 else
3326 rettv->vval.v_string = NULL;
3327 }
3328}
3329
3330/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003331 * "expandcmd()" function
3332 * Expand all the special characters in a command string.
3333 */
3334 static void
3335f_expandcmd(typval_T *argvars, typval_T *rettv)
3336{
3337 exarg_T eap;
3338 char_u *cmdstr;
3339 char *errormsg = NULL;
3340
3341 rettv->v_type = VAR_STRING;
3342 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3343
3344 memset(&eap, 0, sizeof(eap));
3345 eap.cmd = cmdstr;
3346 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003347 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003348 eap.usefilter = FALSE;
3349 eap.nextcmd = NULL;
3350 eap.cmdidx = CMD_USER;
3351
3352 expand_filename(&eap, &cmdstr, &errormsg);
3353 if (errormsg != NULL && *errormsg != NUL)
3354 emsg(errormsg);
3355
3356 rettv->vval.v_string = cmdstr;
3357}
3358
3359/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360 * "extend(list, list [, idx])" function
3361 * "extend(dict, dict [, action])" function
3362 */
3363 static void
3364f_extend(typval_T *argvars, typval_T *rettv)
3365{
3366 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3367
3368 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3369 {
3370 list_T *l1, *l2;
3371 listitem_T *item;
3372 long before;
3373 int error = FALSE;
3374
3375 l1 = argvars[0].vval.v_list;
3376 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003377 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378 && l2 != NULL)
3379 {
3380 if (argvars[2].v_type != VAR_UNKNOWN)
3381 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003382 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003383 if (error)
3384 return; /* type error; errmsg already given */
3385
3386 if (before == l1->lv_len)
3387 item = NULL;
3388 else
3389 {
3390 item = list_find(l1, before);
3391 if (item == NULL)
3392 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003393 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003394 return;
3395 }
3396 }
3397 }
3398 else
3399 item = NULL;
3400 list_extend(l1, l2, item);
3401
3402 copy_tv(&argvars[0], rettv);
3403 }
3404 }
3405 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3406 {
3407 dict_T *d1, *d2;
3408 char_u *action;
3409 int i;
3410
3411 d1 = argvars[0].vval.v_dict;
3412 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003413 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414 && d2 != NULL)
3415 {
3416 /* Check the third argument. */
3417 if (argvars[2].v_type != VAR_UNKNOWN)
3418 {
3419 static char *(av[]) = {"keep", "force", "error"};
3420
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003421 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422 if (action == NULL)
3423 return; /* type error; errmsg already given */
3424 for (i = 0; i < 3; ++i)
3425 if (STRCMP(action, av[i]) == 0)
3426 break;
3427 if (i == 3)
3428 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003429 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003430 return;
3431 }
3432 }
3433 else
3434 action = (char_u *)"force";
3435
3436 dict_extend(d1, d2, action);
3437
3438 copy_tv(&argvars[0], rettv);
3439 }
3440 }
3441 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003442 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003443}
3444
3445/*
3446 * "feedkeys()" function
3447 */
3448 static void
3449f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3450{
3451 int remap = TRUE;
3452 int insert = FALSE;
3453 char_u *keys, *flags;
3454 char_u nbuf[NUMBUFLEN];
3455 int typed = FALSE;
3456 int execute = FALSE;
3457 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003458 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003459 char_u *keys_esc;
3460
3461 /* This is not allowed in the sandbox. If the commands would still be
3462 * executed in the sandbox it would be OK, but it probably happens later,
3463 * when "sandbox" is no longer set. */
3464 if (check_secure())
3465 return;
3466
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003467 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468
3469 if (argvars[1].v_type != VAR_UNKNOWN)
3470 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003471 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472 for ( ; *flags != NUL; ++flags)
3473 {
3474 switch (*flags)
3475 {
3476 case 'n': remap = FALSE; break;
3477 case 'm': remap = TRUE; break;
3478 case 't': typed = TRUE; break;
3479 case 'i': insert = TRUE; break;
3480 case 'x': execute = TRUE; break;
3481 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003482 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 }
3484 }
3485 }
3486
3487 if (*keys != NUL || execute)
3488 {
3489 /* Need to escape K_SPECIAL and CSI before putting the string in the
3490 * typeahead buffer. */
3491 keys_esc = vim_strsave_escape_csi(keys);
3492 if (keys_esc != NULL)
3493 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003494 if (lowlevel)
3495 {
3496#ifdef USE_INPUT_BUF
3497 add_to_input_buf(keys, (int)STRLEN(keys));
3498#else
3499 emsg(_("E980: lowlevel input not supported"));
3500#endif
3501 }
3502 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003503 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003504 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003506 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003507#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003508 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003509#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003510 )
3511 typebuf_was_filled = TRUE;
3512 }
3513 vim_free(keys_esc);
3514
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003515 if (execute)
3516 {
3517 int save_msg_scroll = msg_scroll;
3518
3519 /* Avoid a 1 second delay when the keys start Insert mode. */
3520 msg_scroll = FALSE;
3521
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003522 if (!dangerous)
3523 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003524 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003525 if (!dangerous)
3526 --ex_normal_busy;
3527
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003528 msg_scroll |= save_msg_scroll;
3529 }
3530 }
3531 }
3532}
3533
3534/*
3535 * "filereadable()" function
3536 */
3537 static void
3538f_filereadable(typval_T *argvars, typval_T *rettv)
3539{
3540 int fd;
3541 char_u *p;
3542 int n;
3543
3544#ifndef O_NONBLOCK
3545# define O_NONBLOCK 0
3546#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003547 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003548 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3549 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3550 {
3551 n = TRUE;
3552 close(fd);
3553 }
3554 else
3555 n = FALSE;
3556
3557 rettv->vval.v_number = n;
3558}
3559
3560/*
3561 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3562 * rights to write into.
3563 */
3564 static void
3565f_filewritable(typval_T *argvars, typval_T *rettv)
3566{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003567 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568}
3569
3570 static void
3571findfilendir(
3572 typval_T *argvars UNUSED,
3573 typval_T *rettv,
3574 int find_what UNUSED)
3575{
3576#ifdef FEAT_SEARCHPATH
3577 char_u *fname;
3578 char_u *fresult = NULL;
3579 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3580 char_u *p;
3581 char_u pathbuf[NUMBUFLEN];
3582 int count = 1;
3583 int first = TRUE;
3584 int error = FALSE;
3585#endif
3586
3587 rettv->vval.v_string = NULL;
3588 rettv->v_type = VAR_STRING;
3589
3590#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003591 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003592
3593 if (argvars[1].v_type != VAR_UNKNOWN)
3594 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003595 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003596 if (p == NULL)
3597 error = TRUE;
3598 else
3599 {
3600 if (*p != NUL)
3601 path = p;
3602
3603 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003604 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605 }
3606 }
3607
3608 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3609 error = TRUE;
3610
3611 if (*fname != NUL && !error)
3612 {
3613 do
3614 {
3615 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3616 vim_free(fresult);
3617 fresult = find_file_in_path_option(first ? fname : NULL,
3618 first ? (int)STRLEN(fname) : 0,
3619 0, first, path,
3620 find_what,
3621 curbuf->b_ffname,
3622 find_what == FINDFILE_DIR
3623 ? (char_u *)"" : curbuf->b_p_sua);
3624 first = FALSE;
3625
3626 if (fresult != NULL && rettv->v_type == VAR_LIST)
3627 list_append_string(rettv->vval.v_list, fresult, -1);
3628
3629 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3630 }
3631
3632 if (rettv->v_type == VAR_STRING)
3633 rettv->vval.v_string = fresult;
3634#endif
3635}
3636
3637/*
3638 * "filter()" function
3639 */
3640 static void
3641f_filter(typval_T *argvars, typval_T *rettv)
3642{
3643 filter_map(argvars, rettv, FALSE);
3644}
3645
3646/*
3647 * "finddir({fname}[, {path}[, {count}]])" function
3648 */
3649 static void
3650f_finddir(typval_T *argvars, typval_T *rettv)
3651{
3652 findfilendir(argvars, rettv, FINDFILE_DIR);
3653}
3654
3655/*
3656 * "findfile({fname}[, {path}[, {count}]])" function
3657 */
3658 static void
3659f_findfile(typval_T *argvars, typval_T *rettv)
3660{
3661 findfilendir(argvars, rettv, FINDFILE_FILE);
3662}
3663
3664#ifdef FEAT_FLOAT
3665/*
3666 * "float2nr({float})" function
3667 */
3668 static void
3669f_float2nr(typval_T *argvars, typval_T *rettv)
3670{
3671 float_T f = 0.0;
3672
3673 if (get_float_arg(argvars, &f) == OK)
3674 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003675 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003676 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003677 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003678 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003679 else
3680 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681 }
3682}
3683
3684/*
3685 * "floor({float})" function
3686 */
3687 static void
3688f_floor(typval_T *argvars, typval_T *rettv)
3689{
3690 float_T f = 0.0;
3691
3692 rettv->v_type = VAR_FLOAT;
3693 if (get_float_arg(argvars, &f) == OK)
3694 rettv->vval.v_float = floor(f);
3695 else
3696 rettv->vval.v_float = 0.0;
3697}
3698
3699/*
3700 * "fmod()" function
3701 */
3702 static void
3703f_fmod(typval_T *argvars, typval_T *rettv)
3704{
3705 float_T fx = 0.0, fy = 0.0;
3706
3707 rettv->v_type = VAR_FLOAT;
3708 if (get_float_arg(argvars, &fx) == OK
3709 && get_float_arg(&argvars[1], &fy) == OK)
3710 rettv->vval.v_float = fmod(fx, fy);
3711 else
3712 rettv->vval.v_float = 0.0;
3713}
3714#endif
3715
3716/*
3717 * "fnameescape({string})" function
3718 */
3719 static void
3720f_fnameescape(typval_T *argvars, typval_T *rettv)
3721{
3722 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003723 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003724 rettv->v_type = VAR_STRING;
3725}
3726
3727/*
3728 * "fnamemodify({fname}, {mods})" function
3729 */
3730 static void
3731f_fnamemodify(typval_T *argvars, typval_T *rettv)
3732{
3733 char_u *fname;
3734 char_u *mods;
3735 int usedlen = 0;
3736 int len;
3737 char_u *fbuf = NULL;
3738 char_u buf[NUMBUFLEN];
3739
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003740 fname = tv_get_string_chk(&argvars[0]);
3741 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742 if (fname == NULL || mods == NULL)
3743 fname = NULL;
3744 else
3745 {
3746 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003747 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003748 }
3749
3750 rettv->v_type = VAR_STRING;
3751 if (fname == NULL)
3752 rettv->vval.v_string = NULL;
3753 else
3754 rettv->vval.v_string = vim_strnsave(fname, len);
3755 vim_free(fbuf);
3756}
3757
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003758/*
3759 * "foldclosed()" function
3760 */
3761 static void
3762foldclosed_both(
3763 typval_T *argvars UNUSED,
3764 typval_T *rettv,
3765 int end UNUSED)
3766{
3767#ifdef FEAT_FOLDING
3768 linenr_T lnum;
3769 linenr_T first, last;
3770
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003771 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003772 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3773 {
3774 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3775 {
3776 if (end)
3777 rettv->vval.v_number = (varnumber_T)last;
3778 else
3779 rettv->vval.v_number = (varnumber_T)first;
3780 return;
3781 }
3782 }
3783#endif
3784 rettv->vval.v_number = -1;
3785}
3786
3787/*
3788 * "foldclosed()" function
3789 */
3790 static void
3791f_foldclosed(typval_T *argvars, typval_T *rettv)
3792{
3793 foldclosed_both(argvars, rettv, FALSE);
3794}
3795
3796/*
3797 * "foldclosedend()" function
3798 */
3799 static void
3800f_foldclosedend(typval_T *argvars, typval_T *rettv)
3801{
3802 foldclosed_both(argvars, rettv, TRUE);
3803}
3804
3805/*
3806 * "foldlevel()" function
3807 */
3808 static void
3809f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3810{
3811#ifdef FEAT_FOLDING
3812 linenr_T lnum;
3813
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003814 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003815 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3816 rettv->vval.v_number = foldLevel(lnum);
3817#endif
3818}
3819
3820/*
3821 * "foldtext()" function
3822 */
3823 static void
3824f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3825{
3826#ifdef FEAT_FOLDING
3827 linenr_T foldstart;
3828 linenr_T foldend;
3829 char_u *dashes;
3830 linenr_T lnum;
3831 char_u *s;
3832 char_u *r;
3833 int len;
3834 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003835 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003836#endif
3837
3838 rettv->v_type = VAR_STRING;
3839 rettv->vval.v_string = NULL;
3840#ifdef FEAT_FOLDING
3841 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3842 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3843 dashes = get_vim_var_str(VV_FOLDDASHES);
3844 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3845 && dashes != NULL)
3846 {
3847 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003848 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003849 if (!linewhite(lnum))
3850 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003851
3852 /* Find interesting text in this line. */
3853 s = skipwhite(ml_get(lnum));
3854 /* skip C comment-start */
3855 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3856 {
3857 s = skipwhite(s + 2);
3858 if (*skipwhite(s) == NUL
3859 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3860 {
3861 s = skipwhite(ml_get(lnum + 1));
3862 if (*s == '*')
3863 s = skipwhite(s + 1);
3864 }
3865 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003866 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003867 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003868 r = alloc(STRLEN(txt)
3869 + STRLEN(dashes) // for %s
3870 + 20 // for %3ld
3871 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003872 if (r != NULL)
3873 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003874 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003875 len = (int)STRLEN(r);
3876 STRCAT(r, s);
3877 /* remove 'foldmarker' and 'commentstring' */
3878 foldtext_cleanup(r + len);
3879 rettv->vval.v_string = r;
3880 }
3881 }
3882#endif
3883}
3884
3885/*
3886 * "foldtextresult(lnum)" function
3887 */
3888 static void
3889f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3890{
3891#ifdef FEAT_FOLDING
3892 linenr_T lnum;
3893 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003894 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003895 foldinfo_T foldinfo;
3896 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003897 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003898#endif
3899
3900 rettv->v_type = VAR_STRING;
3901 rettv->vval.v_string = NULL;
3902#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003903 if (entered)
3904 return; /* reject recursive use */
3905 entered = TRUE;
3906
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003907 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003908 /* treat illegal types and illegal string values for {lnum} the same */
3909 if (lnum < 0)
3910 lnum = 0;
3911 fold_count = foldedCount(curwin, lnum, &foldinfo);
3912 if (fold_count > 0)
3913 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003914 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3915 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003916 if (text == buf)
3917 text = vim_strsave(text);
3918 rettv->vval.v_string = text;
3919 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003920
3921 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003922#endif
3923}
3924
3925/*
3926 * "foreground()" function
3927 */
3928 static void
3929f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3930{
3931#ifdef FEAT_GUI
3932 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003933 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003935 return;
3936 }
3937#endif
3938#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003939 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003940#endif
3941}
3942
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003943 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003944common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003945{
3946 char_u *s;
3947 char_u *name;
3948 int use_string = FALSE;
3949 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003950 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003951
3952 if (argvars[0].v_type == VAR_FUNC)
3953 {
3954 /* function(MyFunc, [arg], dict) */
3955 s = argvars[0].vval.v_string;
3956 }
3957 else if (argvars[0].v_type == VAR_PARTIAL
3958 && argvars[0].vval.v_partial != NULL)
3959 {
3960 /* function(dict.MyFunc, [arg]) */
3961 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003962 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003963 }
3964 else
3965 {
3966 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003967 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003968 use_string = TRUE;
3969 }
3970
Bram Moolenaar843b8842016-08-21 14:36:15 +02003971 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003972 {
3973 name = s;
3974 trans_name = trans_function_name(&name, FALSE,
3975 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3976 if (*name != NUL)
3977 s = NULL;
3978 }
3979
Bram Moolenaar843b8842016-08-21 14:36:15 +02003980 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3981 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003982 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003983 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003984 else if (trans_name != NULL && (is_funcref
3985 ? find_func(trans_name) == NULL
3986 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003987 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003988 else
3989 {
3990 int dict_idx = 0;
3991 int arg_idx = 0;
3992 list_T *list = NULL;
3993
3994 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3995 {
3996 char sid_buf[25];
3997 int off = *s == 's' ? 2 : 5;
3998
3999 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4000 * also be called from another script. Using trans_function_name()
4001 * would also work, but some plugins depend on the name being
4002 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004003 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02004004 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004005 if (name != NULL)
4006 {
4007 STRCPY(name, sid_buf);
4008 STRCAT(name, s + off);
4009 }
4010 }
4011 else
4012 name = vim_strsave(s);
4013
4014 if (argvars[1].v_type != VAR_UNKNOWN)
4015 {
4016 if (argvars[2].v_type != VAR_UNKNOWN)
4017 {
4018 /* function(name, [args], dict) */
4019 arg_idx = 1;
4020 dict_idx = 2;
4021 }
4022 else if (argvars[1].v_type == VAR_DICT)
4023 /* function(name, dict) */
4024 dict_idx = 1;
4025 else
4026 /* function(name, [args]) */
4027 arg_idx = 1;
4028 if (dict_idx > 0)
4029 {
4030 if (argvars[dict_idx].v_type != VAR_DICT)
4031 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004032 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004033 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004034 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004035 }
4036 if (argvars[dict_idx].vval.v_dict == NULL)
4037 dict_idx = 0;
4038 }
4039 if (arg_idx > 0)
4040 {
4041 if (argvars[arg_idx].v_type != VAR_LIST)
4042 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004043 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004045 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004046 }
4047 list = argvars[arg_idx].vval.v_list;
4048 if (list == NULL || list->lv_len == 0)
4049 arg_idx = 0;
4050 }
4051 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004052 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004053 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004054 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004055
4056 /* result is a VAR_PARTIAL */
4057 if (pt == NULL)
4058 vim_free(name);
4059 else
4060 {
4061 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4062 {
4063 listitem_T *li;
4064 int i = 0;
4065 int arg_len = 0;
4066 int lv_len = 0;
4067
4068 if (arg_pt != NULL)
4069 arg_len = arg_pt->pt_argc;
4070 if (list != NULL)
4071 lv_len = list->lv_len;
4072 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02004073 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004074 if (pt->pt_argv == NULL)
4075 {
4076 vim_free(pt);
4077 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004078 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004079 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004080 for (i = 0; i < arg_len; i++)
4081 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4082 if (lv_len > 0)
4083 for (li = list->lv_first; li != NULL;
4084 li = li->li_next)
4085 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004086 }
4087
4088 /* For "function(dict.func, [], dict)" and "func" is a partial
4089 * use "dict". That is backwards compatible. */
4090 if (dict_idx > 0)
4091 {
4092 /* The dict is bound explicitly, pt_auto is FALSE. */
4093 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4094 ++pt->pt_dict->dv_refcount;
4095 }
4096 else if (arg_pt != NULL)
4097 {
4098 /* If the dict was bound automatically the result is also
4099 * bound automatically. */
4100 pt->pt_dict = arg_pt->pt_dict;
4101 pt->pt_auto = arg_pt->pt_auto;
4102 if (pt->pt_dict != NULL)
4103 ++pt->pt_dict->dv_refcount;
4104 }
4105
4106 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004107 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4108 {
4109 pt->pt_func = arg_pt->pt_func;
4110 func_ptr_ref(pt->pt_func);
4111 vim_free(name);
4112 }
4113 else if (is_funcref)
4114 {
4115 pt->pt_func = find_func(trans_name);
4116 func_ptr_ref(pt->pt_func);
4117 vim_free(name);
4118 }
4119 else
4120 {
4121 pt->pt_name = name;
4122 func_ref(name);
4123 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004124 }
4125 rettv->v_type = VAR_PARTIAL;
4126 rettv->vval.v_partial = pt;
4127 }
4128 else
4129 {
4130 /* result is a VAR_FUNC */
4131 rettv->v_type = VAR_FUNC;
4132 rettv->vval.v_string = name;
4133 func_ref(name);
4134 }
4135 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004136theend:
4137 vim_free(trans_name);
4138}
4139
4140/*
4141 * "funcref()" function
4142 */
4143 static void
4144f_funcref(typval_T *argvars, typval_T *rettv)
4145{
4146 common_function(argvars, rettv, TRUE);
4147}
4148
4149/*
4150 * "function()" function
4151 */
4152 static void
4153f_function(typval_T *argvars, typval_T *rettv)
4154{
4155 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156}
4157
4158/*
4159 * "garbagecollect()" function
4160 */
4161 static void
4162f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4163{
4164 /* This is postponed until we are back at the toplevel, because we may be
4165 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4166 want_garbage_collect = TRUE;
4167
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004168 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004169 garbage_collect_at_exit = TRUE;
4170}
4171
4172/*
4173 * "get()" function
4174 */
4175 static void
4176f_get(typval_T *argvars, typval_T *rettv)
4177{
4178 listitem_T *li;
4179 list_T *l;
4180 dictitem_T *di;
4181 dict_T *d;
4182 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004183 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004184
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004185 if (argvars[0].v_type == VAR_BLOB)
4186 {
4187 int error = FALSE;
4188 int idx = tv_get_number_chk(&argvars[1], &error);
4189
4190 if (!error)
4191 {
4192 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004193 if (idx < 0)
4194 idx = blob_len(argvars[0].vval.v_blob) + idx;
4195 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4196 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004197 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004198 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004199 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004200 tv = rettv;
4201 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004202 }
4203 }
4204 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004205 {
4206 if ((l = argvars[0].vval.v_list) != NULL)
4207 {
4208 int error = FALSE;
4209
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004210 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004211 if (!error && li != NULL)
4212 tv = &li->li_tv;
4213 }
4214 }
4215 else if (argvars[0].v_type == VAR_DICT)
4216 {
4217 if ((d = argvars[0].vval.v_dict) != NULL)
4218 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004219 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004220 if (di != NULL)
4221 tv = &di->di_tv;
4222 }
4223 }
4224 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4225 {
4226 partial_T *pt;
4227 partial_T fref_pt;
4228
4229 if (argvars[0].v_type == VAR_PARTIAL)
4230 pt = argvars[0].vval.v_partial;
4231 else
4232 {
4233 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4234 fref_pt.pt_name = argvars[0].vval.v_string;
4235 pt = &fref_pt;
4236 }
4237
4238 if (pt != NULL)
4239 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004240 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004241 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004242
4243 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4244 {
4245 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004246 n = partial_name(pt);
4247 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004248 rettv->vval.v_string = NULL;
4249 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004250 {
4251 rettv->vval.v_string = vim_strsave(n);
4252 if (rettv->v_type == VAR_FUNC)
4253 func_ref(rettv->vval.v_string);
4254 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255 }
4256 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004257 {
4258 what_is_dict = TRUE;
4259 if (pt->pt_dict != NULL)
4260 rettv_dict_set(rettv, pt->pt_dict);
4261 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004262 else if (STRCMP(what, "args") == 0)
4263 {
4264 rettv->v_type = VAR_LIST;
4265 if (rettv_list_alloc(rettv) == OK)
4266 {
4267 int i;
4268
4269 for (i = 0; i < pt->pt_argc; ++i)
4270 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4271 }
4272 }
4273 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004274 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004275
4276 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4277 // third argument
4278 if (!what_is_dict)
4279 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004280 }
4281 }
4282 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004283 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004284
4285 if (tv == NULL)
4286 {
4287 if (argvars[2].v_type != VAR_UNKNOWN)
4288 copy_tv(&argvars[2], rettv);
4289 }
4290 else
4291 copy_tv(tv, rettv);
4292}
4293
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004294/*
4295 * Returns buffer options, variables and other attributes in a dictionary.
4296 */
4297 static dict_T *
4298get_buffer_info(buf_T *buf)
4299{
4300 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004301 tabpage_T *tp;
4302 win_T *wp;
4303 list_T *windows;
4304
4305 dict = dict_alloc();
4306 if (dict == NULL)
4307 return NULL;
4308
Bram Moolenaare0be1672018-07-08 16:50:37 +02004309 dict_add_number(dict, "bufnr", buf->b_fnum);
4310 dict_add_string(dict, "name", buf->b_ffname);
4311 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4312 : buflist_findlnum(buf));
4313 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4314 dict_add_number(dict, "listed", buf->b_p_bl);
4315 dict_add_number(dict, "changed", bufIsChanged(buf));
4316 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4317 dict_add_number(dict, "hidden",
4318 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004319
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004320 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004321 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004322
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004323 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004324 windows = list_alloc();
4325 if (windows != NULL)
4326 {
4327 FOR_ALL_TAB_WINDOWS(tp, wp)
4328 if (wp->w_buffer == buf)
4329 list_append_number(windows, (varnumber_T)wp->w_id);
4330 dict_add_list(dict, "windows", windows);
4331 }
4332
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004333#ifdef FEAT_TEXT_PROP
4334 // List of popup windows displaying this buffer
4335 windows = list_alloc();
4336 if (windows != NULL)
4337 {
4338 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4339 if (wp->w_buffer == buf)
4340 list_append_number(windows, (varnumber_T)wp->w_id);
4341 FOR_ALL_TABPAGES(tp)
4342 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4343 if (wp->w_buffer == buf)
4344 list_append_number(windows, (varnumber_T)wp->w_id);
4345
4346 dict_add_list(dict, "popups", windows);
4347 }
4348#endif
4349
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004350#ifdef FEAT_SIGNS
4351 if (buf->b_signlist != NULL)
4352 {
4353 /* List of signs placed in this buffer */
4354 list_T *signs = list_alloc();
4355 if (signs != NULL)
4356 {
4357 get_buffer_signs(buf, signs);
4358 dict_add_list(dict, "signs", signs);
4359 }
4360 }
4361#endif
4362
4363 return dict;
4364}
4365
4366/*
4367 * "getbufinfo()" function
4368 */
4369 static void
4370f_getbufinfo(typval_T *argvars, typval_T *rettv)
4371{
4372 buf_T *buf = NULL;
4373 buf_T *argbuf = NULL;
4374 dict_T *d;
4375 int filtered = FALSE;
4376 int sel_buflisted = FALSE;
4377 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004378 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004379
4380 if (rettv_list_alloc(rettv) != OK)
4381 return;
4382
4383 /* List of all the buffers or selected buffers */
4384 if (argvars[0].v_type == VAR_DICT)
4385 {
4386 dict_T *sel_d = argvars[0].vval.v_dict;
4387
4388 if (sel_d != NULL)
4389 {
4390 dictitem_T *di;
4391
4392 filtered = TRUE;
4393
4394 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004395 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004396 sel_buflisted = TRUE;
4397
4398 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004399 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004400 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004401
4402 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004403 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004404 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004405 }
4406 }
4407 else if (argvars[0].v_type != VAR_UNKNOWN)
4408 {
4409 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004410 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004411 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004412 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004413 --emsg_off;
4414 if (argbuf == NULL)
4415 return;
4416 }
4417
4418 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004419 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004420 {
4421 if (argbuf != NULL && argbuf != buf)
4422 continue;
4423 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004424 || (sel_buflisted && !buf->b_p_bl)
4425 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004426 continue;
4427
4428 d = get_buffer_info(buf);
4429 if (d != NULL)
4430 list_append_dict(rettv->vval.v_list, d);
4431 if (argbuf != NULL)
4432 return;
4433 }
4434}
4435
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004436/*
4437 * Get line or list of lines from buffer "buf" into "rettv".
4438 * Return a range (from start to end) of lines in rettv from the specified
4439 * buffer.
4440 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4441 */
4442 static void
4443get_buffer_lines(
4444 buf_T *buf,
4445 linenr_T start,
4446 linenr_T end,
4447 int retlist,
4448 typval_T *rettv)
4449{
4450 char_u *p;
4451
4452 rettv->v_type = VAR_STRING;
4453 rettv->vval.v_string = NULL;
4454 if (retlist && rettv_list_alloc(rettv) == FAIL)
4455 return;
4456
4457 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4458 return;
4459
4460 if (!retlist)
4461 {
4462 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4463 p = ml_get_buf(buf, start, FALSE);
4464 else
4465 p = (char_u *)"";
4466 rettv->vval.v_string = vim_strsave(p);
4467 }
4468 else
4469 {
4470 if (end < start)
4471 return;
4472
4473 if (start < 1)
4474 start = 1;
4475 if (end > buf->b_ml.ml_line_count)
4476 end = buf->b_ml.ml_line_count;
4477 while (start <= end)
4478 if (list_append_string(rettv->vval.v_list,
4479 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4480 break;
4481 }
4482}
4483
4484/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004485 * "getbufline()" function
4486 */
4487 static void
4488f_getbufline(typval_T *argvars, typval_T *rettv)
4489{
4490 linenr_T lnum;
4491 linenr_T end;
4492 buf_T *buf;
4493
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004494 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004495 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004496 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004497 --emsg_off;
4498
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004499 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004500 if (argvars[2].v_type == VAR_UNKNOWN)
4501 end = lnum;
4502 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004503 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004504
4505 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4506}
4507
4508/*
4509 * "getbufvar()" function
4510 */
4511 static void
4512f_getbufvar(typval_T *argvars, typval_T *rettv)
4513{
4514 buf_T *buf;
4515 buf_T *save_curbuf;
4516 char_u *varname;
4517 dictitem_T *v;
4518 int done = FALSE;
4519
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004520 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4521 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004522 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004523 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004524
4525 rettv->v_type = VAR_STRING;
4526 rettv->vval.v_string = NULL;
4527
4528 if (buf != NULL && varname != NULL)
4529 {
4530 /* set curbuf to be our buf, temporarily */
4531 save_curbuf = curbuf;
4532 curbuf = buf;
4533
Bram Moolenaar30567352016-08-27 21:25:44 +02004534 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004535 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004536 if (varname[1] == NUL)
4537 {
4538 /* get all buffer-local options in a dict */
4539 dict_T *opts = get_winbuf_options(TRUE);
4540
4541 if (opts != NULL)
4542 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004543 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004544 done = TRUE;
4545 }
4546 }
4547 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4548 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549 done = TRUE;
4550 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004551 else
4552 {
4553 /* Look up the variable. */
4554 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4555 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4556 'b', varname, FALSE);
4557 if (v != NULL)
4558 {
4559 copy_tv(&v->di_tv, rettv);
4560 done = TRUE;
4561 }
4562 }
4563
4564 /* restore previous notion of curbuf */
4565 curbuf = save_curbuf;
4566 }
4567
4568 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4569 /* use the default value */
4570 copy_tv(&argvars[2], rettv);
4571
4572 --emsg_off;
4573}
4574
4575/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004576 * "getchangelist()" function
4577 */
4578 static void
4579f_getchangelist(typval_T *argvars, typval_T *rettv)
4580{
4581#ifdef FEAT_JUMPLIST
4582 buf_T *buf;
4583 int i;
4584 list_T *l;
4585 dict_T *d;
4586#endif
4587
4588 if (rettv_list_alloc(rettv) != OK)
4589 return;
4590
4591#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004592 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004593 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004594 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004595 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004596 if (buf == NULL)
4597 return;
4598
4599 l = list_alloc();
4600 if (l == NULL)
4601 return;
4602
4603 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4604 return;
4605 /*
4606 * The current window change list index tracks only the position in the
4607 * current buffer change list. For other buffers, use the change list
4608 * length as the current index.
4609 */
4610 list_append_number(rettv->vval.v_list,
4611 (varnumber_T)((buf == curwin->w_buffer)
4612 ? curwin->w_changelistidx : buf->b_changelistlen));
4613
4614 for (i = 0; i < buf->b_changelistlen; ++i)
4615 {
4616 if (buf->b_changelist[i].lnum == 0)
4617 continue;
4618 if ((d = dict_alloc()) == NULL)
4619 return;
4620 if (list_append_dict(l, d) == FAIL)
4621 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004622 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4623 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004624 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004625 }
4626#endif
4627}
4628/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004629 * "getchar()" function
4630 */
4631 static void
4632f_getchar(typval_T *argvars, typval_T *rettv)
4633{
4634 varnumber_T n;
4635 int error = FALSE;
4636
Bram Moolenaar84d93902018-09-11 20:10:20 +02004637#ifdef MESSAGE_QUEUE
4638 // vpeekc() used to check for messages, but that caused problems, invoking
4639 // a callback where it was not expected. Some plugins use getchar(1) in a
4640 // loop to await a message, therefore make sure we check for messages here.
4641 parse_queued_messages();
4642#endif
4643
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004644 /* Position the cursor. Needed after a message that ends in a space. */
4645 windgoto(msg_row, msg_col);
4646
4647 ++no_mapping;
4648 ++allow_keys;
4649 for (;;)
4650 {
4651 if (argvars[0].v_type == VAR_UNKNOWN)
4652 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004653 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004654 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004655 /* getchar(1): only check if char avail */
4656 n = vpeekc_any();
4657 else if (error || vpeekc_any() == NUL)
4658 /* illegal argument or getchar(0) and no char avail: return zero */
4659 n = 0;
4660 else
4661 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004662 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663
4664 if (n == K_IGNORE)
4665 continue;
4666 break;
4667 }
4668 --no_mapping;
4669 --allow_keys;
4670
4671 set_vim_var_nr(VV_MOUSE_WIN, 0);
4672 set_vim_var_nr(VV_MOUSE_WINID, 0);
4673 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4674 set_vim_var_nr(VV_MOUSE_COL, 0);
4675
4676 rettv->vval.v_number = n;
4677 if (IS_SPECIAL(n) || mod_mask != 0)
4678 {
4679 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4680 int i = 0;
4681
4682 /* Turn a special key into three bytes, plus modifier. */
4683 if (mod_mask != 0)
4684 {
4685 temp[i++] = K_SPECIAL;
4686 temp[i++] = KS_MODIFIER;
4687 temp[i++] = mod_mask;
4688 }
4689 if (IS_SPECIAL(n))
4690 {
4691 temp[i++] = K_SPECIAL;
4692 temp[i++] = K_SECOND(n);
4693 temp[i++] = K_THIRD(n);
4694 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004695 else if (has_mbyte)
4696 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004697 else
4698 temp[i++] = n;
4699 temp[i++] = NUL;
4700 rettv->v_type = VAR_STRING;
4701 rettv->vval.v_string = vim_strsave(temp);
4702
4703#ifdef FEAT_MOUSE
4704 if (is_mouse_key(n))
4705 {
4706 int row = mouse_row;
4707 int col = mouse_col;
4708 win_T *win;
4709 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004711 int winnr = 1;
4712
4713 if (row >= 0 && col >= 0)
4714 {
4715 /* Find the window at the mouse coordinates and compute the
4716 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004717 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004718 if (win == NULL)
4719 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004720 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004721# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004722 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004723 winnr = 0;
4724 else
4725# endif
4726 for (wp = firstwin; wp != win && wp != NULL;
4727 wp = wp->w_next)
4728 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4730 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4731 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4732 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4733 }
4734 }
4735#endif
4736 }
4737}
4738
4739/*
4740 * "getcharmod()" function
4741 */
4742 static void
4743f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4744{
4745 rettv->vval.v_number = mod_mask;
4746}
4747
4748/*
4749 * "getcharsearch()" function
4750 */
4751 static void
4752f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4753{
4754 if (rettv_dict_alloc(rettv) != FAIL)
4755 {
4756 dict_T *dict = rettv->vval.v_dict;
4757
Bram Moolenaare0be1672018-07-08 16:50:37 +02004758 dict_add_string(dict, "char", last_csearch());
4759 dict_add_number(dict, "forward", last_csearch_forward());
4760 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004761 }
4762}
4763
4764/*
4765 * "getcmdline()" function
4766 */
4767 static void
4768f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4769{
4770 rettv->v_type = VAR_STRING;
4771 rettv->vval.v_string = get_cmdline_str();
4772}
4773
4774/*
4775 * "getcmdpos()" function
4776 */
4777 static void
4778f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4779{
4780 rettv->vval.v_number = get_cmdline_pos() + 1;
4781}
4782
4783/*
4784 * "getcmdtype()" function
4785 */
4786 static void
4787f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4788{
4789 rettv->v_type = VAR_STRING;
4790 rettv->vval.v_string = alloc(2);
4791 if (rettv->vval.v_string != NULL)
4792 {
4793 rettv->vval.v_string[0] = get_cmdline_type();
4794 rettv->vval.v_string[1] = NUL;
4795 }
4796}
4797
4798/*
4799 * "getcmdwintype()" function
4800 */
4801 static void
4802f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4803{
4804 rettv->v_type = VAR_STRING;
4805 rettv->vval.v_string = NULL;
4806#ifdef FEAT_CMDWIN
4807 rettv->vval.v_string = alloc(2);
4808 if (rettv->vval.v_string != NULL)
4809 {
4810 rettv->vval.v_string[0] = cmdwin_type;
4811 rettv->vval.v_string[1] = NUL;
4812 }
4813#endif
4814}
4815
4816#if defined(FEAT_CMDL_COMPL)
4817/*
4818 * "getcompletion()" function
4819 */
4820 static void
4821f_getcompletion(typval_T *argvars, typval_T *rettv)
4822{
4823 char_u *pat;
4824 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004825 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004826 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
4827 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004829 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004830 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832 if (p_wic)
4833 options |= WILD_ICASE;
4834
Bram Moolenaare9d58a62016-08-13 15:07:41 +02004835 /* For filtered results, 'wildignore' is used */
4836 if (!filtered)
4837 options |= WILD_KEEP_ALL;
4838
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004840 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004842 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004843 if (xpc.xp_context == EXPAND_NOTHING)
4844 {
4845 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004846 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004847 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004848 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004849 return;
4850 }
4851
4852# if defined(FEAT_MENU)
4853 if (xpc.xp_context == EXPAND_MENUS)
4854 {
4855 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
4856 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4857 }
4858# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02004859#ifdef FEAT_CSCOPE
4860 if (xpc.xp_context == EXPAND_CSCOPE)
4861 {
4862 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
4863 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4864 }
4865#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02004866#ifdef FEAT_SIGNS
4867 if (xpc.xp_context == EXPAND_SIGN)
4868 {
4869 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
4870 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
4871 }
4872#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004873
4874 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
4875 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
4876 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02004877 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878
4879 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
4880
4881 for (i = 0; i < xpc.xp_numfiles; i++)
4882 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
4883 }
4884 vim_free(pat);
4885 ExpandCleanup(&xpc);
4886}
4887#endif
4888
4889/*
4890 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004891 *
4892 * Return the current working directory of a window in a tab page.
4893 * First optional argument 'winnr' is the window number or -1 and the second
4894 * optional argument 'tabnr' is the tab page number.
4895 *
4896 * If no arguments are supplied, then return the directory of the current
4897 * window.
4898 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4899 * the specified window.
4900 * If 'winnr' is 0 then return the directory of the current window.
4901 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4902 * directory of the specified tab page. Otherwise return the directory of the
4903 * specified window in the specified tab page.
4904 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004905 */
4906 static void
4907f_getcwd(typval_T *argvars, typval_T *rettv)
4908{
4909 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004910 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004912 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004913
4914 rettv->v_type = VAR_STRING;
4915 rettv->vval.v_string = NULL;
4916
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004917 if (argvars[0].v_type == VAR_NUMBER
4918 && argvars[0].vval.v_number == -1
4919 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004920 global = TRUE;
4921 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004922 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004923
4924 if (wp != NULL && wp->w_localdir != NULL)
4925 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004926 else if (tp != NULL && tp->tp_localdir != NULL)
4927 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4928 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004929 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004930 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931 rettv->vval.v_string = vim_strsave(globaldir);
4932 else
4933 {
4934 cwd = alloc(MAXPATHL);
4935 if (cwd != NULL)
4936 {
4937 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4938 rettv->vval.v_string = vim_strsave(cwd);
4939 vim_free(cwd);
4940 }
4941 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004943#ifdef BACKSLASH_IN_FILENAME
4944 if (rettv->vval.v_string != NULL)
4945 slash_adjust(rettv->vval.v_string);
4946#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947}
4948
4949/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004950 * "getenv()" function
4951 */
4952 static void
4953f_getenv(typval_T *argvars, typval_T *rettv)
4954{
4955 int mustfree = FALSE;
4956 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4957
4958 if (p == NULL)
4959 {
4960 rettv->v_type = VAR_SPECIAL;
4961 rettv->vval.v_number = VVAL_NULL;
4962 return;
4963 }
4964 if (!mustfree)
4965 p = vim_strsave(p);
4966 rettv->vval.v_string = p;
4967 rettv->v_type = VAR_STRING;
4968}
4969
4970/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004971 * "getfontname()" function
4972 */
4973 static void
4974f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4975{
4976 rettv->v_type = VAR_STRING;
4977 rettv->vval.v_string = NULL;
4978#ifdef FEAT_GUI
4979 if (gui.in_use)
4980 {
4981 GuiFont font;
4982 char_u *name = NULL;
4983
4984 if (argvars[0].v_type == VAR_UNKNOWN)
4985 {
4986 /* Get the "Normal" font. Either the name saved by
4987 * hl_set_font_name() or from the font ID. */
4988 font = gui.norm_font;
4989 name = hl_get_font_name();
4990 }
4991 else
4992 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004993 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004994 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4995 return;
4996 font = gui_mch_get_font(name, FALSE);
4997 if (font == NOFONT)
4998 return; /* Invalid font name, return empty string. */
4999 }
5000 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5001 if (argvars[0].v_type != VAR_UNKNOWN)
5002 gui_mch_free_font(font);
5003 }
5004#endif
5005}
5006
5007/*
5008 * "getfperm({fname})" function
5009 */
5010 static void
5011f_getfperm(typval_T *argvars, typval_T *rettv)
5012{
5013 char_u *fname;
5014 stat_T st;
5015 char_u *perm = NULL;
5016 char_u flags[] = "rwx";
5017 int i;
5018
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005019 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005020
5021 rettv->v_type = VAR_STRING;
5022 if (mch_stat((char *)fname, &st) >= 0)
5023 {
5024 perm = vim_strsave((char_u *)"---------");
5025 if (perm != NULL)
5026 {
5027 for (i = 0; i < 9; i++)
5028 {
5029 if (st.st_mode & (1 << (8 - i)))
5030 perm[i] = flags[i % 3];
5031 }
5032 }
5033 }
5034 rettv->vval.v_string = perm;
5035}
5036
5037/*
5038 * "getfsize({fname})" function
5039 */
5040 static void
5041f_getfsize(typval_T *argvars, typval_T *rettv)
5042{
5043 char_u *fname;
5044 stat_T st;
5045
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005046 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005047
5048 rettv->v_type = VAR_NUMBER;
5049
5050 if (mch_stat((char *)fname, &st) >= 0)
5051 {
5052 if (mch_isdir(fname))
5053 rettv->vval.v_number = 0;
5054 else
5055 {
5056 rettv->vval.v_number = (varnumber_T)st.st_size;
5057
5058 /* non-perfect check for overflow */
5059 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5060 rettv->vval.v_number = -2;
5061 }
5062 }
5063 else
5064 rettv->vval.v_number = -1;
5065}
5066
5067/*
5068 * "getftime({fname})" function
5069 */
5070 static void
5071f_getftime(typval_T *argvars, typval_T *rettv)
5072{
5073 char_u *fname;
5074 stat_T st;
5075
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005076 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077
5078 if (mch_stat((char *)fname, &st) >= 0)
5079 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5080 else
5081 rettv->vval.v_number = -1;
5082}
5083
5084/*
5085 * "getftype({fname})" function
5086 */
5087 static void
5088f_getftype(typval_T *argvars, typval_T *rettv)
5089{
5090 char_u *fname;
5091 stat_T st;
5092 char_u *type = NULL;
5093 char *t;
5094
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005095 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096
5097 rettv->v_type = VAR_STRING;
5098 if (mch_lstat((char *)fname, &st) >= 0)
5099 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005100 if (S_ISREG(st.st_mode))
5101 t = "file";
5102 else if (S_ISDIR(st.st_mode))
5103 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104 else if (S_ISLNK(st.st_mode))
5105 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106 else if (S_ISBLK(st.st_mode))
5107 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108 else if (S_ISCHR(st.st_mode))
5109 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110 else if (S_ISFIFO(st.st_mode))
5111 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005112 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005113 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114 else
5115 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005116 type = vim_strsave((char_u *)t);
5117 }
5118 rettv->vval.v_string = type;
5119}
5120
5121/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005122 * "getjumplist()" function
5123 */
5124 static void
5125f_getjumplist(typval_T *argvars, typval_T *rettv)
5126{
5127#ifdef FEAT_JUMPLIST
5128 win_T *wp;
5129 int i;
5130 list_T *l;
5131 dict_T *d;
5132#endif
5133
5134 if (rettv_list_alloc(rettv) != OK)
5135 return;
5136
5137#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005138 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005139 if (wp == NULL)
5140 return;
5141
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005142 cleanup_jumplist(wp, TRUE);
5143
Bram Moolenaar4f505882018-02-10 21:06:32 +01005144 l = list_alloc();
5145 if (l == NULL)
5146 return;
5147
5148 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5149 return;
5150 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5151
5152 for (i = 0; i < wp->w_jumplistlen; ++i)
5153 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005154 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5155 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005156 if ((d = dict_alloc()) == NULL)
5157 return;
5158 if (list_append_dict(l, d) == FAIL)
5159 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005160 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5161 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005162 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005163 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005164 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005165 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005166 }
5167#endif
5168}
5169
5170/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171 * "getline(lnum, [end])" function
5172 */
5173 static void
5174f_getline(typval_T *argvars, typval_T *rettv)
5175{
5176 linenr_T lnum;
5177 linenr_T end;
5178 int retlist;
5179
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005180 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005181 if (argvars[1].v_type == VAR_UNKNOWN)
5182 {
5183 end = 0;
5184 retlist = FALSE;
5185 }
5186 else
5187 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005188 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005189 retlist = TRUE;
5190 }
5191
5192 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5193}
5194
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005195#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005196 static void
5197get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5198{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005199 if (what_arg->v_type == VAR_UNKNOWN)
5200 {
5201 if (rettv_list_alloc(rettv) == OK)
5202 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005203 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005204 }
5205 else
5206 {
5207 if (rettv_dict_alloc(rettv) == OK)
5208 if (is_qf || (wp != NULL))
5209 {
5210 if (what_arg->v_type == VAR_DICT)
5211 {
5212 dict_T *d = what_arg->vval.v_dict;
5213
5214 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005215 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005216 }
5217 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005218 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005219 }
5220 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005221}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005222#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005223
5224/*
5225 * "getloclist()" function
5226 */
5227 static void
5228f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5229{
5230#ifdef FEAT_QUICKFIX
5231 win_T *wp;
5232
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005233 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005234 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5235#endif
5236}
5237
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005238/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005239 * "getpid()" function
5240 */
5241 static void
5242f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5243{
5244 rettv->vval.v_number = mch_get_pid();
5245}
5246
5247 static void
5248getpos_both(
5249 typval_T *argvars,
5250 typval_T *rettv,
5251 int getcurpos)
5252{
5253 pos_T *fp;
5254 list_T *l;
5255 int fnum = -1;
5256
5257 if (rettv_list_alloc(rettv) == OK)
5258 {
5259 l = rettv->vval.v_list;
5260 if (getcurpos)
5261 fp = &curwin->w_cursor;
5262 else
5263 fp = var2fpos(&argvars[0], TRUE, &fnum);
5264 if (fnum != -1)
5265 list_append_number(l, (varnumber_T)fnum);
5266 else
5267 list_append_number(l, (varnumber_T)0);
5268 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5269 : (varnumber_T)0);
5270 list_append_number(l, (fp != NULL)
5271 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5272 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005273 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005274 (varnumber_T)0);
5275 if (getcurpos)
5276 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005277 int save_set_curswant = curwin->w_set_curswant;
5278 colnr_T save_curswant = curwin->w_curswant;
5279 colnr_T save_virtcol = curwin->w_virtcol;
5280
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005281 update_curswant();
5282 list_append_number(l, curwin->w_curswant == MAXCOL ?
5283 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005284
5285 // Do not change "curswant", as it is unexpected that a get
5286 // function has a side effect.
5287 if (save_set_curswant)
5288 {
5289 curwin->w_set_curswant = save_set_curswant;
5290 curwin->w_curswant = save_curswant;
5291 curwin->w_virtcol = save_virtcol;
5292 curwin->w_valid &= ~VALID_VIRTCOL;
5293 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294 }
5295 }
5296 else
5297 rettv->vval.v_number = FALSE;
5298}
5299
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005300/*
5301 * "getcurpos()" function
5302 */
5303 static void
5304f_getcurpos(typval_T *argvars, typval_T *rettv)
5305{
5306 getpos_both(argvars, rettv, TRUE);
5307}
5308
5309/*
5310 * "getpos(string)" function
5311 */
5312 static void
5313f_getpos(typval_T *argvars, typval_T *rettv)
5314{
5315 getpos_both(argvars, rettv, FALSE);
5316}
5317
5318/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005319 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005320 */
5321 static void
5322f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5323{
5324#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005325 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005326#endif
5327}
5328
5329/*
5330 * "getreg()" function
5331 */
5332 static void
5333f_getreg(typval_T *argvars, typval_T *rettv)
5334{
5335 char_u *strregname;
5336 int regname;
5337 int arg2 = FALSE;
5338 int return_list = FALSE;
5339 int error = FALSE;
5340
5341 if (argvars[0].v_type != VAR_UNKNOWN)
5342 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005343 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005344 error = strregname == NULL;
5345 if (argvars[1].v_type != VAR_UNKNOWN)
5346 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005347 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005348 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005349 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005350 }
5351 }
5352 else
5353 strregname = get_vim_var_str(VV_REG);
5354
5355 if (error)
5356 return;
5357
5358 regname = (strregname == NULL ? '"' : *strregname);
5359 if (regname == 0)
5360 regname = '"';
5361
5362 if (return_list)
5363 {
5364 rettv->v_type = VAR_LIST;
5365 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5366 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5367 if (rettv->vval.v_list == NULL)
5368 (void)rettv_list_alloc(rettv);
5369 else
5370 ++rettv->vval.v_list->lv_refcount;
5371 }
5372 else
5373 {
5374 rettv->v_type = VAR_STRING;
5375 rettv->vval.v_string = get_reg_contents(regname,
5376 arg2 ? GREG_EXPR_SRC : 0);
5377 }
5378}
5379
5380/*
5381 * "getregtype()" function
5382 */
5383 static void
5384f_getregtype(typval_T *argvars, typval_T *rettv)
5385{
5386 char_u *strregname;
5387 int regname;
5388 char_u buf[NUMBUFLEN + 2];
5389 long reglen = 0;
5390
5391 if (argvars[0].v_type != VAR_UNKNOWN)
5392 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005393 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005394 if (strregname == NULL) /* type error; errmsg already given */
5395 {
5396 rettv->v_type = VAR_STRING;
5397 rettv->vval.v_string = NULL;
5398 return;
5399 }
5400 }
5401 else
5402 /* Default to v:register */
5403 strregname = get_vim_var_str(VV_REG);
5404
5405 regname = (strregname == NULL ? '"' : *strregname);
5406 if (regname == 0)
5407 regname = '"';
5408
5409 buf[0] = NUL;
5410 buf[1] = NUL;
5411 switch (get_reg_type(regname, &reglen))
5412 {
5413 case MLINE: buf[0] = 'V'; break;
5414 case MCHAR: buf[0] = 'v'; break;
5415 case MBLOCK:
5416 buf[0] = Ctrl_V;
5417 sprintf((char *)buf + 1, "%ld", reglen + 1);
5418 break;
5419 }
5420 rettv->v_type = VAR_STRING;
5421 rettv->vval.v_string = vim_strsave(buf);
5422}
5423
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005424/*
5425 * Returns information (variables, options, etc.) about a tab page
5426 * as a dictionary.
5427 */
5428 static dict_T *
5429get_tabpage_info(tabpage_T *tp, int tp_idx)
5430{
5431 win_T *wp;
5432 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005433 list_T *l;
5434
5435 dict = dict_alloc();
5436 if (dict == NULL)
5437 return NULL;
5438
Bram Moolenaare0be1672018-07-08 16:50:37 +02005439 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005440
5441 l = list_alloc();
5442 if (l != NULL)
5443 {
5444 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005445 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005446 list_append_number(l, (varnumber_T)wp->w_id);
5447 dict_add_list(dict, "windows", l);
5448 }
5449
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005450 /* Make a reference to tabpage variables */
5451 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005452
5453 return dict;
5454}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005455
5456/*
5457 * "gettabinfo()" function
5458 */
5459 static void
5460f_gettabinfo(typval_T *argvars, typval_T *rettv)
5461{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005462 tabpage_T *tp, *tparg = NULL;
5463 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005464 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005465
5466 if (rettv_list_alloc(rettv) != OK)
5467 return;
5468
5469 if (argvars[0].v_type != VAR_UNKNOWN)
5470 {
5471 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005472 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005473 if (tparg == NULL)
5474 return;
5475 }
5476
5477 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005478 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005479 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005480 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005481 if (tparg != NULL && tp != tparg)
5482 continue;
5483 d = get_tabpage_info(tp, tpnr);
5484 if (d != NULL)
5485 list_append_dict(rettv->vval.v_list, d);
5486 if (tparg != NULL)
5487 return;
5488 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005489}
5490
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491/*
5492 * "gettabvar()" function
5493 */
5494 static void
5495f_gettabvar(typval_T *argvars, typval_T *rettv)
5496{
5497 win_T *oldcurwin;
5498 tabpage_T *tp, *oldtabpage;
5499 dictitem_T *v;
5500 char_u *varname;
5501 int done = FALSE;
5502
5503 rettv->v_type = VAR_STRING;
5504 rettv->vval.v_string = NULL;
5505
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005506 varname = tv_get_string_chk(&argvars[1]);
5507 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005508 if (tp != NULL && varname != NULL)
5509 {
5510 /* Set tp to be our tabpage, temporarily. Also set the window to the
5511 * first window in the tabpage, otherwise the window is not valid. */
5512 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005513 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5514 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005515 {
5516 /* look up the variable */
5517 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5518 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5519 if (v != NULL)
5520 {
5521 copy_tv(&v->di_tv, rettv);
5522 done = TRUE;
5523 }
5524 }
5525
5526 /* restore previous notion of curwin */
5527 restore_win(oldcurwin, oldtabpage, TRUE);
5528 }
5529
5530 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5531 copy_tv(&argvars[2], rettv);
5532}
5533
5534/*
5535 * "gettabwinvar()" function
5536 */
5537 static void
5538f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5539{
5540 getwinvar(argvars, rettv, 1);
5541}
5542
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005543/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005544 * "gettagstack()" function
5545 */
5546 static void
5547f_gettagstack(typval_T *argvars, typval_T *rettv)
5548{
5549 win_T *wp = curwin; // default is current window
5550
5551 if (rettv_dict_alloc(rettv) != OK)
5552 return;
5553
5554 if (argvars[0].v_type != VAR_UNKNOWN)
5555 {
5556 wp = find_win_by_nr_or_id(&argvars[0]);
5557 if (wp == NULL)
5558 return;
5559 }
5560
5561 get_tagstack(wp, rettv->vval.v_dict);
5562}
5563
5564/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005565 * Returns information about a window as a dictionary.
5566 */
5567 static dict_T *
5568get_win_info(win_T *wp, short tpnr, short winnr)
5569{
5570 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005571
5572 dict = dict_alloc();
5573 if (dict == NULL)
5574 return NULL;
5575
Bram Moolenaare0be1672018-07-08 16:50:37 +02005576 dict_add_number(dict, "tabnr", tpnr);
5577 dict_add_number(dict, "winnr", winnr);
5578 dict_add_number(dict, "winid", wp->w_id);
5579 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005580 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005581 dict_add_number(dict, "topline", wp->w_topline);
5582 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005583#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005584 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005585#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005586 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005587 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005588 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005589
Bram Moolenaar69905d12017-08-13 18:14:47 +02005590#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005591 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005592#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005593#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005594 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5595 dict_add_number(dict, "loclist",
5596 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005597#endif
5598
Bram Moolenaar30567352016-08-27 21:25:44 +02005599 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005600 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005601
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005602 return dict;
5603}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005604
5605/*
5606 * "getwininfo()" function
5607 */
5608 static void
5609f_getwininfo(typval_T *argvars, typval_T *rettv)
5610{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005611 tabpage_T *tp;
5612 win_T *wp = NULL, *wparg = NULL;
5613 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005614 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005615
5616 if (rettv_list_alloc(rettv) != OK)
5617 return;
5618
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005619 if (argvars[0].v_type != VAR_UNKNOWN)
5620 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005621 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005622 if (wparg == NULL)
5623 return;
5624 }
5625
5626 /* Collect information about either all the windows across all the tab
5627 * pages or one particular window.
5628 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005629 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005630 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005631 tabnr++;
5632 winnr = 0;
5633 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005634 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005635 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005636 if (wparg != NULL && wp != wparg)
5637 continue;
5638 d = get_win_info(wp, tabnr, winnr);
5639 if (d != NULL)
5640 list_append_dict(rettv->vval.v_list, d);
5641 if (wparg != NULL)
5642 /* found information about a specific window */
5643 return;
5644 }
5645 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005646}
5647
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005649 * "win_execute()" function
5650 */
5651 static void
5652f_win_execute(typval_T *argvars, typval_T *rettv)
5653{
5654 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005655 tabpage_T *tp;
5656 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005657 win_T *save_curwin;
5658 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005659
Bram Moolenaar820680b2019-08-09 14:56:22 +02005660 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005661 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005662 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005663 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005664 check_cursor();
5665 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005666 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005667 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005668 }
5669}
5670
5671/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005672 * "win_findbuf()" function
5673 */
5674 static void
5675f_win_findbuf(typval_T *argvars, typval_T *rettv)
5676{
5677 if (rettv_list_alloc(rettv) != FAIL)
5678 win_findbuf(argvars, rettv->vval.v_list);
5679}
5680
5681/*
5682 * "win_getid()" function
5683 */
5684 static void
5685f_win_getid(typval_T *argvars, typval_T *rettv)
5686{
5687 rettv->vval.v_number = win_getid(argvars);
5688}
5689
5690/*
5691 * "win_gotoid()" function
5692 */
5693 static void
5694f_win_gotoid(typval_T *argvars, typval_T *rettv)
5695{
5696 rettv->vval.v_number = win_gotoid(argvars);
5697}
5698
5699/*
5700 * "win_id2tabwin()" function
5701 */
5702 static void
5703f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5704{
5705 if (rettv_list_alloc(rettv) != FAIL)
5706 win_id2tabwin(argvars, rettv->vval.v_list);
5707}
5708
5709/*
5710 * "win_id2win()" function
5711 */
5712 static void
5713f_win_id2win(typval_T *argvars, typval_T *rettv)
5714{
5715 rettv->vval.v_number = win_id2win(argvars);
5716}
5717
5718/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005719 * "win_screenpos()" function
5720 */
5721 static void
5722f_win_screenpos(typval_T *argvars, typval_T *rettv)
5723{
5724 win_T *wp;
5725
5726 if (rettv_list_alloc(rettv) == FAIL)
5727 return;
5728
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005729 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005730 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5731 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5732}
5733
5734/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005735 * "getwinpos({timeout})" function
5736 */
5737 static void
5738f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5739{
5740 int x = -1;
5741 int y = -1;
5742
5743 if (rettv_list_alloc(rettv) == FAIL)
5744 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005745#if defined(FEAT_GUI) \
5746 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5747 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005748 {
5749 varnumber_T timeout = 100;
5750
5751 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005752 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005753
5754 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005755 }
5756#endif
5757 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5758 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5759}
5760
5761
5762/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005763 * "getwinposx()" function
5764 */
5765 static void
5766f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5767{
5768 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005769#if defined(FEAT_GUI) \
5770 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5771 || defined(MSWIN)
5772
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005773 {
5774 int x, y;
5775
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005776 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005777 rettv->vval.v_number = x;
5778 }
5779#endif
5780}
5781
5782/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 * "getwinposy()" function
5784 */
5785 static void
5786f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5787{
5788 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005789#if defined(FEAT_GUI) \
5790 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5791 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 {
5793 int x, y;
5794
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005795 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005796 rettv->vval.v_number = y;
5797 }
5798#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799}
5800
5801/*
5802 * "getwinvar()" function
5803 */
5804 static void
5805f_getwinvar(typval_T *argvars, typval_T *rettv)
5806{
5807 getwinvar(argvars, rettv, 0);
5808}
5809
5810/*
5811 * "glob()" function
5812 */
5813 static void
5814f_glob(typval_T *argvars, typval_T *rettv)
5815{
5816 int options = WILD_SILENT|WILD_USE_NL;
5817 expand_T xpc;
5818 int error = FALSE;
5819
5820 /* When the optional second argument is non-zero, don't remove matches
5821 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5822 rettv->v_type = VAR_STRING;
5823 if (argvars[1].v_type != VAR_UNKNOWN)
5824 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005825 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005826 options |= WILD_KEEP_ALL;
5827 if (argvars[2].v_type != VAR_UNKNOWN)
5828 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005829 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005830 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005831 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005832 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005833 options |= WILD_ALLLINKS;
5834 }
5835 }
5836 if (!error)
5837 {
5838 ExpandInit(&xpc);
5839 xpc.xp_context = EXPAND_FILES;
5840 if (p_wic)
5841 options += WILD_ICASE;
5842 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005843 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005844 NULL, options, WILD_ALL);
5845 else if (rettv_list_alloc(rettv) != FAIL)
5846 {
5847 int i;
5848
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005849 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850 NULL, options, WILD_ALL_KEEP);
5851 for (i = 0; i < xpc.xp_numfiles; i++)
5852 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5853
5854 ExpandCleanup(&xpc);
5855 }
5856 }
5857 else
5858 rettv->vval.v_string = NULL;
5859}
5860
5861/*
5862 * "globpath()" function
5863 */
5864 static void
5865f_globpath(typval_T *argvars, typval_T *rettv)
5866{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005867 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005869 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005870 int error = FALSE;
5871 garray_T ga;
5872 int i;
5873
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005874 // When the optional second argument is non-zero, don't remove matches
5875 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005876 rettv->v_type = VAR_STRING;
5877 if (argvars[2].v_type != VAR_UNKNOWN)
5878 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005879 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005880 flags |= WILD_KEEP_ALL;
5881 if (argvars[3].v_type != VAR_UNKNOWN)
5882 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005883 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005884 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005886 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005887 flags |= WILD_ALLLINKS;
5888 }
5889 }
5890 if (file != NULL && !error)
5891 {
5892 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005893 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005894 if (rettv->v_type == VAR_STRING)
5895 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5896 else if (rettv_list_alloc(rettv) != FAIL)
5897 for (i = 0; i < ga.ga_len; ++i)
5898 list_append_string(rettv->vval.v_list,
5899 ((char_u **)(ga.ga_data))[i], -1);
5900 ga_clear_strings(&ga);
5901 }
5902 else
5903 rettv->vval.v_string = NULL;
5904}
5905
5906/*
5907 * "glob2regpat()" function
5908 */
5909 static void
5910f_glob2regpat(typval_T *argvars, typval_T *rettv)
5911{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005912 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005913
5914 rettv->v_type = VAR_STRING;
5915 rettv->vval.v_string = (pat == NULL)
5916 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5917}
5918
5919/* for VIM_VERSION_ defines */
5920#include "version.h"
5921
5922/*
5923 * "has()" function
5924 */
5925 static void
5926f_has(typval_T *argvars, typval_T *rettv)
5927{
5928 int i;
5929 char_u *name;
5930 int n = FALSE;
5931 static char *(has_list[]) =
5932 {
5933#ifdef AMIGA
5934 "amiga",
5935# ifdef FEAT_ARP
5936 "arp",
5937# endif
5938#endif
5939#ifdef __BEOS__
5940 "beos",
5941#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005942#if defined(BSD) && !defined(MACOS_X)
5943 "bsd",
5944#endif
5945#ifdef hpux
5946 "hpux",
5947#endif
5948#ifdef __linux__
5949 "linux",
5950#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005951#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005952 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5953 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005954# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005955 "macunix", /* Mac OS X, with the darwin feature */
5956 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005957# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005958#endif
5959#ifdef __QNX__
5960 "qnx",
5961#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005962#ifdef SUN_SYSTEM
5963 "sun",
5964#else
5965 "moon",
5966#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005967#ifdef UNIX
5968 "unix",
5969#endif
5970#ifdef VMS
5971 "vms",
5972#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005973#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005974 "win32",
5975#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005976#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005977 "win32unix",
5978#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005979#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005980 "win64",
5981#endif
5982#ifdef EBCDIC
5983 "ebcdic",
5984#endif
5985#ifndef CASE_INSENSITIVE_FILENAME
5986 "fname_case",
5987#endif
5988#ifdef HAVE_ACL
5989 "acl",
5990#endif
5991#ifdef FEAT_ARABIC
5992 "arabic",
5993#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005995#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005996 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005997#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005998#ifdef FEAT_AUTOSERVERNAME
5999 "autoservername",
6000#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006001#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006002 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006003# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006004 "balloon_multiline",
6005# endif
6006#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006007#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006008 "balloon_eval_term",
6009#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006010#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6011 "builtin_terms",
6012# ifdef ALL_BUILTIN_TCAPS
6013 "all_builtin_terms",
6014# endif
6015#endif
6016#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006017 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 || defined(FEAT_GUI_MOTIF))
6019 "browsefilter",
6020#endif
6021#ifdef FEAT_BYTEOFF
6022 "byte_offset",
6023#endif
6024#ifdef FEAT_JOB_CHANNEL
6025 "channel",
6026#endif
6027#ifdef FEAT_CINDENT
6028 "cindent",
6029#endif
6030#ifdef FEAT_CLIENTSERVER
6031 "clientserver",
6032#endif
6033#ifdef FEAT_CLIPBOARD
6034 "clipboard",
6035#endif
6036#ifdef FEAT_CMDL_COMPL
6037 "cmdline_compl",
6038#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006039 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006040#ifdef FEAT_COMMENTS
6041 "comments",
6042#endif
6043#ifdef FEAT_CONCEAL
6044 "conceal",
6045#endif
6046#ifdef FEAT_CRYPT
6047 "cryptv",
6048 "crypt-blowfish",
6049 "crypt-blowfish2",
6050#endif
6051#ifdef FEAT_CSCOPE
6052 "cscope",
6053#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006054 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006055#ifdef CURSOR_SHAPE
6056 "cursorshape",
6057#endif
6058#ifdef DEBUG
6059 "debug",
6060#endif
6061#ifdef FEAT_CON_DIALOG
6062 "dialog_con",
6063#endif
6064#ifdef FEAT_GUI_DIALOG
6065 "dialog_gui",
6066#endif
6067#ifdef FEAT_DIFF
6068 "diff",
6069#endif
6070#ifdef FEAT_DIGRAPHS
6071 "digraphs",
6072#endif
6073#ifdef FEAT_DIRECTX
6074 "directx",
6075#endif
6076#ifdef FEAT_DND
6077 "dnd",
6078#endif
6079#ifdef FEAT_EMACS_TAGS
6080 "emacs_tags",
6081#endif
6082 "eval", /* always present, of course! */
6083 "ex_extra", /* graduated feature */
6084#ifdef FEAT_SEARCH_EXTRA
6085 "extra_search",
6086#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087#ifdef FEAT_SEARCHPATH
6088 "file_in_path",
6089#endif
6090#ifdef FEAT_FILTERPIPE
6091 "filterpipe",
6092#endif
6093#ifdef FEAT_FIND_ID
6094 "find_in_path",
6095#endif
6096#ifdef FEAT_FLOAT
6097 "float",
6098#endif
6099#ifdef FEAT_FOLDING
6100 "folding",
6101#endif
6102#ifdef FEAT_FOOTER
6103 "footer",
6104#endif
6105#if !defined(USE_SYSTEM) && defined(UNIX)
6106 "fork",
6107#endif
6108#ifdef FEAT_GETTEXT
6109 "gettext",
6110#endif
6111#ifdef FEAT_GUI
6112 "gui",
6113#endif
6114#ifdef FEAT_GUI_ATHENA
6115# ifdef FEAT_GUI_NEXTAW
6116 "gui_neXtaw",
6117# else
6118 "gui_athena",
6119# endif
6120#endif
6121#ifdef FEAT_GUI_GTK
6122 "gui_gtk",
6123# ifdef USE_GTK3
6124 "gui_gtk3",
6125# else
6126 "gui_gtk2",
6127# endif
6128#endif
6129#ifdef FEAT_GUI_GNOME
6130 "gui_gnome",
6131#endif
6132#ifdef FEAT_GUI_MAC
6133 "gui_mac",
6134#endif
6135#ifdef FEAT_GUI_MOTIF
6136 "gui_motif",
6137#endif
6138#ifdef FEAT_GUI_PHOTON
6139 "gui_photon",
6140#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006141#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006142 "gui_win32",
6143#endif
6144#ifdef FEAT_HANGULIN
6145 "hangul_input",
6146#endif
6147#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6148 "iconv",
6149#endif
6150#ifdef FEAT_INS_EXPAND
6151 "insert_expand",
6152#endif
6153#ifdef FEAT_JOB_CHANNEL
6154 "job",
6155#endif
6156#ifdef FEAT_JUMPLIST
6157 "jumplist",
6158#endif
6159#ifdef FEAT_KEYMAP
6160 "keymap",
6161#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006162 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006163#ifdef FEAT_LANGMAP
6164 "langmap",
6165#endif
6166#ifdef FEAT_LIBCALL
6167 "libcall",
6168#endif
6169#ifdef FEAT_LINEBREAK
6170 "linebreak",
6171#endif
6172#ifdef FEAT_LISP
6173 "lispindent",
6174#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006176 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006177#ifdef FEAT_LUA
6178# ifndef DYNAMIC_LUA
6179 "lua",
6180# endif
6181#endif
6182#ifdef FEAT_MENU
6183 "menu",
6184#endif
6185#ifdef FEAT_SESSION
6186 "mksession",
6187#endif
6188#ifdef FEAT_MODIFY_FNAME
6189 "modify_fname",
6190#endif
6191#ifdef FEAT_MOUSE
6192 "mouse",
6193#endif
6194#ifdef FEAT_MOUSESHAPE
6195 "mouseshape",
6196#endif
6197#if defined(UNIX) || defined(VMS)
6198# ifdef FEAT_MOUSE_DEC
6199 "mouse_dec",
6200# endif
6201# ifdef FEAT_MOUSE_GPM
6202 "mouse_gpm",
6203# endif
6204# ifdef FEAT_MOUSE_JSB
6205 "mouse_jsbterm",
6206# endif
6207# ifdef FEAT_MOUSE_NET
6208 "mouse_netterm",
6209# endif
6210# ifdef FEAT_MOUSE_PTERM
6211 "mouse_pterm",
6212# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006213# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006214 "mouse_sgr",
6215# endif
6216# ifdef FEAT_SYSMOUSE
6217 "mouse_sysmouse",
6218# endif
6219# ifdef FEAT_MOUSE_URXVT
6220 "mouse_urxvt",
6221# endif
6222# ifdef FEAT_MOUSE_XTERM
6223 "mouse_xterm",
6224# endif
6225#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006226 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006227#ifdef FEAT_MBYTE_IME
6228 "multi_byte_ime",
6229#endif
6230#ifdef FEAT_MULTI_LANG
6231 "multi_lang",
6232#endif
6233#ifdef FEAT_MZSCHEME
6234#ifndef DYNAMIC_MZSCHEME
6235 "mzscheme",
6236#endif
6237#endif
6238#ifdef FEAT_NUM64
6239 "num64",
6240#endif
6241#ifdef FEAT_OLE
6242 "ole",
6243#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006244#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006245 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006246#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006247#ifdef FEAT_PATH_EXTRA
6248 "path_extra",
6249#endif
6250#ifdef FEAT_PERL
6251#ifndef DYNAMIC_PERL
6252 "perl",
6253#endif
6254#endif
6255#ifdef FEAT_PERSISTENT_UNDO
6256 "persistent_undo",
6257#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006258#if defined(FEAT_PYTHON)
6259 "python_compiled",
6260# if defined(DYNAMIC_PYTHON)
6261 "python_dynamic",
6262# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006263 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006264 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006265# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006266#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006267#if defined(FEAT_PYTHON3)
6268 "python3_compiled",
6269# if defined(DYNAMIC_PYTHON3)
6270 "python3_dynamic",
6271# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006273 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006274# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006275#endif
6276#ifdef FEAT_POSTSCRIPT
6277 "postscript",
6278#endif
6279#ifdef FEAT_PRINTER
6280 "printer",
6281#endif
6282#ifdef FEAT_PROFILE
6283 "profile",
6284#endif
6285#ifdef FEAT_RELTIME
6286 "reltime",
6287#endif
6288#ifdef FEAT_QUICKFIX
6289 "quickfix",
6290#endif
6291#ifdef FEAT_RIGHTLEFT
6292 "rightleft",
6293#endif
6294#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6295 "ruby",
6296#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006298#ifdef FEAT_CMDL_INFO
6299 "showcmd",
6300 "cmdline_info",
6301#endif
6302#ifdef FEAT_SIGNS
6303 "signs",
6304#endif
6305#ifdef FEAT_SMARTINDENT
6306 "smartindent",
6307#endif
6308#ifdef STARTUPTIME
6309 "startuptime",
6310#endif
6311#ifdef FEAT_STL_OPT
6312 "statusline",
6313#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006314#ifdef FEAT_NETBEANS_INTG
6315 "netbeans_intg",
6316#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006317#ifdef FEAT_SOUND
6318 "sound",
6319#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006320#ifdef FEAT_SPELL
6321 "spell",
6322#endif
6323#ifdef FEAT_SYN_HL
6324 "syntax",
6325#endif
6326#if defined(USE_SYSTEM) || !defined(UNIX)
6327 "system",
6328#endif
6329#ifdef FEAT_TAG_BINS
6330 "tag_binary",
6331#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006332#ifdef FEAT_TCL
6333# ifndef DYNAMIC_TCL
6334 "tcl",
6335# endif
6336#endif
6337#ifdef FEAT_TERMGUICOLORS
6338 "termguicolors",
6339#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006340#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006341 "terminal",
6342#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343#ifdef TERMINFO
6344 "terminfo",
6345#endif
6346#ifdef FEAT_TERMRESPONSE
6347 "termresponse",
6348#endif
6349#ifdef FEAT_TEXTOBJ
6350 "textobjects",
6351#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006352#ifdef FEAT_TEXT_PROP
6353 "textprop",
6354#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355#ifdef HAVE_TGETENT
6356 "tgetent",
6357#endif
6358#ifdef FEAT_TIMERS
6359 "timers",
6360#endif
6361#ifdef FEAT_TITLE
6362 "title",
6363#endif
6364#ifdef FEAT_TOOLBAR
6365 "toolbar",
6366#endif
6367#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6368 "unnamedplus",
6369#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006370 "user-commands", /* was accidentally included in 5.4 */
6371 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006372#ifdef FEAT_VARTABS
6373 "vartabs",
6374#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006375 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376#ifdef FEAT_VIMINFO
6377 "viminfo",
6378#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006379 "vimscript-1",
6380 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006381 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006382 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006383 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006384 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006386#ifdef FEAT_VTP
6387 "vtp",
6388#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006389#ifdef FEAT_WILDIGN
6390 "wildignore",
6391#endif
6392#ifdef FEAT_WILDMENU
6393 "wildmenu",
6394#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006395 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396#ifdef FEAT_WAK
6397 "winaltkeys",
6398#endif
6399#ifdef FEAT_WRITEBACKUP
6400 "writebackup",
6401#endif
6402#ifdef FEAT_XIM
6403 "xim",
6404#endif
6405#ifdef FEAT_XFONTSET
6406 "xfontset",
6407#endif
6408#ifdef FEAT_XPM_W32
6409 "xpm",
6410 "xpm_w32", /* for backward compatibility */
6411#else
6412# if defined(HAVE_XPM)
6413 "xpm",
6414# endif
6415#endif
6416#ifdef USE_XSMP
6417 "xsmp",
6418#endif
6419#ifdef USE_XSMP_INTERACT
6420 "xsmp_interact",
6421#endif
6422#ifdef FEAT_XCLIPBOARD
6423 "xterm_clipboard",
6424#endif
6425#ifdef FEAT_XTERM_SAVE
6426 "xterm_save",
6427#endif
6428#if defined(UNIX) && defined(FEAT_X11)
6429 "X11",
6430#endif
6431 NULL
6432 };
6433
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006434 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006435 for (i = 0; has_list[i] != NULL; ++i)
6436 if (STRICMP(name, has_list[i]) == 0)
6437 {
6438 n = TRUE;
6439 break;
6440 }
6441
6442 if (n == FALSE)
6443 {
6444 if (STRNICMP(name, "patch", 5) == 0)
6445 {
6446 if (name[5] == '-'
6447 && STRLEN(name) >= 11
6448 && vim_isdigit(name[6])
6449 && vim_isdigit(name[8])
6450 && vim_isdigit(name[10]))
6451 {
6452 int major = atoi((char *)name + 6);
6453 int minor = atoi((char *)name + 8);
6454
6455 /* Expect "patch-9.9.01234". */
6456 n = (major < VIM_VERSION_MAJOR
6457 || (major == VIM_VERSION_MAJOR
6458 && (minor < VIM_VERSION_MINOR
6459 || (minor == VIM_VERSION_MINOR
6460 && has_patch(atoi((char *)name + 10))))));
6461 }
6462 else
6463 n = has_patch(atoi((char *)name + 5));
6464 }
6465 else if (STRICMP(name, "vim_starting") == 0)
6466 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006467 else if (STRICMP(name, "ttyin") == 0)
6468 n = mch_input_isatty();
6469 else if (STRICMP(name, "ttyout") == 0)
6470 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006471 else if (STRICMP(name, "multi_byte_encoding") == 0)
6472 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006473#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 else if (STRICMP(name, "balloon_multiline") == 0)
6475 n = multiline_balloon_available();
6476#endif
6477#ifdef DYNAMIC_TCL
6478 else if (STRICMP(name, "tcl") == 0)
6479 n = tcl_enabled(FALSE);
6480#endif
6481#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6482 else if (STRICMP(name, "iconv") == 0)
6483 n = iconv_enabled(FALSE);
6484#endif
6485#ifdef DYNAMIC_LUA
6486 else if (STRICMP(name, "lua") == 0)
6487 n = lua_enabled(FALSE);
6488#endif
6489#ifdef DYNAMIC_MZSCHEME
6490 else if (STRICMP(name, "mzscheme") == 0)
6491 n = mzscheme_enabled(FALSE);
6492#endif
6493#ifdef DYNAMIC_RUBY
6494 else if (STRICMP(name, "ruby") == 0)
6495 n = ruby_enabled(FALSE);
6496#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006497#ifdef DYNAMIC_PYTHON
6498 else if (STRICMP(name, "python") == 0)
6499 n = python_enabled(FALSE);
6500#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501#ifdef DYNAMIC_PYTHON3
6502 else if (STRICMP(name, "python3") == 0)
6503 n = python3_enabled(FALSE);
6504#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006505#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6506 else if (STRICMP(name, "pythonx") == 0)
6507 {
6508# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6509 if (p_pyx == 0)
6510 n = python3_enabled(FALSE) || python_enabled(FALSE);
6511 else if (p_pyx == 3)
6512 n = python3_enabled(FALSE);
6513 else if (p_pyx == 2)
6514 n = python_enabled(FALSE);
6515# elif defined(DYNAMIC_PYTHON)
6516 n = python_enabled(FALSE);
6517# elif defined(DYNAMIC_PYTHON3)
6518 n = python3_enabled(FALSE);
6519# endif
6520 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006521#endif
6522#ifdef DYNAMIC_PERL
6523 else if (STRICMP(name, "perl") == 0)
6524 n = perl_enabled(FALSE);
6525#endif
6526#ifdef FEAT_GUI
6527 else if (STRICMP(name, "gui_running") == 0)
6528 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006529# ifdef FEAT_BROWSE
6530 else if (STRICMP(name, "browse") == 0)
6531 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6532# endif
6533#endif
6534#ifdef FEAT_SYN_HL
6535 else if (STRICMP(name, "syntax_items") == 0)
6536 n = syntax_present(curwin);
6537#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006538#ifdef FEAT_VTP
6539 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006540 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541#endif
6542#ifdef FEAT_NETBEANS_INTG
6543 else if (STRICMP(name, "netbeans_enabled") == 0)
6544 n = netbeans_active();
6545#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006546#ifdef FEAT_MOUSE_GPM
6547 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6548 n = gpm_enabled();
6549#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006550#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006551 else if (STRICMP(name, "terminal") == 0)
6552 n = terminal_enabled();
6553#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006554#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006555 else if (STRICMP(name, "conpty") == 0)
6556 n = use_conpty();
6557#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006558#ifdef FEAT_CLIPBOARD
6559 else if (STRICMP(name, "clipboard_working") == 0)
6560 n = clip_star.available;
6561#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562 }
6563
6564 rettv->vval.v_number = n;
6565}
6566
6567/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568 * "haslocaldir()" function
6569 */
6570 static void
6571f_haslocaldir(typval_T *argvars, typval_T *rettv)
6572{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006573 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574 win_T *wp = NULL;
6575
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006576 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6577
6578 // Check for window-local and tab-local directories
6579 if (wp != NULL && wp->w_localdir != NULL)
6580 rettv->vval.v_number = 1;
6581 else if (tp != NULL && tp->tp_localdir != NULL)
6582 rettv->vval.v_number = 2;
6583 else
6584 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006585}
6586
6587/*
6588 * "hasmapto()" function
6589 */
6590 static void
6591f_hasmapto(typval_T *argvars, typval_T *rettv)
6592{
6593 char_u *name;
6594 char_u *mode;
6595 char_u buf[NUMBUFLEN];
6596 int abbr = FALSE;
6597
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006598 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599 if (argvars[1].v_type == VAR_UNKNOWN)
6600 mode = (char_u *)"nvo";
6601 else
6602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006603 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006604 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006605 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006606 }
6607
6608 if (map_to_exists(name, mode, abbr))
6609 rettv->vval.v_number = TRUE;
6610 else
6611 rettv->vval.v_number = FALSE;
6612}
6613
6614/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006615 * "highlightID(name)" function
6616 */
6617 static void
6618f_hlID(typval_T *argvars, typval_T *rettv)
6619{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006620 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006621}
6622
6623/*
6624 * "highlight_exists()" function
6625 */
6626 static void
6627f_hlexists(typval_T *argvars, typval_T *rettv)
6628{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006629 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006630}
6631
6632/*
6633 * "hostname()" function
6634 */
6635 static void
6636f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6637{
6638 char_u hostname[256];
6639
6640 mch_get_host_name(hostname, 256);
6641 rettv->v_type = VAR_STRING;
6642 rettv->vval.v_string = vim_strsave(hostname);
6643}
6644
6645/*
6646 * iconv() function
6647 */
6648 static void
6649f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6650{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651 char_u buf1[NUMBUFLEN];
6652 char_u buf2[NUMBUFLEN];
6653 char_u *from, *to, *str;
6654 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006655
6656 rettv->v_type = VAR_STRING;
6657 rettv->vval.v_string = NULL;
6658
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006659 str = tv_get_string(&argvars[0]);
6660 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6661 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006662 vimconv.vc_type = CONV_NONE;
6663 convert_setup(&vimconv, from, to);
6664
6665 /* If the encodings are equal, no conversion needed. */
6666 if (vimconv.vc_type == CONV_NONE)
6667 rettv->vval.v_string = vim_strsave(str);
6668 else
6669 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6670
6671 convert_setup(&vimconv, NULL, NULL);
6672 vim_free(from);
6673 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006674}
6675
6676/*
6677 * "indent()" function
6678 */
6679 static void
6680f_indent(typval_T *argvars, typval_T *rettv)
6681{
6682 linenr_T lnum;
6683
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006684 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6686 rettv->vval.v_number = get_indent_lnum(lnum);
6687 else
6688 rettv->vval.v_number = -1;
6689}
6690
6691/*
6692 * "index()" function
6693 */
6694 static void
6695f_index(typval_T *argvars, typval_T *rettv)
6696{
6697 list_T *l;
6698 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006699 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700 long idx = 0;
6701 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006702 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006703
6704 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006705 if (argvars[0].v_type == VAR_BLOB)
6706 {
6707 typval_T tv;
6708 int start = 0;
6709
6710 if (argvars[2].v_type != VAR_UNKNOWN)
6711 {
6712 start = tv_get_number_chk(&argvars[2], &error);
6713 if (error)
6714 return;
6715 }
6716 b = argvars[0].vval.v_blob;
6717 if (b == NULL)
6718 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006719 if (start < 0)
6720 {
6721 start = blob_len(b) + start;
6722 if (start < 0)
6723 start = 0;
6724 }
6725
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006726 for (idx = start; idx < blob_len(b); ++idx)
6727 {
6728 tv.v_type = VAR_NUMBER;
6729 tv.vval.v_number = blob_get(b, idx);
6730 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6731 {
6732 rettv->vval.v_number = idx;
6733 return;
6734 }
6735 }
6736 return;
6737 }
6738 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006740 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741 return;
6742 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006743
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006744 l = argvars[0].vval.v_list;
6745 if (l != NULL)
6746 {
6747 item = l->lv_first;
6748 if (argvars[2].v_type != VAR_UNKNOWN)
6749 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006750 /* Start at specified item. Use the cached index that list_find()
6751 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006752 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006753 idx = l->lv_idx;
6754 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006755 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006756 if (error)
6757 item = NULL;
6758 }
6759
6760 for ( ; item != NULL; item = item->li_next, ++idx)
6761 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6762 {
6763 rettv->vval.v_number = idx;
6764 break;
6765 }
6766 }
6767}
6768
6769static int inputsecret_flag = 0;
6770
6771/*
6772 * "input()" function
6773 * Also handles inputsecret() when inputsecret is set.
6774 */
6775 static void
6776f_input(typval_T *argvars, typval_T *rettv)
6777{
6778 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6779}
6780
6781/*
6782 * "inputdialog()" function
6783 */
6784 static void
6785f_inputdialog(typval_T *argvars, typval_T *rettv)
6786{
6787#if defined(FEAT_GUI_TEXTDIALOG)
6788 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6789 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6790 {
6791 char_u *message;
6792 char_u buf[NUMBUFLEN];
6793 char_u *defstr = (char_u *)"";
6794
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006795 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006797 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006798 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6799 else
6800 IObuff[0] = NUL;
6801 if (message != NULL && defstr != NULL
6802 && do_dialog(VIM_QUESTION, NULL, message,
6803 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6804 rettv->vval.v_string = vim_strsave(IObuff);
6805 else
6806 {
6807 if (message != NULL && defstr != NULL
6808 && argvars[1].v_type != VAR_UNKNOWN
6809 && argvars[2].v_type != VAR_UNKNOWN)
6810 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006811 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812 else
6813 rettv->vval.v_string = NULL;
6814 }
6815 rettv->v_type = VAR_STRING;
6816 }
6817 else
6818#endif
6819 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6820}
6821
6822/*
6823 * "inputlist()" function
6824 */
6825 static void
6826f_inputlist(typval_T *argvars, typval_T *rettv)
6827{
6828 listitem_T *li;
6829 int selected;
6830 int mouse_used;
6831
6832#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006833 /* While starting up, there is no place to enter text. When running tests
6834 * with --not-a-term we assume feedkeys() will be used. */
6835 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836 return;
6837#endif
6838 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6839 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006840 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006841 return;
6842 }
6843
6844 msg_start();
6845 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6846 lines_left = Rows; /* avoid more prompt */
6847 msg_scroll = TRUE;
6848 msg_clr_eos();
6849
6850 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6851 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006852 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006853 msg_putchar('\n');
6854 }
6855
6856 /* Ask for choice. */
6857 selected = prompt_for_number(&mouse_used);
6858 if (mouse_used)
6859 selected -= lines_left;
6860
6861 rettv->vval.v_number = selected;
6862}
6863
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006864static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6865
6866/*
6867 * "inputrestore()" function
6868 */
6869 static void
6870f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6871{
6872 if (ga_userinput.ga_len > 0)
6873 {
6874 --ga_userinput.ga_len;
6875 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6876 + ga_userinput.ga_len);
6877 /* default return is zero == OK */
6878 }
6879 else if (p_verbose > 1)
6880 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006881 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882 rettv->vval.v_number = 1; /* Failed */
6883 }
6884}
6885
6886/*
6887 * "inputsave()" function
6888 */
6889 static void
6890f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6891{
6892 /* Add an entry to the stack of typeahead storage. */
6893 if (ga_grow(&ga_userinput, 1) == OK)
6894 {
6895 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6896 + ga_userinput.ga_len);
6897 ++ga_userinput.ga_len;
6898 /* default return is zero == OK */
6899 }
6900 else
6901 rettv->vval.v_number = 1; /* Failed */
6902}
6903
6904/*
6905 * "inputsecret()" function
6906 */
6907 static void
6908f_inputsecret(typval_T *argvars, typval_T *rettv)
6909{
6910 ++cmdline_star;
6911 ++inputsecret_flag;
6912 f_input(argvars, rettv);
6913 --cmdline_star;
6914 --inputsecret_flag;
6915}
6916
6917/*
6918 * "insert()" function
6919 */
6920 static void
6921f_insert(typval_T *argvars, typval_T *rettv)
6922{
6923 long before = 0;
6924 listitem_T *item;
6925 list_T *l;
6926 int error = FALSE;
6927
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006928 if (argvars[0].v_type == VAR_BLOB)
6929 {
6930 int val, len;
6931 char_u *p;
6932
6933 len = blob_len(argvars[0].vval.v_blob);
6934 if (argvars[2].v_type != VAR_UNKNOWN)
6935 {
6936 before = (long)tv_get_number_chk(&argvars[2], &error);
6937 if (error)
6938 return; // type error; errmsg already given
6939 if (before < 0 || before > len)
6940 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006941 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006942 return;
6943 }
6944 }
6945 val = tv_get_number_chk(&argvars[1], &error);
6946 if (error)
6947 return;
6948 if (val < 0 || val > 255)
6949 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006950 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006951 return;
6952 }
6953
6954 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6955 return;
6956 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6957 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6958 *(p + before) = val;
6959 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6960
6961 copy_tv(&argvars[0], rettv);
6962 }
6963 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006964 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006965 else if ((l = argvars[0].vval.v_list) != NULL
6966 && !var_check_lock(l->lv_lock,
6967 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006968 {
6969 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006970 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006971 if (error)
6972 return; /* type error; errmsg already given */
6973
6974 if (before == l->lv_len)
6975 item = NULL;
6976 else
6977 {
6978 item = list_find(l, before);
6979 if (item == NULL)
6980 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006981 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982 l = NULL;
6983 }
6984 }
6985 if (l != NULL)
6986 {
6987 list_insert_tv(l, &argvars[1], item);
6988 copy_tv(&argvars[0], rettv);
6989 }
6990 }
6991}
6992
6993/*
6994 * "invert(expr)" function
6995 */
6996 static void
6997f_invert(typval_T *argvars, typval_T *rettv)
6998{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006999 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007000}
7001
7002/*
7003 * "isdirectory()" function
7004 */
7005 static void
7006f_isdirectory(typval_T *argvars, typval_T *rettv)
7007{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007008 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007009}
7010
7011/*
7012 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7013 * or it refers to a List or Dictionary that is locked.
7014 */
7015 static int
7016tv_islocked(typval_T *tv)
7017{
7018 return (tv->v_lock & VAR_LOCKED)
7019 || (tv->v_type == VAR_LIST
7020 && tv->vval.v_list != NULL
7021 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7022 || (tv->v_type == VAR_DICT
7023 && tv->vval.v_dict != NULL
7024 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7025}
7026
7027/*
7028 * "islocked()" function
7029 */
7030 static void
7031f_islocked(typval_T *argvars, typval_T *rettv)
7032{
7033 lval_T lv;
7034 char_u *end;
7035 dictitem_T *di;
7036
7037 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007038 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007039 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007040 if (end != NULL && lv.ll_name != NULL)
7041 {
7042 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007043 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007044 else
7045 {
7046 if (lv.ll_tv == NULL)
7047 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007048 di = find_var(lv.ll_name, NULL, TRUE);
7049 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007050 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007051 /* Consider a variable locked when:
7052 * 1. the variable itself is locked
7053 * 2. the value of the variable is locked.
7054 * 3. the List or Dict value is locked.
7055 */
7056 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7057 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007058 }
7059 }
7060 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007061 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007063 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007064 else if (lv.ll_list != NULL)
7065 /* List item. */
7066 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7067 else
7068 /* Dictionary item. */
7069 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7070 }
7071 }
7072
7073 clear_lval(&lv);
7074}
7075
7076#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7077/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007078 * "isinf()" function
7079 */
7080 static void
7081f_isinf(typval_T *argvars, typval_T *rettv)
7082{
7083 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7084 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7085}
7086
7087/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007088 * "isnan()" function
7089 */
7090 static void
7091f_isnan(typval_T *argvars, typval_T *rettv)
7092{
7093 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7094 && isnan(argvars[0].vval.v_float);
7095}
7096#endif
7097
7098/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007099 * "last_buffer_nr()" function.
7100 */
7101 static void
7102f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7103{
7104 int n = 0;
7105 buf_T *buf;
7106
Bram Moolenaar29323592016-07-24 22:04:11 +02007107 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108 if (n < buf->b_fnum)
7109 n = buf->b_fnum;
7110
7111 rettv->vval.v_number = n;
7112}
7113
7114/*
7115 * "len()" function
7116 */
7117 static void
7118f_len(typval_T *argvars, typval_T *rettv)
7119{
7120 switch (argvars[0].v_type)
7121 {
7122 case VAR_STRING:
7123 case VAR_NUMBER:
7124 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007125 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007126 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007127 case VAR_BLOB:
7128 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7129 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007130 case VAR_LIST:
7131 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7132 break;
7133 case VAR_DICT:
7134 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7135 break;
7136 case VAR_UNKNOWN:
7137 case VAR_SPECIAL:
7138 case VAR_FLOAT:
7139 case VAR_FUNC:
7140 case VAR_PARTIAL:
7141 case VAR_JOB:
7142 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007143 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007144 break;
7145 }
7146}
7147
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007149libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150{
7151#ifdef FEAT_LIBCALL
7152 char_u *string_in;
7153 char_u **string_result;
7154 int nr_result;
7155#endif
7156
7157 rettv->v_type = type;
7158 if (type != VAR_NUMBER)
7159 rettv->vval.v_string = NULL;
7160
7161 if (check_restricted() || check_secure())
7162 return;
7163
7164#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007165 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007166 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7167 {
7168 string_in = NULL;
7169 if (argvars[2].v_type == VAR_STRING)
7170 string_in = argvars[2].vval.v_string;
7171 if (type == VAR_NUMBER)
7172 string_result = NULL;
7173 else
7174 string_result = &rettv->vval.v_string;
7175 if (mch_libcall(argvars[0].vval.v_string,
7176 argvars[1].vval.v_string,
7177 string_in,
7178 argvars[2].vval.v_number,
7179 string_result,
7180 &nr_result) == OK
7181 && type == VAR_NUMBER)
7182 rettv->vval.v_number = nr_result;
7183 }
7184#endif
7185}
7186
7187/*
7188 * "libcall()" function
7189 */
7190 static void
7191f_libcall(typval_T *argvars, typval_T *rettv)
7192{
7193 libcall_common(argvars, rettv, VAR_STRING);
7194}
7195
7196/*
7197 * "libcallnr()" function
7198 */
7199 static void
7200f_libcallnr(typval_T *argvars, typval_T *rettv)
7201{
7202 libcall_common(argvars, rettv, VAR_NUMBER);
7203}
7204
7205/*
7206 * "line(string)" function
7207 */
7208 static void
7209f_line(typval_T *argvars, typval_T *rettv)
7210{
7211 linenr_T lnum = 0;
7212 pos_T *fp;
7213 int fnum;
7214
7215 fp = var2fpos(&argvars[0], TRUE, &fnum);
7216 if (fp != NULL)
7217 lnum = fp->lnum;
7218 rettv->vval.v_number = lnum;
7219}
7220
7221/*
7222 * "line2byte(lnum)" function
7223 */
7224 static void
7225f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7226{
7227#ifndef FEAT_BYTEOFF
7228 rettv->vval.v_number = -1;
7229#else
7230 linenr_T lnum;
7231
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007232 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7234 rettv->vval.v_number = -1;
7235 else
7236 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7237 if (rettv->vval.v_number >= 0)
7238 ++rettv->vval.v_number;
7239#endif
7240}
7241
7242/*
7243 * "lispindent(lnum)" function
7244 */
7245 static void
7246f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7247{
7248#ifdef FEAT_LISP
7249 pos_T pos;
7250 linenr_T lnum;
7251
7252 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007253 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7255 {
7256 curwin->w_cursor.lnum = lnum;
7257 rettv->vval.v_number = get_lisp_indent();
7258 curwin->w_cursor = pos;
7259 }
7260 else
7261#endif
7262 rettv->vval.v_number = -1;
7263}
7264
7265/*
7266 * "localtime()" function
7267 */
7268 static void
7269f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7270{
7271 rettv->vval.v_number = (varnumber_T)time(NULL);
7272}
7273
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274#ifdef FEAT_FLOAT
7275/*
7276 * "log()" function
7277 */
7278 static void
7279f_log(typval_T *argvars, typval_T *rettv)
7280{
7281 float_T f = 0.0;
7282
7283 rettv->v_type = VAR_FLOAT;
7284 if (get_float_arg(argvars, &f) == OK)
7285 rettv->vval.v_float = log(f);
7286 else
7287 rettv->vval.v_float = 0.0;
7288}
7289
7290/*
7291 * "log10()" function
7292 */
7293 static void
7294f_log10(typval_T *argvars, typval_T *rettv)
7295{
7296 float_T f = 0.0;
7297
7298 rettv->v_type = VAR_FLOAT;
7299 if (get_float_arg(argvars, &f) == OK)
7300 rettv->vval.v_float = log10(f);
7301 else
7302 rettv->vval.v_float = 0.0;
7303}
7304#endif
7305
7306#ifdef FEAT_LUA
7307/*
7308 * "luaeval()" function
7309 */
7310 static void
7311f_luaeval(typval_T *argvars, typval_T *rettv)
7312{
7313 char_u *str;
7314 char_u buf[NUMBUFLEN];
7315
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007316 if (check_restricted() || check_secure())
7317 return;
7318
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007319 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007320 do_luaeval(str, argvars + 1, rettv);
7321}
7322#endif
7323
7324/*
7325 * "map()" function
7326 */
7327 static void
7328f_map(typval_T *argvars, typval_T *rettv)
7329{
7330 filter_map(argvars, rettv, TRUE);
7331}
7332
7333/*
7334 * "maparg()" function
7335 */
7336 static void
7337f_maparg(typval_T *argvars, typval_T *rettv)
7338{
7339 get_maparg(argvars, rettv, TRUE);
7340}
7341
7342/*
7343 * "mapcheck()" function
7344 */
7345 static void
7346f_mapcheck(typval_T *argvars, typval_T *rettv)
7347{
7348 get_maparg(argvars, rettv, FALSE);
7349}
7350
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007351typedef enum
7352{
7353 MATCH_END, /* matchend() */
7354 MATCH_MATCH, /* match() */
7355 MATCH_STR, /* matchstr() */
7356 MATCH_LIST, /* matchlist() */
7357 MATCH_POS /* matchstrpos() */
7358} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007359
7360 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007361find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362{
7363 char_u *str = NULL;
7364 long len = 0;
7365 char_u *expr = NULL;
7366 char_u *pat;
7367 regmatch_T regmatch;
7368 char_u patbuf[NUMBUFLEN];
7369 char_u strbuf[NUMBUFLEN];
7370 char_u *save_cpo;
7371 long start = 0;
7372 long nth = 1;
7373 colnr_T startcol = 0;
7374 int match = 0;
7375 list_T *l = NULL;
7376 listitem_T *li = NULL;
7377 long idx = 0;
7378 char_u *tofree = NULL;
7379
7380 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7381 save_cpo = p_cpo;
7382 p_cpo = (char_u *)"";
7383
7384 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007385 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007387 /* type MATCH_LIST: return empty list when there are no matches.
7388 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389 if (rettv_list_alloc(rettv) == FAIL)
7390 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007391 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 && (list_append_string(rettv->vval.v_list,
7393 (char_u *)"", 0) == 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 || list_append_number(rettv->vval.v_list,
7399 (varnumber_T)-1) == FAIL))
7400 {
7401 list_free(rettv->vval.v_list);
7402 rettv->vval.v_list = NULL;
7403 goto theend;
7404 }
7405 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007406 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 {
7408 rettv->v_type = VAR_STRING;
7409 rettv->vval.v_string = NULL;
7410 }
7411
7412 if (argvars[0].v_type == VAR_LIST)
7413 {
7414 if ((l = argvars[0].vval.v_list) == NULL)
7415 goto theend;
7416 li = l->lv_first;
7417 }
7418 else
7419 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007420 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007421 len = (long)STRLEN(str);
7422 }
7423
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007424 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007425 if (pat == NULL)
7426 goto theend;
7427
7428 if (argvars[2].v_type != VAR_UNKNOWN)
7429 {
7430 int error = FALSE;
7431
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007432 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433 if (error)
7434 goto theend;
7435 if (l != NULL)
7436 {
7437 li = list_find(l, start);
7438 if (li == NULL)
7439 goto theend;
7440 idx = l->lv_idx; /* use the cached index */
7441 }
7442 else
7443 {
7444 if (start < 0)
7445 start = 0;
7446 if (start > len)
7447 goto theend;
7448 /* When "count" argument is there ignore matches before "start",
7449 * otherwise skip part of the string. Differs when pattern is "^"
7450 * or "\<". */
7451 if (argvars[3].v_type != VAR_UNKNOWN)
7452 startcol = start;
7453 else
7454 {
7455 str += start;
7456 len -= start;
7457 }
7458 }
7459
7460 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007461 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007462 if (error)
7463 goto theend;
7464 }
7465
7466 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7467 if (regmatch.regprog != NULL)
7468 {
7469 regmatch.rm_ic = p_ic;
7470
7471 for (;;)
7472 {
7473 if (l != NULL)
7474 {
7475 if (li == NULL)
7476 {
7477 match = FALSE;
7478 break;
7479 }
7480 vim_free(tofree);
7481 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7482 if (str == NULL)
7483 break;
7484 }
7485
7486 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7487
7488 if (match && --nth <= 0)
7489 break;
7490 if (l == NULL && !match)
7491 break;
7492
7493 /* Advance to just after the match. */
7494 if (l != NULL)
7495 {
7496 li = li->li_next;
7497 ++idx;
7498 }
7499 else
7500 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501 startcol = (colnr_T)(regmatch.startp[0]
7502 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503 if (startcol > (colnr_T)len
7504 || str + startcol <= regmatch.startp[0])
7505 {
7506 match = FALSE;
7507 break;
7508 }
7509 }
7510 }
7511
7512 if (match)
7513 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007514 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 {
7516 listitem_T *li1 = rettv->vval.v_list->lv_first;
7517 listitem_T *li2 = li1->li_next;
7518 listitem_T *li3 = li2->li_next;
7519 listitem_T *li4 = li3->li_next;
7520
7521 vim_free(li1->li_tv.vval.v_string);
7522 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7523 (int)(regmatch.endp[0] - regmatch.startp[0]));
7524 li3->li_tv.vval.v_number =
7525 (varnumber_T)(regmatch.startp[0] - expr);
7526 li4->li_tv.vval.v_number =
7527 (varnumber_T)(regmatch.endp[0] - expr);
7528 if (l != NULL)
7529 li2->li_tv.vval.v_number = (varnumber_T)idx;
7530 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007531 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 {
7533 int i;
7534
7535 /* return list with matched string and submatches */
7536 for (i = 0; i < NSUBEXP; ++i)
7537 {
7538 if (regmatch.endp[i] == NULL)
7539 {
7540 if (list_append_string(rettv->vval.v_list,
7541 (char_u *)"", 0) == FAIL)
7542 break;
7543 }
7544 else if (list_append_string(rettv->vval.v_list,
7545 regmatch.startp[i],
7546 (int)(regmatch.endp[i] - regmatch.startp[i]))
7547 == FAIL)
7548 break;
7549 }
7550 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007551 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552 {
7553 /* return matched string */
7554 if (l != NULL)
7555 copy_tv(&li->li_tv, rettv);
7556 else
7557 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7558 (int)(regmatch.endp[0] - regmatch.startp[0]));
7559 }
7560 else if (l != NULL)
7561 rettv->vval.v_number = idx;
7562 else
7563 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007564 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007565 rettv->vval.v_number =
7566 (varnumber_T)(regmatch.startp[0] - str);
7567 else
7568 rettv->vval.v_number =
7569 (varnumber_T)(regmatch.endp[0] - str);
7570 rettv->vval.v_number += (varnumber_T)(str - expr);
7571 }
7572 }
7573 vim_regfree(regmatch.regprog);
7574 }
7575
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007576theend:
7577 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007578 /* matchstrpos() without a list: drop the second item. */
7579 listitem_remove(rettv->vval.v_list,
7580 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581 vim_free(tofree);
7582 p_cpo = save_cpo;
7583}
7584
7585/*
7586 * "match()" function
7587 */
7588 static void
7589f_match(typval_T *argvars, typval_T *rettv)
7590{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007591 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007592}
7593
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007594/*
7595 * "matchend()" function
7596 */
7597 static void
7598f_matchend(typval_T *argvars, typval_T *rettv)
7599{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007600 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007601}
7602
7603/*
7604 * "matchlist()" function
7605 */
7606 static void
7607f_matchlist(typval_T *argvars, typval_T *rettv)
7608{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007609 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610}
7611
7612/*
7613 * "matchstr()" function
7614 */
7615 static void
7616f_matchstr(typval_T *argvars, typval_T *rettv)
7617{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007618 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619}
7620
7621/*
7622 * "matchstrpos()" function
7623 */
7624 static void
7625f_matchstrpos(typval_T *argvars, typval_T *rettv)
7626{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007627 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007628}
7629
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630 static void
7631max_min(typval_T *argvars, typval_T *rettv, int domax)
7632{
7633 varnumber_T n = 0;
7634 varnumber_T i;
7635 int error = FALSE;
7636
7637 if (argvars[0].v_type == VAR_LIST)
7638 {
7639 list_T *l;
7640 listitem_T *li;
7641
7642 l = argvars[0].vval.v_list;
7643 if (l != NULL)
7644 {
7645 li = l->lv_first;
7646 if (li != NULL)
7647 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007648 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649 for (;;)
7650 {
7651 li = li->li_next;
7652 if (li == NULL)
7653 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007654 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655 if (domax ? i > n : i < n)
7656 n = i;
7657 }
7658 }
7659 }
7660 }
7661 else if (argvars[0].v_type == VAR_DICT)
7662 {
7663 dict_T *d;
7664 int first = TRUE;
7665 hashitem_T *hi;
7666 int todo;
7667
7668 d = argvars[0].vval.v_dict;
7669 if (d != NULL)
7670 {
7671 todo = (int)d->dv_hashtab.ht_used;
7672 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7673 {
7674 if (!HASHITEM_EMPTY(hi))
7675 {
7676 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007677 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678 if (first)
7679 {
7680 n = i;
7681 first = FALSE;
7682 }
7683 else if (domax ? i > n : i < n)
7684 n = i;
7685 }
7686 }
7687 }
7688 }
7689 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007690 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007691 rettv->vval.v_number = error ? 0 : n;
7692}
7693
7694/*
7695 * "max()" function
7696 */
7697 static void
7698f_max(typval_T *argvars, typval_T *rettv)
7699{
7700 max_min(argvars, rettv, TRUE);
7701}
7702
7703/*
7704 * "min()" function
7705 */
7706 static void
7707f_min(typval_T *argvars, typval_T *rettv)
7708{
7709 max_min(argvars, rettv, FALSE);
7710}
7711
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007712/*
7713 * Create the directory in which "dir" is located, and higher levels when
7714 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007715 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716 */
7717 static int
7718mkdir_recurse(char_u *dir, int prot)
7719{
7720 char_u *p;
7721 char_u *updir;
7722 int r = FAIL;
7723
7724 /* Get end of directory name in "dir".
7725 * We're done when it's "/" or "c:/". */
7726 p = gettail_sep(dir);
7727 if (p <= get_past_head(dir))
7728 return OK;
7729
7730 /* If the directory exists we're done. Otherwise: create it.*/
7731 updir = vim_strnsave(dir, (int)(p - dir));
7732 if (updir == NULL)
7733 return FAIL;
7734 if (mch_isdir(updir))
7735 r = OK;
7736 else if (mkdir_recurse(updir, prot) == OK)
7737 r = vim_mkdir_emsg(updir, prot);
7738 vim_free(updir);
7739 return r;
7740}
7741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007742/*
7743 * "mkdir()" function
7744 */
7745 static void
7746f_mkdir(typval_T *argvars, typval_T *rettv)
7747{
7748 char_u *dir;
7749 char_u buf[NUMBUFLEN];
7750 int prot = 0755;
7751
7752 rettv->vval.v_number = FAIL;
7753 if (check_restricted() || check_secure())
7754 return;
7755
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007756 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007757 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007758 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007760 if (*gettail(dir) == NUL)
7761 /* remove trailing slashes */
7762 *gettail_sep(dir) = NUL;
7763
7764 if (argvars[1].v_type != VAR_UNKNOWN)
7765 {
7766 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007768 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007769 if (prot == -1)
7770 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007771 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007772 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007773 {
7774 if (mch_isdir(dir))
7775 {
7776 /* With the "p" flag it's OK if the dir already exists. */
7777 rettv->vval.v_number = OK;
7778 return;
7779 }
7780 mkdir_recurse(dir, prot);
7781 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007782 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007783 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007784}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007785
7786/*
7787 * "mode()" function
7788 */
7789 static void
7790f_mode(typval_T *argvars, typval_T *rettv)
7791{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007792 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007793
Bram Moolenaar612cc382018-07-29 15:34:26 +02007794 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795
7796 if (time_for_testing == 93784)
7797 {
7798 /* Testing the two-character code. */
7799 buf[0] = 'x';
7800 buf[1] = '!';
7801 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007802#ifdef FEAT_TERMINAL
7803 else if (term_use_loop())
7804 buf[0] = 't';
7805#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007806 else if (VIsual_active)
7807 {
7808 if (VIsual_select)
7809 buf[0] = VIsual_mode + 's' - 'v';
7810 else
7811 buf[0] = VIsual_mode;
7812 }
7813 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7814 || State == CONFIRM)
7815 {
7816 buf[0] = 'r';
7817 if (State == ASKMORE)
7818 buf[1] = 'm';
7819 else if (State == CONFIRM)
7820 buf[1] = '?';
7821 }
7822 else if (State == EXTERNCMD)
7823 buf[0] = '!';
7824 else if (State & INSERT)
7825 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 if (State & VREPLACE_FLAG)
7827 {
7828 buf[0] = 'R';
7829 buf[1] = 'v';
7830 }
7831 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007832 {
7833 if (State & REPLACE_FLAG)
7834 buf[0] = 'R';
7835 else
7836 buf[0] = 'i';
7837#ifdef FEAT_INS_EXPAND
7838 if (ins_compl_active())
7839 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007840 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007841 buf[1] = 'x';
7842#endif
7843 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007844 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007845 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 {
7847 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007848 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007849 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007850 else if (exmode_active == EXMODE_NORMAL)
7851 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007852 }
7853 else
7854 {
7855 buf[0] = 'n';
7856 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007857 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007859 // to be able to detect force-linewise/blockwise/characterwise operations
7860 buf[2] = motion_force;
7861 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007862 else if (restart_edit == 'I' || restart_edit == 'R'
7863 || restart_edit == 'V')
7864 {
7865 buf[1] = 'i';
7866 buf[2] = restart_edit;
7867 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 }
7869
7870 /* Clear out the minor mode when the argument is not a non-zero number or
7871 * non-empty string. */
7872 if (!non_zero_arg(&argvars[0]))
7873 buf[1] = NUL;
7874
7875 rettv->vval.v_string = vim_strsave(buf);
7876 rettv->v_type = VAR_STRING;
7877}
7878
7879#if defined(FEAT_MZSCHEME) || defined(PROTO)
7880/*
7881 * "mzeval()" function
7882 */
7883 static void
7884f_mzeval(typval_T *argvars, typval_T *rettv)
7885{
7886 char_u *str;
7887 char_u buf[NUMBUFLEN];
7888
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007889 if (check_restricted() || check_secure())
7890 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007891 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892 do_mzeval(str, rettv);
7893}
7894
7895 void
7896mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7897{
7898 typval_T argvars[3];
7899
7900 argvars[0].v_type = VAR_STRING;
7901 argvars[0].vval.v_string = name;
7902 copy_tv(args, &argvars[1]);
7903 argvars[2].v_type = VAR_UNKNOWN;
7904 f_call(argvars, rettv);
7905 clear_tv(&argvars[1]);
7906}
7907#endif
7908
7909/*
7910 * "nextnonblank()" function
7911 */
7912 static void
7913f_nextnonblank(typval_T *argvars, typval_T *rettv)
7914{
7915 linenr_T lnum;
7916
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007917 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918 {
7919 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7920 {
7921 lnum = 0;
7922 break;
7923 }
7924 if (*skipwhite(ml_get(lnum)) != NUL)
7925 break;
7926 }
7927 rettv->vval.v_number = lnum;
7928}
7929
7930/*
7931 * "nr2char()" function
7932 */
7933 static void
7934f_nr2char(typval_T *argvars, typval_T *rettv)
7935{
7936 char_u buf[NUMBUFLEN];
7937
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007938 if (has_mbyte)
7939 {
7940 int utf8 = 0;
7941
7942 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007943 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007944 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007945 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007946 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007947 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007948 }
7949 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007951 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007952 buf[1] = NUL;
7953 }
7954 rettv->v_type = VAR_STRING;
7955 rettv->vval.v_string = vim_strsave(buf);
7956}
7957
7958/*
7959 * "or(expr, expr)" function
7960 */
7961 static void
7962f_or(typval_T *argvars, typval_T *rettv)
7963{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007964 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7965 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007966}
7967
7968/*
7969 * "pathshorten()" function
7970 */
7971 static void
7972f_pathshorten(typval_T *argvars, typval_T *rettv)
7973{
7974 char_u *p;
7975
7976 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007977 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007978 if (p == NULL)
7979 rettv->vval.v_string = NULL;
7980 else
7981 {
7982 p = vim_strsave(p);
7983 rettv->vval.v_string = p;
7984 if (p != NULL)
7985 shorten_dir(p);
7986 }
7987}
7988
7989#ifdef FEAT_PERL
7990/*
7991 * "perleval()" function
7992 */
7993 static void
7994f_perleval(typval_T *argvars, typval_T *rettv)
7995{
7996 char_u *str;
7997 char_u buf[NUMBUFLEN];
7998
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007999 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008000 do_perleval(str, rettv);
8001}
8002#endif
8003
8004#ifdef FEAT_FLOAT
8005/*
8006 * "pow()" function
8007 */
8008 static void
8009f_pow(typval_T *argvars, typval_T *rettv)
8010{
8011 float_T fx = 0.0, fy = 0.0;
8012
8013 rettv->v_type = VAR_FLOAT;
8014 if (get_float_arg(argvars, &fx) == OK
8015 && get_float_arg(&argvars[1], &fy) == OK)
8016 rettv->vval.v_float = pow(fx, fy);
8017 else
8018 rettv->vval.v_float = 0.0;
8019}
8020#endif
8021
8022/*
8023 * "prevnonblank()" function
8024 */
8025 static void
8026f_prevnonblank(typval_T *argvars, typval_T *rettv)
8027{
8028 linenr_T lnum;
8029
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008030 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008031 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8032 lnum = 0;
8033 else
8034 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8035 --lnum;
8036 rettv->vval.v_number = lnum;
8037}
8038
8039/* This dummy va_list is here because:
8040 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8041 * - locally in the function results in a "used before set" warning
8042 * - using va_start() to initialize it gives "function with fixed args" error */
8043static va_list ap;
8044
8045/*
8046 * "printf()" function
8047 */
8048 static void
8049f_printf(typval_T *argvars, typval_T *rettv)
8050{
8051 char_u buf[NUMBUFLEN];
8052 int len;
8053 char_u *s;
8054 int saved_did_emsg = did_emsg;
8055 char *fmt;
8056
8057 rettv->v_type = VAR_STRING;
8058 rettv->vval.v_string = NULL;
8059
8060 /* Get the required length, allocate the buffer and do it for real. */
8061 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008062 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008063 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008064 if (!did_emsg)
8065 {
8066 s = alloc(len + 1);
8067 if (s != NULL)
8068 {
8069 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008070 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8071 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008072 }
8073 }
8074 did_emsg |= saved_did_emsg;
8075}
8076
8077/*
8078 * "pumvisible()" function
8079 */
8080 static void
8081f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8082{
8083#ifdef FEAT_INS_EXPAND
8084 if (pum_visible())
8085 rettv->vval.v_number = 1;
8086#endif
8087}
8088
8089#ifdef FEAT_PYTHON3
8090/*
8091 * "py3eval()" function
8092 */
8093 static void
8094f_py3eval(typval_T *argvars, typval_T *rettv)
8095{
8096 char_u *str;
8097 char_u buf[NUMBUFLEN];
8098
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008099 if (check_restricted() || check_secure())
8100 return;
8101
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008102 if (p_pyx == 0)
8103 p_pyx = 3;
8104
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008105 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106 do_py3eval(str, rettv);
8107}
8108#endif
8109
8110#ifdef FEAT_PYTHON
8111/*
8112 * "pyeval()" function
8113 */
8114 static void
8115f_pyeval(typval_T *argvars, typval_T *rettv)
8116{
8117 char_u *str;
8118 char_u buf[NUMBUFLEN];
8119
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008120 if (check_restricted() || check_secure())
8121 return;
8122
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008123 if (p_pyx == 0)
8124 p_pyx = 2;
8125
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008126 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008127 do_pyeval(str, rettv);
8128}
8129#endif
8130
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008131#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
8132/*
8133 * "pyxeval()" function
8134 */
8135 static void
8136f_pyxeval(typval_T *argvars, typval_T *rettv)
8137{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008138 if (check_restricted() || check_secure())
8139 return;
8140
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01008141# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
8142 init_pyxversion();
8143 if (p_pyx == 2)
8144 f_pyeval(argvars, rettv);
8145 else
8146 f_py3eval(argvars, rettv);
8147# elif defined(FEAT_PYTHON)
8148 f_pyeval(argvars, rettv);
8149# elif defined(FEAT_PYTHON3)
8150 f_py3eval(argvars, rettv);
8151# endif
8152}
8153#endif
8154
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008155/*
8156 * "range()" function
8157 */
8158 static void
8159f_range(typval_T *argvars, typval_T *rettv)
8160{
8161 varnumber_T start;
8162 varnumber_T end;
8163 varnumber_T stride = 1;
8164 varnumber_T i;
8165 int error = FALSE;
8166
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008167 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008168 if (argvars[1].v_type == VAR_UNKNOWN)
8169 {
8170 end = start - 1;
8171 start = 0;
8172 }
8173 else
8174 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008175 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008177 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008178 }
8179
8180 if (error)
8181 return; /* type error; errmsg already given */
8182 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008183 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008185 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 else
8187 {
8188 if (rettv_list_alloc(rettv) == OK)
8189 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
8190 if (list_append_number(rettv->vval.v_list,
8191 (varnumber_T)i) == FAIL)
8192 break;
8193 }
8194}
8195
8196/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008197 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008198 */
8199 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008200readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008201{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008202 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008203 typval_T save_val;
8204 typval_T rettv;
8205 typval_T argv[2];
8206 int retval = 0;
8207 int error = FALSE;
8208
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008209 if (expr->v_type == VAR_UNKNOWN)
8210 return 1;
8211
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008212 prepare_vimvar(VV_VAL, &save_val);
8213 set_vim_var_string(VV_VAL, name, -1);
8214 argv[0].v_type = VAR_STRING;
8215 argv[0].vval.v_string = name;
8216
8217 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8218 goto theend;
8219
8220 retval = tv_get_number_chk(&rettv, &error);
8221 if (error)
8222 retval = -1;
8223 clear_tv(&rettv);
8224
8225theend:
8226 set_vim_var_string(VV_VAL, NULL, 0);
8227 restore_vimvar(VV_VAL, &save_val);
8228 return retval;
8229}
8230
8231/*
8232 * "readdir()" function
8233 */
8234 static void
8235f_readdir(typval_T *argvars, typval_T *rettv)
8236{
8237 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008238 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008239 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008240 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008241 garray_T ga;
8242 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008243
8244 if (rettv_list_alloc(rettv) == FAIL)
8245 return;
8246 path = tv_get_string(&argvars[0]);
8247 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008248
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008249 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8250 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008251 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008252 for (i = 0; i < ga.ga_len; i++)
8253 {
8254 p = ((char_u **)ga.ga_data)[i];
8255 list_append_string(rettv->vval.v_list, p, -1);
8256 }
8257 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008258 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008259}
8260
8261/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008262 * "readfile()" function
8263 */
8264 static void
8265f_readfile(typval_T *argvars, typval_T *rettv)
8266{
8267 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008268 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008269 int failed = FALSE;
8270 char_u *fname;
8271 FILE *fd;
8272 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8273 int io_size = sizeof(buf);
8274 int readlen; /* size of last fread() */
8275 char_u *prev = NULL; /* previously read bytes, if any */
8276 long prevlen = 0; /* length of data in prev */
8277 long prevsize = 0; /* size of prev buffer */
8278 long maxline = MAXLNUM;
8279 long cnt = 0;
8280 char_u *p; /* position in buf */
8281 char_u *start; /* start of current line */
8282
8283 if (argvars[1].v_type != VAR_UNKNOWN)
8284 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008285 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008286 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008287 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8288 blob = TRUE;
8289
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008290 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008291 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008292 }
8293
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008294 if (blob)
8295 {
8296 if (rettv_blob_alloc(rettv) == FAIL)
8297 return;
8298 }
8299 else
8300 {
8301 if (rettv_list_alloc(rettv) == FAIL)
8302 return;
8303 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304
8305 /* Always open the file in binary mode, library functions have a mind of
8306 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008307 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8309 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008310 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008311 return;
8312 }
8313
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008314 if (blob)
8315 {
8316 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8317 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008318 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008319 blob_free(rettv->vval.v_blob);
8320 }
8321 fclose(fd);
8322 return;
8323 }
8324
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008325 while (cnt < maxline || maxline < 0)
8326 {
8327 readlen = (int)fread(buf, 1, io_size, fd);
8328
8329 /* This for loop processes what was read, but is also entered at end
8330 * of file so that either:
8331 * - an incomplete line gets written
8332 * - a "binary" file gets an empty line at the end if it ends in a
8333 * newline. */
8334 for (p = buf, start = buf;
8335 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8336 ++p)
8337 {
8338 if (*p == '\n' || readlen <= 0)
8339 {
8340 listitem_T *li;
8341 char_u *s = NULL;
8342 long_u len = p - start;
8343
8344 /* Finished a line. Remove CRs before NL. */
8345 if (readlen > 0 && !binary)
8346 {
8347 while (len > 0 && start[len - 1] == '\r')
8348 --len;
8349 /* removal may cross back to the "prev" string */
8350 if (len == 0)
8351 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8352 --prevlen;
8353 }
8354 if (prevlen == 0)
8355 s = vim_strnsave(start, (int)len);
8356 else
8357 {
8358 /* Change "prev" buffer to be the right size. This way
8359 * the bytes are only copied once, and very long lines are
8360 * allocated only once. */
8361 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8362 {
8363 mch_memmove(s + prevlen, start, len);
8364 s[prevlen + len] = NUL;
8365 prev = NULL; /* the list will own the string */
8366 prevlen = prevsize = 0;
8367 }
8368 }
8369 if (s == NULL)
8370 {
8371 do_outofmem_msg((long_u) prevlen + len + 1);
8372 failed = TRUE;
8373 break;
8374 }
8375
8376 if ((li = listitem_alloc()) == NULL)
8377 {
8378 vim_free(s);
8379 failed = TRUE;
8380 break;
8381 }
8382 li->li_tv.v_type = VAR_STRING;
8383 li->li_tv.v_lock = 0;
8384 li->li_tv.vval.v_string = s;
8385 list_append(rettv->vval.v_list, li);
8386
8387 start = p + 1; /* step over newline */
8388 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8389 break;
8390 }
8391 else if (*p == NUL)
8392 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008393 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8394 * when finding the BF and check the previous two bytes. */
8395 else if (*p == 0xbf && enc_utf8 && !binary)
8396 {
8397 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8398 * + 1, these may be in the "prev" string. */
8399 char_u back1 = p >= buf + 1 ? p[-1]
8400 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8401 char_u back2 = p >= buf + 2 ? p[-2]
8402 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8403 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8404
8405 if (back2 == 0xef && back1 == 0xbb)
8406 {
8407 char_u *dest = p - 2;
8408
8409 /* Usually a BOM is at the beginning of a file, and so at
8410 * the beginning of a line; then we can just step over it.
8411 */
8412 if (start == dest)
8413 start = p + 1;
8414 else
8415 {
8416 /* have to shuffle buf to close gap */
8417 int adjust_prevlen = 0;
8418
8419 if (dest < buf)
8420 {
8421 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8422 dest = buf;
8423 }
8424 if (readlen > p - buf + 1)
8425 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8426 readlen -= 3 - adjust_prevlen;
8427 prevlen -= adjust_prevlen;
8428 p = dest - 1;
8429 }
8430 }
8431 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008432 } /* for */
8433
8434 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8435 break;
8436 if (start < p)
8437 {
8438 /* There's part of a line in buf, store it in "prev". */
8439 if (p - start + prevlen >= prevsize)
8440 {
8441 /* need bigger "prev" buffer */
8442 char_u *newprev;
8443
8444 /* A common use case is ordinary text files and "prev" gets a
8445 * fragment of a line, so the first allocation is made
8446 * small, to avoid repeatedly 'allocing' large and
8447 * 'reallocing' small. */
8448 if (prevsize == 0)
8449 prevsize = (long)(p - start);
8450 else
8451 {
8452 long grow50pc = (prevsize * 3) / 2;
8453 long growmin = (long)((p - start) * 2 + prevlen);
8454 prevsize = grow50pc > growmin ? grow50pc : growmin;
8455 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008456 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008457 if (newprev == NULL)
8458 {
8459 do_outofmem_msg((long_u)prevsize);
8460 failed = TRUE;
8461 break;
8462 }
8463 prev = newprev;
8464 }
8465 /* Add the line part to end of "prev". */
8466 mch_memmove(prev + prevlen, start, p - start);
8467 prevlen += (long)(p - start);
8468 }
8469 } /* while */
8470
8471 /*
8472 * For a negative line count use only the lines at the end of the file,
8473 * free the rest.
8474 */
8475 if (!failed && maxline < 0)
8476 while (cnt > -maxline)
8477 {
8478 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8479 --cnt;
8480 }
8481
8482 if (failed)
8483 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008484 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008485 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008486 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008487 }
8488
8489 vim_free(prev);
8490 fclose(fd);
8491}
8492
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008493 static void
8494return_register(int regname, typval_T *rettv)
8495{
8496 char_u buf[2] = {0, 0};
8497
8498 buf[0] = (char_u)regname;
8499 rettv->v_type = VAR_STRING;
8500 rettv->vval.v_string = vim_strsave(buf);
8501}
8502
8503/*
8504 * "reg_executing()" function
8505 */
8506 static void
8507f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8508{
8509 return_register(reg_executing, rettv);
8510}
8511
8512/*
8513 * "reg_recording()" function
8514 */
8515 static void
8516f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8517{
8518 return_register(reg_recording, rettv);
8519}
8520
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008521#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008522/*
8523 * Convert a List to proftime_T.
8524 * Return FAIL when there is something wrong.
8525 */
8526 static int
8527list2proftime(typval_T *arg, proftime_T *tm)
8528{
8529 long n1, n2;
8530 int error = FALSE;
8531
8532 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8533 || arg->vval.v_list->lv_len != 2)
8534 return FAIL;
8535 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8536 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008537# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008538 tm->HighPart = n1;
8539 tm->LowPart = n2;
8540# else
8541 tm->tv_sec = n1;
8542 tm->tv_usec = n2;
8543# endif
8544 return error ? FAIL : OK;
8545}
8546#endif /* FEAT_RELTIME */
8547
8548/*
8549 * "reltime()" function
8550 */
8551 static void
8552f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8553{
8554#ifdef FEAT_RELTIME
8555 proftime_T res;
8556 proftime_T start;
8557
8558 if (argvars[0].v_type == VAR_UNKNOWN)
8559 {
8560 /* No arguments: get current time. */
8561 profile_start(&res);
8562 }
8563 else if (argvars[1].v_type == VAR_UNKNOWN)
8564 {
8565 if (list2proftime(&argvars[0], &res) == FAIL)
8566 return;
8567 profile_end(&res);
8568 }
8569 else
8570 {
8571 /* Two arguments: compute the difference. */
8572 if (list2proftime(&argvars[0], &start) == FAIL
8573 || list2proftime(&argvars[1], &res) == FAIL)
8574 return;
8575 profile_sub(&res, &start);
8576 }
8577
8578 if (rettv_list_alloc(rettv) == OK)
8579 {
8580 long n1, n2;
8581
Bram Moolenaar4f974752019-02-17 17:44:42 +01008582# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008583 n1 = res.HighPart;
8584 n2 = res.LowPart;
8585# else
8586 n1 = res.tv_sec;
8587 n2 = res.tv_usec;
8588# endif
8589 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8590 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8591 }
8592#endif
8593}
8594
8595#ifdef FEAT_FLOAT
8596/*
8597 * "reltimefloat()" function
8598 */
8599 static void
8600f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8601{
8602# ifdef FEAT_RELTIME
8603 proftime_T tm;
8604# endif
8605
8606 rettv->v_type = VAR_FLOAT;
8607 rettv->vval.v_float = 0;
8608# ifdef FEAT_RELTIME
8609 if (list2proftime(&argvars[0], &tm) == OK)
8610 rettv->vval.v_float = profile_float(&tm);
8611# endif
8612}
8613#endif
8614
8615/*
8616 * "reltimestr()" function
8617 */
8618 static void
8619f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8620{
8621#ifdef FEAT_RELTIME
8622 proftime_T tm;
8623#endif
8624
8625 rettv->v_type = VAR_STRING;
8626 rettv->vval.v_string = NULL;
8627#ifdef FEAT_RELTIME
8628 if (list2proftime(&argvars[0], &tm) == OK)
8629 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8630#endif
8631}
8632
8633#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008634 static void
8635make_connection(void)
8636{
8637 if (X_DISPLAY == NULL
8638# ifdef FEAT_GUI
8639 && !gui.in_use
8640# endif
8641 )
8642 {
8643 x_force_connect = TRUE;
8644 setup_term_clip();
8645 x_force_connect = FALSE;
8646 }
8647}
8648
8649 static int
8650check_connection(void)
8651{
8652 make_connection();
8653 if (X_DISPLAY == NULL)
8654 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008655 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008656 return FAIL;
8657 }
8658 return OK;
8659}
8660#endif
8661
8662#ifdef FEAT_CLIENTSERVER
8663 static void
8664remote_common(typval_T *argvars, typval_T *rettv, int expr)
8665{
8666 char_u *server_name;
8667 char_u *keys;
8668 char_u *r = NULL;
8669 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008670 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008671# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008672 HWND w;
8673# else
8674 Window w;
8675# endif
8676
8677 if (check_restricted() || check_secure())
8678 return;
8679
8680# ifdef FEAT_X11
8681 if (check_connection() == FAIL)
8682 return;
8683# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008684 if (argvars[2].v_type != VAR_UNKNOWN
8685 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008686 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008687
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008688 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689 if (server_name == NULL)
8690 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008691 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008692# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008693 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008694# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008695 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8696 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008697# endif
8698 {
8699 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008700 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008701 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008702 vim_free(r);
8703 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008704 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008705 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008706 return;
8707 }
8708
8709 rettv->vval.v_string = r;
8710
8711 if (argvars[2].v_type != VAR_UNKNOWN)
8712 {
8713 dictitem_T v;
8714 char_u str[30];
8715 char_u *idvar;
8716
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008717 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008718 if (idvar != NULL && *idvar != NUL)
8719 {
8720 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8721 v.di_tv.v_type = VAR_STRING;
8722 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008723 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008724 vim_free(v.di_tv.vval.v_string);
8725 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726 }
8727}
8728#endif
8729
8730/*
8731 * "remote_expr()" function
8732 */
8733 static void
8734f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8735{
8736 rettv->v_type = VAR_STRING;
8737 rettv->vval.v_string = NULL;
8738#ifdef FEAT_CLIENTSERVER
8739 remote_common(argvars, rettv, TRUE);
8740#endif
8741}
8742
8743/*
8744 * "remote_foreground()" function
8745 */
8746 static void
8747f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8748{
8749#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008750# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008751 /* On Win32 it's done in this application. */
8752 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008753 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008754
8755 if (server_name != NULL)
8756 serverForeground(server_name);
8757 }
8758# else
8759 /* Send a foreground() expression to the server. */
8760 argvars[1].v_type = VAR_STRING;
8761 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8762 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008763 rettv->v_type = VAR_STRING;
8764 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008765 remote_common(argvars, rettv, TRUE);
8766 vim_free(argvars[1].vval.v_string);
8767# endif
8768#endif
8769}
8770
8771 static void
8772f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8773{
8774#ifdef FEAT_CLIENTSERVER
8775 dictitem_T v;
8776 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008777# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008778 long_u n = 0;
8779# endif
8780 char_u *serverid;
8781
8782 if (check_restricted() || check_secure())
8783 {
8784 rettv->vval.v_number = -1;
8785 return;
8786 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008787 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008788 if (serverid == NULL)
8789 {
8790 rettv->vval.v_number = -1;
8791 return; /* type error; errmsg already given */
8792 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008793# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008794 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8795 if (n == 0)
8796 rettv->vval.v_number = -1;
8797 else
8798 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008799 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008800 rettv->vval.v_number = (s != NULL);
8801 }
8802# else
8803 if (check_connection() == FAIL)
8804 return;
8805
8806 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8807 serverStrToWin(serverid), &s);
8808# endif
8809
8810 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8811 {
8812 char_u *retvar;
8813
8814 v.di_tv.v_type = VAR_STRING;
8815 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008816 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008817 if (retvar != NULL)
8818 set_var(retvar, &v.di_tv, FALSE);
8819 vim_free(v.di_tv.vval.v_string);
8820 }
8821#else
8822 rettv->vval.v_number = -1;
8823#endif
8824}
8825
8826 static void
8827f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8828{
8829 char_u *r = NULL;
8830
8831#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008832 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008833
8834 if (serverid != NULL && !check_restricted() && !check_secure())
8835 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008836 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008837# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008838 /* The server's HWND is encoded in the 'id' parameter */
8839 long_u n = 0;
8840# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008841
8842 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008843 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008844
Bram Moolenaar4f974752019-02-17 17:44:42 +01008845# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008846 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8847 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008848 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008849 if (r == NULL)
8850# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008851 if (check_connection() == FAIL
8852 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8853 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008855 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008856 }
8857#endif
8858 rettv->v_type = VAR_STRING;
8859 rettv->vval.v_string = r;
8860}
8861
8862/*
8863 * "remote_send()" function
8864 */
8865 static void
8866f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8867{
8868 rettv->v_type = VAR_STRING;
8869 rettv->vval.v_string = NULL;
8870#ifdef FEAT_CLIENTSERVER
8871 remote_common(argvars, rettv, FALSE);
8872#endif
8873}
8874
8875/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008876 * "remote_startserver()" function
8877 */
8878 static void
8879f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8880{
8881#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008882 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008883
8884 if (server == NULL)
8885 return; /* type error; errmsg already given */
8886 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008887 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008888 else
8889 {
8890# ifdef FEAT_X11
8891 if (check_connection() == OK)
8892 serverRegisterName(X_DISPLAY, server);
8893# else
8894 serverSetName(server);
8895# endif
8896 }
8897#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008898 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008899#endif
8900}
8901
8902/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008903 * "remove()" function
8904 */
8905 static void
8906f_remove(typval_T *argvars, typval_T *rettv)
8907{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008908 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8909
8910 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008911 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008912 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008913 blob_remove(argvars, rettv);
8914 else if (argvars[0].v_type == VAR_LIST)
8915 list_remove(argvars, rettv, arg_errmsg);
8916 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008917 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008918}
8919
8920/*
8921 * "rename({from}, {to})" function
8922 */
8923 static void
8924f_rename(typval_T *argvars, typval_T *rettv)
8925{
8926 char_u buf[NUMBUFLEN];
8927
8928 if (check_restricted() || check_secure())
8929 rettv->vval.v_number = -1;
8930 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008931 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8932 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008933}
8934
8935/*
8936 * "repeat()" function
8937 */
8938 static void
8939f_repeat(typval_T *argvars, typval_T *rettv)
8940{
8941 char_u *p;
8942 int n;
8943 int slen;
8944 int len;
8945 char_u *r;
8946 int i;
8947
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008948 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008949 if (argvars[0].v_type == VAR_LIST)
8950 {
8951 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8952 while (n-- > 0)
8953 if (list_extend(rettv->vval.v_list,
8954 argvars[0].vval.v_list, NULL) == FAIL)
8955 break;
8956 }
8957 else
8958 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008959 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008960 rettv->v_type = VAR_STRING;
8961 rettv->vval.v_string = NULL;
8962
8963 slen = (int)STRLEN(p);
8964 len = slen * n;
8965 if (len <= 0)
8966 return;
8967
8968 r = alloc(len + 1);
8969 if (r != NULL)
8970 {
8971 for (i = 0; i < n; i++)
8972 mch_memmove(r + i * slen, p, (size_t)slen);
8973 r[len] = NUL;
8974 }
8975
8976 rettv->vval.v_string = r;
8977 }
8978}
8979
8980/*
8981 * "resolve()" function
8982 */
8983 static void
8984f_resolve(typval_T *argvars, typval_T *rettv)
8985{
8986 char_u *p;
8987#ifdef HAVE_READLINK
8988 char_u *buf = NULL;
8989#endif
8990
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008991 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008992#ifdef FEAT_SHORTCUT
8993 {
8994 char_u *v = NULL;
8995
Bram Moolenaardce1e892019-02-10 23:18:53 +01008996 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008997 if (v != NULL)
8998 rettv->vval.v_string = v;
8999 else
9000 rettv->vval.v_string = vim_strsave(p);
9001 }
9002#else
9003# ifdef HAVE_READLINK
9004 {
9005 char_u *cpy;
9006 int len;
9007 char_u *remain = NULL;
9008 char_u *q;
9009 int is_relative_to_current = FALSE;
9010 int has_trailing_pathsep = FALSE;
9011 int limit = 100;
9012
9013 p = vim_strsave(p);
9014
9015 if (p[0] == '.' && (vim_ispathsep(p[1])
9016 || (p[1] == '.' && (vim_ispathsep(p[2])))))
9017 is_relative_to_current = TRUE;
9018
9019 len = STRLEN(p);
9020 if (len > 0 && after_pathsep(p, p + len))
9021 {
9022 has_trailing_pathsep = TRUE;
9023 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
9024 }
9025
9026 q = getnextcomp(p);
9027 if (*q != NUL)
9028 {
9029 /* Separate the first path component in "p", and keep the
9030 * remainder (beginning with the path separator). */
9031 remain = vim_strsave(q - 1);
9032 q[-1] = NUL;
9033 }
9034
9035 buf = alloc(MAXPATHL + 1);
9036 if (buf == NULL)
9037 goto fail;
9038
9039 for (;;)
9040 {
9041 for (;;)
9042 {
9043 len = readlink((char *)p, (char *)buf, MAXPATHL);
9044 if (len <= 0)
9045 break;
9046 buf[len] = NUL;
9047
9048 if (limit-- == 0)
9049 {
9050 vim_free(p);
9051 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009052 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009053 rettv->vval.v_string = NULL;
9054 goto fail;
9055 }
9056
9057 /* Ensure that the result will have a trailing path separator
9058 * if the argument has one. */
9059 if (remain == NULL && has_trailing_pathsep)
9060 add_pathsep(buf);
9061
9062 /* Separate the first path component in the link value and
9063 * concatenate the remainders. */
9064 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
9065 if (*q != NUL)
9066 {
9067 if (remain == NULL)
9068 remain = vim_strsave(q - 1);
9069 else
9070 {
9071 cpy = concat_str(q - 1, remain);
9072 if (cpy != NULL)
9073 {
9074 vim_free(remain);
9075 remain = cpy;
9076 }
9077 }
9078 q[-1] = NUL;
9079 }
9080
9081 q = gettail(p);
9082 if (q > p && *q == NUL)
9083 {
9084 /* Ignore trailing path separator. */
9085 q[-1] = NUL;
9086 q = gettail(p);
9087 }
9088 if (q > p && !mch_isFullName(buf))
9089 {
9090 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009091 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009092 if (cpy != NULL)
9093 {
9094 STRCPY(cpy, p);
9095 STRCPY(gettail(cpy), buf);
9096 vim_free(p);
9097 p = cpy;
9098 }
9099 }
9100 else
9101 {
9102 vim_free(p);
9103 p = vim_strsave(buf);
9104 }
9105 }
9106
9107 if (remain == NULL)
9108 break;
9109
9110 /* Append the first path component of "remain" to "p". */
9111 q = getnextcomp(remain + 1);
9112 len = q - remain - (*q != NUL);
9113 cpy = vim_strnsave(p, STRLEN(p) + len);
9114 if (cpy != NULL)
9115 {
9116 STRNCAT(cpy, remain, len);
9117 vim_free(p);
9118 p = cpy;
9119 }
9120 /* Shorten "remain". */
9121 if (*q != NUL)
9122 STRMOVE(remain, q - 1);
9123 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01009124 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009125 }
9126
9127 /* If the result is a relative path name, make it explicitly relative to
9128 * the current directory if and only if the argument had this form. */
9129 if (!vim_ispathsep(*p))
9130 {
9131 if (is_relative_to_current
9132 && *p != NUL
9133 && !(p[0] == '.'
9134 && (p[1] == NUL
9135 || vim_ispathsep(p[1])
9136 || (p[1] == '.'
9137 && (p[2] == NUL
9138 || vim_ispathsep(p[2]))))))
9139 {
9140 /* Prepend "./". */
9141 cpy = concat_str((char_u *)"./", p);
9142 if (cpy != NULL)
9143 {
9144 vim_free(p);
9145 p = cpy;
9146 }
9147 }
9148 else if (!is_relative_to_current)
9149 {
9150 /* Strip leading "./". */
9151 q = p;
9152 while (q[0] == '.' && vim_ispathsep(q[1]))
9153 q += 2;
9154 if (q > p)
9155 STRMOVE(p, p + 2);
9156 }
9157 }
9158
9159 /* Ensure that the result will have no trailing path separator
9160 * if the argument had none. But keep "/" or "//". */
9161 if (!has_trailing_pathsep)
9162 {
9163 q = p + STRLEN(p);
9164 if (after_pathsep(p, q))
9165 *gettail_sep(p) = NUL;
9166 }
9167
9168 rettv->vval.v_string = p;
9169 }
9170# else
9171 rettv->vval.v_string = vim_strsave(p);
9172# endif
9173#endif
9174
9175 simplify_filename(rettv->vval.v_string);
9176
9177#ifdef HAVE_READLINK
9178fail:
9179 vim_free(buf);
9180#endif
9181 rettv->v_type = VAR_STRING;
9182}
9183
9184/*
9185 * "reverse({list})" function
9186 */
9187 static void
9188f_reverse(typval_T *argvars, typval_T *rettv)
9189{
9190 list_T *l;
9191 listitem_T *li, *ni;
9192
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009193 if (argvars[0].v_type == VAR_BLOB)
9194 {
9195 blob_T *b = argvars[0].vval.v_blob;
9196 int i, len = blob_len(b);
9197
9198 for (i = 0; i < len / 2; i++)
9199 {
9200 int tmp = blob_get(b, i);
9201
9202 blob_set(b, i, blob_get(b, len - i - 1));
9203 blob_set(b, len - i - 1, tmp);
9204 }
9205 rettv_blob_set(rettv, b);
9206 return;
9207 }
9208
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009209 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009210 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009211 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009212 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009213 (char_u *)N_("reverse() argument"), TRUE))
9214 {
9215 li = l->lv_last;
9216 l->lv_first = l->lv_last = NULL;
9217 l->lv_len = 0;
9218 while (li != NULL)
9219 {
9220 ni = li->li_prev;
9221 list_append(l, li);
9222 li = ni;
9223 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009224 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009225 l->lv_idx = l->lv_len - l->lv_idx - 1;
9226 }
9227}
9228
9229#define SP_NOMOVE 0x01 /* don't move cursor */
9230#define SP_REPEAT 0x02 /* repeat to find outer pair */
9231#define SP_RETCOUNT 0x04 /* return matchcount */
9232#define SP_SETPCMARK 0x08 /* set previous context mark */
9233#define SP_START 0x10 /* accept match at start position */
9234#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9235#define SP_END 0x40 /* leave cursor at end of match */
9236#define SP_COLUMN 0x80 /* start at cursor column */
9237
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009238/*
9239 * Get flags for a search function.
9240 * Possibly sets "p_ws".
9241 * Returns BACKWARD, FORWARD or zero (for an error).
9242 */
9243 static int
9244get_search_arg(typval_T *varp, int *flagsp)
9245{
9246 int dir = FORWARD;
9247 char_u *flags;
9248 char_u nbuf[NUMBUFLEN];
9249 int mask;
9250
9251 if (varp->v_type != VAR_UNKNOWN)
9252 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009253 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009254 if (flags == NULL)
9255 return 0; /* type error; errmsg already given */
9256 while (*flags != NUL)
9257 {
9258 switch (*flags)
9259 {
9260 case 'b': dir = BACKWARD; break;
9261 case 'w': p_ws = TRUE; break;
9262 case 'W': p_ws = FALSE; break;
9263 default: mask = 0;
9264 if (flagsp != NULL)
9265 switch (*flags)
9266 {
9267 case 'c': mask = SP_START; break;
9268 case 'e': mask = SP_END; break;
9269 case 'm': mask = SP_RETCOUNT; break;
9270 case 'n': mask = SP_NOMOVE; break;
9271 case 'p': mask = SP_SUBPAT; break;
9272 case 'r': mask = SP_REPEAT; break;
9273 case 's': mask = SP_SETPCMARK; break;
9274 case 'z': mask = SP_COLUMN; break;
9275 }
9276 if (mask == 0)
9277 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009278 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009279 dir = 0;
9280 }
9281 else
9282 *flagsp |= mask;
9283 }
9284 if (dir == 0)
9285 break;
9286 ++flags;
9287 }
9288 }
9289 return dir;
9290}
9291
9292/*
9293 * Shared by search() and searchpos() functions.
9294 */
9295 static int
9296search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9297{
9298 int flags;
9299 char_u *pat;
9300 pos_T pos;
9301 pos_T save_cursor;
9302 int save_p_ws = p_ws;
9303 int dir;
9304 int retval = 0; /* default: FAIL */
9305 long lnum_stop = 0;
9306 proftime_T tm;
9307#ifdef FEAT_RELTIME
9308 long time_limit = 0;
9309#endif
9310 int options = SEARCH_KEEP;
9311 int subpatnum;
9312
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009313 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009314 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9315 if (dir == 0)
9316 goto theend;
9317 flags = *flagsp;
9318 if (flags & SP_START)
9319 options |= SEARCH_START;
9320 if (flags & SP_END)
9321 options |= SEARCH_END;
9322 if (flags & SP_COLUMN)
9323 options |= SEARCH_COL;
9324
9325 /* Optional arguments: line number to stop searching and timeout. */
9326 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9327 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009328 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009329 if (lnum_stop < 0)
9330 goto theend;
9331#ifdef FEAT_RELTIME
9332 if (argvars[3].v_type != VAR_UNKNOWN)
9333 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009334 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009335 if (time_limit < 0)
9336 goto theend;
9337 }
9338#endif
9339 }
9340
9341#ifdef FEAT_RELTIME
9342 /* Set the time limit, if there is one. */
9343 profile_setlimit(time_limit, &tm);
9344#endif
9345
9346 /*
9347 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9348 * Check to make sure only those flags are set.
9349 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9350 * flags cannot be set. Check for that condition also.
9351 */
9352 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9353 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9354 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009355 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009356 goto theend;
9357 }
9358
9359 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009360 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009361 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009362 if (subpatnum != FAIL)
9363 {
9364 if (flags & SP_SUBPAT)
9365 retval = subpatnum;
9366 else
9367 retval = pos.lnum;
9368 if (flags & SP_SETPCMARK)
9369 setpcmark();
9370 curwin->w_cursor = pos;
9371 if (match_pos != NULL)
9372 {
9373 /* Store the match cursor position */
9374 match_pos->lnum = pos.lnum;
9375 match_pos->col = pos.col + 1;
9376 }
9377 /* "/$" will put the cursor after the end of the line, may need to
9378 * correct that here */
9379 check_cursor();
9380 }
9381
9382 /* If 'n' flag is used: restore cursor position. */
9383 if (flags & SP_NOMOVE)
9384 curwin->w_cursor = save_cursor;
9385 else
9386 curwin->w_set_curswant = TRUE;
9387theend:
9388 p_ws = save_p_ws;
9389
9390 return retval;
9391}
9392
9393#ifdef FEAT_FLOAT
9394
9395/*
9396 * round() is not in C90, use ceil() or floor() instead.
9397 */
9398 float_T
9399vim_round(float_T f)
9400{
9401 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9402}
9403
9404/*
9405 * "round({float})" function
9406 */
9407 static void
9408f_round(typval_T *argvars, typval_T *rettv)
9409{
9410 float_T f = 0.0;
9411
9412 rettv->v_type = VAR_FLOAT;
9413 if (get_float_arg(argvars, &f) == OK)
9414 rettv->vval.v_float = vim_round(f);
9415 else
9416 rettv->vval.v_float = 0.0;
9417}
9418#endif
9419
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009420#ifdef FEAT_RUBY
9421/*
9422 * "rubyeval()" function
9423 */
9424 static void
9425f_rubyeval(typval_T *argvars, typval_T *rettv)
9426{
9427 char_u *str;
9428 char_u buf[NUMBUFLEN];
9429
9430 str = tv_get_string_buf(&argvars[0], buf);
9431 do_rubyeval(str, rettv);
9432}
9433#endif
9434
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009435/*
9436 * "screenattr()" function
9437 */
9438 static void
9439f_screenattr(typval_T *argvars, typval_T *rettv)
9440{
9441 int row;
9442 int col;
9443 int c;
9444
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009445 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9446 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009447 if (row < 0 || row >= screen_Rows
9448 || col < 0 || col >= screen_Columns)
9449 c = -1;
9450 else
9451 c = ScreenAttrs[LineOffset[row] + col];
9452 rettv->vval.v_number = c;
9453}
9454
9455/*
9456 * "screenchar()" function
9457 */
9458 static void
9459f_screenchar(typval_T *argvars, typval_T *rettv)
9460{
9461 int row;
9462 int col;
9463 int off;
9464 int c;
9465
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009466 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9467 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009468 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009469 c = -1;
9470 else
9471 {
9472 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009473 if (enc_utf8 && ScreenLinesUC[off] != 0)
9474 c = ScreenLinesUC[off];
9475 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009476 c = ScreenLines[off];
9477 }
9478 rettv->vval.v_number = c;
9479}
9480
9481/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009482 * "screenchars()" function
9483 */
9484 static void
9485f_screenchars(typval_T *argvars, typval_T *rettv)
9486{
9487 int row;
9488 int col;
9489 int off;
9490 int c;
9491 int i;
9492
9493 if (rettv_list_alloc(rettv) == FAIL)
9494 return;
9495 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9496 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9497 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9498 return;
9499
9500 off = LineOffset[row] + col;
9501 if (enc_utf8 && ScreenLinesUC[off] != 0)
9502 c = ScreenLinesUC[off];
9503 else
9504 c = ScreenLines[off];
9505 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9506
9507 if (enc_utf8)
9508
9509 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9510 list_append_number(rettv->vval.v_list,
9511 (varnumber_T)ScreenLinesC[i][off]);
9512}
9513
9514/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009515 * "screencol()" function
9516 *
9517 * First column is 1 to be consistent with virtcol().
9518 */
9519 static void
9520f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9521{
9522 rettv->vval.v_number = screen_screencol() + 1;
9523}
9524
9525/*
9526 * "screenrow()" function
9527 */
9528 static void
9529f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9530{
9531 rettv->vval.v_number = screen_screenrow() + 1;
9532}
9533
9534/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009535 * "screenstring()" function
9536 */
9537 static void
9538f_screenstring(typval_T *argvars, typval_T *rettv)
9539{
9540 int row;
9541 int col;
9542 int off;
9543 int c;
9544 int i;
9545 char_u buf[MB_MAXBYTES + 1];
9546 int buflen = 0;
9547
9548 rettv->vval.v_string = NULL;
9549 rettv->v_type = VAR_STRING;
9550
9551 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9552 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9553 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9554 return;
9555
9556 off = LineOffset[row] + col;
9557 if (enc_utf8 && ScreenLinesUC[off] != 0)
9558 c = ScreenLinesUC[off];
9559 else
9560 c = ScreenLines[off];
9561 buflen += mb_char2bytes(c, buf);
9562
9563 if (enc_utf8)
9564 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9565 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9566
9567 buf[buflen] = NUL;
9568 rettv->vval.v_string = vim_strsave(buf);
9569}
9570
9571/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009572 * "search()" function
9573 */
9574 static void
9575f_search(typval_T *argvars, typval_T *rettv)
9576{
9577 int flags = 0;
9578
9579 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9580}
9581
9582/*
9583 * "searchdecl()" function
9584 */
9585 static void
9586f_searchdecl(typval_T *argvars, typval_T *rettv)
9587{
9588 int locally = 1;
9589 int thisblock = 0;
9590 int error = FALSE;
9591 char_u *name;
9592
9593 rettv->vval.v_number = 1; /* default: FAIL */
9594
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009595 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009596 if (argvars[1].v_type != VAR_UNKNOWN)
9597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009598 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009599 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009600 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009601 }
9602 if (!error && name != NULL)
9603 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9604 locally, thisblock, SEARCH_KEEP) == FAIL;
9605}
9606
9607/*
9608 * Used by searchpair() and searchpairpos()
9609 */
9610 static int
9611searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9612{
9613 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009614 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009615 int save_p_ws = p_ws;
9616 int dir;
9617 int flags = 0;
9618 char_u nbuf1[NUMBUFLEN];
9619 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009620 int retval = 0; /* default: FAIL */
9621 long lnum_stop = 0;
9622 long time_limit = 0;
9623
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009624 /* Get the three pattern arguments: start, middle, end. Will result in an
9625 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009626 spat = tv_get_string_chk(&argvars[0]);
9627 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9628 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009629 if (spat == NULL || mpat == NULL || epat == NULL)
9630 goto theend; /* type error */
9631
9632 /* Handle the optional fourth argument: flags */
9633 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9634 if (dir == 0)
9635 goto theend;
9636
9637 /* Don't accept SP_END or SP_SUBPAT.
9638 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9639 */
9640 if ((flags & (SP_END | SP_SUBPAT)) != 0
9641 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9642 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009643 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009644 goto theend;
9645 }
9646
9647 /* Using 'r' implies 'W', otherwise it doesn't work. */
9648 if (flags & SP_REPEAT)
9649 p_ws = FALSE;
9650
9651 /* Optional fifth argument: skip expression */
9652 if (argvars[3].v_type == VAR_UNKNOWN
9653 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009654 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009655 else
9656 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009657 skip = &argvars[4];
9658 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9659 && skip->v_type != VAR_STRING)
9660 {
9661 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009662 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009663 goto theend;
9664 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009665 if (argvars[5].v_type != VAR_UNKNOWN)
9666 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009667 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009668 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009669 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009670 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009671 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009672 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009673#ifdef FEAT_RELTIME
9674 if (argvars[6].v_type != VAR_UNKNOWN)
9675 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009676 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009677 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009678 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009679 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009680 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009681 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009682 }
9683#endif
9684 }
9685 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009686
9687 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9688 match_pos, lnum_stop, time_limit);
9689
9690theend:
9691 p_ws = save_p_ws;
9692
9693 return retval;
9694}
9695
9696/*
9697 * "searchpair()" function
9698 */
9699 static void
9700f_searchpair(typval_T *argvars, typval_T *rettv)
9701{
9702 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9703}
9704
9705/*
9706 * "searchpairpos()" function
9707 */
9708 static void
9709f_searchpairpos(typval_T *argvars, typval_T *rettv)
9710{
9711 pos_T match_pos;
9712 int lnum = 0;
9713 int col = 0;
9714
9715 if (rettv_list_alloc(rettv) == FAIL)
9716 return;
9717
9718 if (searchpair_cmn(argvars, &match_pos) > 0)
9719 {
9720 lnum = match_pos.lnum;
9721 col = match_pos.col;
9722 }
9723
9724 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9725 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9726}
9727
9728/*
9729 * Search for a start/middle/end thing.
9730 * Used by searchpair(), see its documentation for the details.
9731 * Returns 0 or -1 for no match,
9732 */
9733 long
9734do_searchpair(
9735 char_u *spat, /* start pattern */
9736 char_u *mpat, /* middle pattern */
9737 char_u *epat, /* end pattern */
9738 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009739 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009740 int flags, /* SP_SETPCMARK and other SP_ values */
9741 pos_T *match_pos,
9742 linenr_T lnum_stop, /* stop at this line if not zero */
9743 long time_limit UNUSED) /* stop after this many msec */
9744{
9745 char_u *save_cpo;
9746 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9747 long retval = 0;
9748 pos_T pos;
9749 pos_T firstpos;
9750 pos_T foundpos;
9751 pos_T save_cursor;
9752 pos_T save_pos;
9753 int n;
9754 int r;
9755 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009756 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009757 int err;
9758 int options = SEARCH_KEEP;
9759 proftime_T tm;
9760
9761 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9762 save_cpo = p_cpo;
9763 p_cpo = empty_option;
9764
9765#ifdef FEAT_RELTIME
9766 /* Set the time limit, if there is one. */
9767 profile_setlimit(time_limit, &tm);
9768#endif
9769
9770 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9771 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009772 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9773 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009774 if (pat2 == NULL || pat3 == NULL)
9775 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009776 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009777 if (*mpat == NUL)
9778 STRCPY(pat3, pat2);
9779 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009780 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009781 spat, epat, mpat);
9782 if (flags & SP_START)
9783 options |= SEARCH_START;
9784
Bram Moolenaar48570482017-10-30 21:48:41 +01009785 if (skip != NULL)
9786 {
9787 /* Empty string means to not use the skip expression. */
9788 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9789 use_skip = skip->vval.v_string != NULL
9790 && *skip->vval.v_string != NUL;
9791 }
9792
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009793 save_cursor = curwin->w_cursor;
9794 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009795 CLEAR_POS(&firstpos);
9796 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009797 pat = pat3;
9798 for (;;)
9799 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009800 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009801 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009802 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009803 /* didn't find it or found the first match again: FAIL */
9804 break;
9805
9806 if (firstpos.lnum == 0)
9807 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009808 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 {
9810 /* Found the same position again. Can happen with a pattern that
9811 * has "\zs" at the end and searching backwards. Advance one
9812 * character and try again. */
9813 if (dir == BACKWARD)
9814 decl(&pos);
9815 else
9816 incl(&pos);
9817 }
9818 foundpos = pos;
9819
9820 /* clear the start flag to avoid getting stuck here */
9821 options &= ~SEARCH_START;
9822
9823 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009824 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009825 {
9826 save_pos = curwin->w_cursor;
9827 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009828 err = FALSE;
9829 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009830 curwin->w_cursor = save_pos;
9831 if (err)
9832 {
9833 /* Evaluating {skip} caused an error, break here. */
9834 curwin->w_cursor = save_cursor;
9835 retval = -1;
9836 break;
9837 }
9838 if (r)
9839 continue;
9840 }
9841
9842 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9843 {
9844 /* Found end when searching backwards or start when searching
9845 * forward: nested pair. */
9846 ++nest;
9847 pat = pat2; /* nested, don't search for middle */
9848 }
9849 else
9850 {
9851 /* Found end when searching forward or start when searching
9852 * backward: end of (nested) pair; or found middle in outer pair. */
9853 if (--nest == 1)
9854 pat = pat3; /* outer level, search for middle */
9855 }
9856
9857 if (nest == 0)
9858 {
9859 /* Found the match: return matchcount or line number. */
9860 if (flags & SP_RETCOUNT)
9861 ++retval;
9862 else
9863 retval = pos.lnum;
9864 if (flags & SP_SETPCMARK)
9865 setpcmark();
9866 curwin->w_cursor = pos;
9867 if (!(flags & SP_REPEAT))
9868 break;
9869 nest = 1; /* search for next unmatched */
9870 }
9871 }
9872
9873 if (match_pos != NULL)
9874 {
9875 /* Store the match cursor position */
9876 match_pos->lnum = curwin->w_cursor.lnum;
9877 match_pos->col = curwin->w_cursor.col + 1;
9878 }
9879
9880 /* If 'n' flag is used or search failed: restore cursor position. */
9881 if ((flags & SP_NOMOVE) || retval == 0)
9882 curwin->w_cursor = save_cursor;
9883
9884theend:
9885 vim_free(pat2);
9886 vim_free(pat3);
9887 if (p_cpo == empty_option)
9888 p_cpo = save_cpo;
9889 else
9890 /* Darn, evaluating the {skip} expression changed the value. */
9891 free_string_option(save_cpo);
9892
9893 return retval;
9894}
9895
9896/*
9897 * "searchpos()" function
9898 */
9899 static void
9900f_searchpos(typval_T *argvars, typval_T *rettv)
9901{
9902 pos_T match_pos;
9903 int lnum = 0;
9904 int col = 0;
9905 int n;
9906 int flags = 0;
9907
9908 if (rettv_list_alloc(rettv) == FAIL)
9909 return;
9910
9911 n = search_cmn(argvars, &match_pos, &flags);
9912 if (n > 0)
9913 {
9914 lnum = match_pos.lnum;
9915 col = match_pos.col;
9916 }
9917
9918 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9919 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9920 if (flags & SP_SUBPAT)
9921 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9922}
9923
9924 static void
9925f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9926{
9927#ifdef FEAT_CLIENTSERVER
9928 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009929 char_u *server = tv_get_string_chk(&argvars[0]);
9930 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009931
9932 rettv->vval.v_number = -1;
9933 if (server == NULL || reply == NULL)
9934 return;
9935 if (check_restricted() || check_secure())
9936 return;
9937# ifdef FEAT_X11
9938 if (check_connection() == FAIL)
9939 return;
9940# endif
9941
9942 if (serverSendReply(server, reply) < 0)
9943 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009944 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009945 return;
9946 }
9947 rettv->vval.v_number = 0;
9948#else
9949 rettv->vval.v_number = -1;
9950#endif
9951}
9952
9953 static void
9954f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9955{
9956 char_u *r = NULL;
9957
9958#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009959# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009960 r = serverGetVimNames();
9961# else
9962 make_connection();
9963 if (X_DISPLAY != NULL)
9964 r = serverGetVimNames(X_DISPLAY);
9965# endif
9966#endif
9967 rettv->v_type = VAR_STRING;
9968 rettv->vval.v_string = r;
9969}
9970
9971/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009972 * "setbufline()" function
9973 */
9974 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009975f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009976{
9977 linenr_T lnum;
9978 buf_T *buf;
9979
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009980 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009981 if (buf == NULL)
9982 rettv->vval.v_number = 1; /* FAIL */
9983 else
9984 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009985 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009986 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009987 }
9988}
9989
9990/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009991 * "setbufvar()" function
9992 */
9993 static void
9994f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9995{
9996 buf_T *buf;
9997 char_u *varname, *bufvarname;
9998 typval_T *varp;
9999 char_u nbuf[NUMBUFLEN];
10000
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010001 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010002 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010003 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10004 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010005 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010006 varp = &argvars[2];
10007
10008 if (buf != NULL && varname != NULL && varp != NULL)
10009 {
10010 if (*varname == '&')
10011 {
10012 long numval;
10013 char_u *strval;
10014 int error = FALSE;
10015 aco_save_T aco;
10016
10017 /* set curbuf to be our buf, temporarily */
10018 aucmd_prepbuf(&aco, buf);
10019
10020 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010021 numval = (long)tv_get_number_chk(varp, &error);
10022 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010023 if (!error && strval != NULL)
10024 set_option_value(varname, numval, strval, OPT_LOCAL);
10025
10026 /* reset notion of buffer */
10027 aucmd_restbuf(&aco);
10028 }
10029 else
10030 {
10031 buf_T *save_curbuf = curbuf;
10032
Bram Moolenaar964b3742019-05-24 18:54:09 +020010033 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010034 if (bufvarname != NULL)
10035 {
10036 curbuf = buf;
10037 STRCPY(bufvarname, "b:");
10038 STRCPY(bufvarname + 2, varname);
10039 set_var(bufvarname, varp, TRUE);
10040 vim_free(bufvarname);
10041 curbuf = save_curbuf;
10042 }
10043 }
10044 }
10045}
10046
10047 static void
10048f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
10049{
10050 dict_T *d;
10051 dictitem_T *di;
10052 char_u *csearch;
10053
10054 if (argvars[0].v_type != VAR_DICT)
10055 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010056 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010057 return;
10058 }
10059
10060 if ((d = argvars[0].vval.v_dict) != NULL)
10061 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010062 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010063 if (csearch != NULL)
10064 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010065 if (enc_utf8)
10066 {
10067 int pcc[MAX_MCO];
10068 int c = utfc_ptr2char(csearch, pcc);
10069
10070 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
10071 }
10072 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010073 set_last_csearch(PTR2CHAR(csearch),
10074 csearch, MB_PTR2LEN(csearch));
10075 }
10076
10077 di = dict_find(d, (char_u *)"forward", -1);
10078 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010079 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010080 ? FORWARD : BACKWARD);
10081
10082 di = dict_find(d, (char_u *)"until", -1);
10083 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010084 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010085 }
10086}
10087
10088/*
10089 * "setcmdpos()" function
10090 */
10091 static void
10092f_setcmdpos(typval_T *argvars, typval_T *rettv)
10093{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010094 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010095
10096 if (pos >= 0)
10097 rettv->vval.v_number = set_cmdline_pos(pos);
10098}
10099
10100/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +020010101 * "setenv()" function
10102 */
10103 static void
10104f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
10105{
10106 char_u namebuf[NUMBUFLEN];
10107 char_u valbuf[NUMBUFLEN];
10108 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
10109
10110 if (argvars[1].v_type == VAR_SPECIAL
10111 && argvars[1].vval.v_number == VVAL_NULL)
10112 vim_unsetenv(name);
10113 else
10114 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
10115}
10116
10117/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010118 * "setfperm({fname}, {mode})" function
10119 */
10120 static void
10121f_setfperm(typval_T *argvars, typval_T *rettv)
10122{
10123 char_u *fname;
10124 char_u modebuf[NUMBUFLEN];
10125 char_u *mode_str;
10126 int i;
10127 int mask;
10128 int mode = 0;
10129
10130 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010131 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010132 if (fname == NULL)
10133 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010134 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010135 if (mode_str == NULL)
10136 return;
10137 if (STRLEN(mode_str) != 9)
10138 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010139 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010140 return;
10141 }
10142
10143 mask = 1;
10144 for (i = 8; i >= 0; --i)
10145 {
10146 if (mode_str[i] != '-')
10147 mode |= mask;
10148 mask = mask << 1;
10149 }
10150 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
10151}
10152
10153/*
10154 * "setline()" function
10155 */
10156 static void
10157f_setline(typval_T *argvars, typval_T *rettv)
10158{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010159 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010160
Bram Moolenaarca851592018-06-06 21:04:07 +020010161 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010162}
10163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010164/*
10165 * Used by "setqflist()" and "setloclist()" functions
10166 */
10167 static void
10168set_qf_ll_list(
10169 win_T *wp UNUSED,
10170 typval_T *list_arg UNUSED,
10171 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020010172 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010173 typval_T *rettv)
10174{
10175#ifdef FEAT_QUICKFIX
10176 static char *e_invact = N_("E927: Invalid action: '%s'");
10177 char_u *act;
10178 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010179 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010180#endif
10181
10182 rettv->vval.v_number = -1;
10183
10184#ifdef FEAT_QUICKFIX
10185 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010186 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010187 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010188 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010189 else
10190 {
10191 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010192 dict_T *d = NULL;
10193 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010194
10195 if (action_arg->v_type == VAR_STRING)
10196 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010197 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010198 if (act == NULL)
10199 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010200 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10201 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010202 action = *act;
10203 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010204 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010205 }
10206 else if (action_arg->v_type == VAR_UNKNOWN)
10207 action = ' ';
10208 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010209 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010210
Bram Moolenaard823fa92016-08-12 16:29:27 +020010211 if (action_arg->v_type != VAR_UNKNOWN
10212 && what_arg->v_type != VAR_UNKNOWN)
10213 {
10214 if (what_arg->v_type == VAR_DICT)
10215 d = what_arg->vval.v_dict;
10216 else
10217 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010218 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010219 valid_dict = FALSE;
10220 }
10221 }
10222
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010223 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010224 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010225 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10226 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010227 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010228 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010229 }
10230#endif
10231}
10232
10233/*
10234 * "setloclist()" function
10235 */
10236 static void
10237f_setloclist(typval_T *argvars, typval_T *rettv)
10238{
10239 win_T *win;
10240
10241 rettv->vval.v_number = -1;
10242
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010243 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010244 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010245 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010246}
10247
10248/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010249 * "setpos()" function
10250 */
10251 static void
10252f_setpos(typval_T *argvars, typval_T *rettv)
10253{
10254 pos_T pos;
10255 int fnum;
10256 char_u *name;
10257 colnr_T curswant = -1;
10258
10259 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010260 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010261 if (name != NULL)
10262 {
10263 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10264 {
10265 if (--pos.col < 0)
10266 pos.col = 0;
10267 if (name[0] == '.' && name[1] == NUL)
10268 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010269 /* set cursor; "fnum" is ignored */
10270 curwin->w_cursor = pos;
10271 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010272 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010273 curwin->w_curswant = curswant - 1;
10274 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010275 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010276 check_cursor();
10277 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010278 }
10279 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10280 {
10281 /* set mark */
10282 if (setmark_pos(name[1], &pos, fnum) == OK)
10283 rettv->vval.v_number = 0;
10284 }
10285 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010286 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010287 }
10288 }
10289}
10290
10291/*
10292 * "setqflist()" function
10293 */
10294 static void
10295f_setqflist(typval_T *argvars, typval_T *rettv)
10296{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010297 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010298}
10299
10300/*
10301 * "setreg()" function
10302 */
10303 static void
10304f_setreg(typval_T *argvars, typval_T *rettv)
10305{
10306 int regname;
10307 char_u *strregname;
10308 char_u *stropt;
10309 char_u *strval;
10310 int append;
10311 char_u yank_type;
10312 long block_len;
10313
10314 block_len = -1;
10315 yank_type = MAUTO;
10316 append = FALSE;
10317
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010318 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010319 rettv->vval.v_number = 1; /* FAIL is default */
10320
10321 if (strregname == NULL)
10322 return; /* type error; errmsg already given */
10323 regname = *strregname;
10324 if (regname == 0 || regname == '@')
10325 regname = '"';
10326
10327 if (argvars[2].v_type != VAR_UNKNOWN)
10328 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010329 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010330 if (stropt == NULL)
10331 return; /* type error */
10332 for (; *stropt != NUL; ++stropt)
10333 switch (*stropt)
10334 {
10335 case 'a': case 'A': /* append */
10336 append = TRUE;
10337 break;
10338 case 'v': case 'c': /* character-wise selection */
10339 yank_type = MCHAR;
10340 break;
10341 case 'V': case 'l': /* line-wise selection */
10342 yank_type = MLINE;
10343 break;
10344 case 'b': case Ctrl_V: /* block-wise selection */
10345 yank_type = MBLOCK;
10346 if (VIM_ISDIGIT(stropt[1]))
10347 {
10348 ++stropt;
10349 block_len = getdigits(&stropt) - 1;
10350 --stropt;
10351 }
10352 break;
10353 }
10354 }
10355
10356 if (argvars[1].v_type == VAR_LIST)
10357 {
10358 char_u **lstval;
10359 char_u **allocval;
10360 char_u buf[NUMBUFLEN];
10361 char_u **curval;
10362 char_u **curallocval;
10363 list_T *ll = argvars[1].vval.v_list;
10364 listitem_T *li;
10365 int len;
10366
10367 /* If the list is NULL handle like an empty list. */
10368 len = ll == NULL ? 0 : ll->lv_len;
10369
10370 /* First half: use for pointers to result lines; second half: use for
10371 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010372 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010373 if (lstval == NULL)
10374 return;
10375 curval = lstval;
10376 allocval = lstval + len + 2;
10377 curallocval = allocval;
10378
10379 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10380 li = li->li_next)
10381 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010382 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010383 if (strval == NULL)
10384 goto free_lstval;
10385 if (strval == buf)
10386 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010387 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010388 * overwrite the string. */
10389 strval = vim_strsave(buf);
10390 if (strval == NULL)
10391 goto free_lstval;
10392 *curallocval++ = strval;
10393 }
10394 *curval++ = strval;
10395 }
10396 *curval++ = NULL;
10397
10398 write_reg_contents_lst(regname, lstval, -1,
10399 append, yank_type, block_len);
10400free_lstval:
10401 while (curallocval > allocval)
10402 vim_free(*--curallocval);
10403 vim_free(lstval);
10404 }
10405 else
10406 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010407 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010408 if (strval == NULL)
10409 return;
10410 write_reg_contents_ex(regname, strval, -1,
10411 append, yank_type, block_len);
10412 }
10413 rettv->vval.v_number = 0;
10414}
10415
10416/*
10417 * "settabvar()" function
10418 */
10419 static void
10420f_settabvar(typval_T *argvars, typval_T *rettv)
10421{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010422 tabpage_T *save_curtab;
10423 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010424 char_u *varname, *tabvarname;
10425 typval_T *varp;
10426
10427 rettv->vval.v_number = 0;
10428
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010429 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010430 return;
10431
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010432 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10433 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010434 varp = &argvars[2];
10435
Bram Moolenaar4033c552017-09-16 20:54:51 +020010436 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010437 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010438 save_curtab = curtab;
10439 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010440
Bram Moolenaar964b3742019-05-24 18:54:09 +020010441 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010442 if (tabvarname != NULL)
10443 {
10444 STRCPY(tabvarname, "t:");
10445 STRCPY(tabvarname + 2, varname);
10446 set_var(tabvarname, varp, TRUE);
10447 vim_free(tabvarname);
10448 }
10449
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010450 /* Restore current tabpage */
10451 if (valid_tabpage(save_curtab))
10452 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010453 }
10454}
10455
10456/*
10457 * "settabwinvar()" function
10458 */
10459 static void
10460f_settabwinvar(typval_T *argvars, typval_T *rettv)
10461{
10462 setwinvar(argvars, rettv, 1);
10463}
10464
10465/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010466 * "settagstack()" function
10467 */
10468 static void
10469f_settagstack(typval_T *argvars, typval_T *rettv)
10470{
10471 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10472 win_T *wp;
10473 dict_T *d;
10474 int action = 'r';
10475
10476 rettv->vval.v_number = -1;
10477
10478 // first argument: window number or id
10479 wp = find_win_by_nr_or_id(&argvars[0]);
10480 if (wp == NULL)
10481 return;
10482
10483 // second argument: dict with items to set in the tag stack
10484 if (argvars[1].v_type != VAR_DICT)
10485 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010486 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010487 return;
10488 }
10489 d = argvars[1].vval.v_dict;
10490 if (d == NULL)
10491 return;
10492
10493 // third argument: action - 'a' for append and 'r' for replace.
10494 // default is to replace the stack.
10495 if (argvars[2].v_type == VAR_UNKNOWN)
10496 action = 'r';
10497 else if (argvars[2].v_type == VAR_STRING)
10498 {
10499 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010500 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010501 if (actstr == NULL)
10502 return;
10503 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10504 action = *actstr;
10505 else
10506 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010507 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010508 return;
10509 }
10510 }
10511 else
10512 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010513 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010514 return;
10515 }
10516
10517 if (set_tagstack(wp, d, action) == OK)
10518 rettv->vval.v_number = 0;
10519}
10520
10521/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010522 * "setwinvar()" function
10523 */
10524 static void
10525f_setwinvar(typval_T *argvars, typval_T *rettv)
10526{
10527 setwinvar(argvars, rettv, 0);
10528}
10529
10530#ifdef FEAT_CRYPT
10531/*
10532 * "sha256({string})" function
10533 */
10534 static void
10535f_sha256(typval_T *argvars, typval_T *rettv)
10536{
10537 char_u *p;
10538
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010539 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010540 rettv->vval.v_string = vim_strsave(
10541 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10542 rettv->v_type = VAR_STRING;
10543}
10544#endif /* FEAT_CRYPT */
10545
10546/*
10547 * "shellescape({string})" function
10548 */
10549 static void
10550f_shellescape(typval_T *argvars, typval_T *rettv)
10551{
Bram Moolenaar20615522017-06-05 18:46:26 +020010552 int do_special = non_zero_arg(&argvars[1]);
10553
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010554 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010555 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010556 rettv->v_type = VAR_STRING;
10557}
10558
10559/*
10560 * shiftwidth() function
10561 */
10562 static void
10563f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10564{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010565 rettv->vval.v_number = 0;
10566
10567 if (argvars[0].v_type != VAR_UNKNOWN)
10568 {
10569 long col;
10570
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010571 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010572 if (col < 0)
10573 return; // type error; errmsg already given
10574#ifdef FEAT_VARTABS
10575 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10576 return;
10577#endif
10578 }
10579
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010580 rettv->vval.v_number = get_sw_value(curbuf);
10581}
10582
10583/*
10584 * "simplify()" function
10585 */
10586 static void
10587f_simplify(typval_T *argvars, typval_T *rettv)
10588{
10589 char_u *p;
10590
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010591 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010592 rettv->vval.v_string = vim_strsave(p);
10593 simplify_filename(rettv->vval.v_string); /* simplify in place */
10594 rettv->v_type = VAR_STRING;
10595}
10596
10597#ifdef FEAT_FLOAT
10598/*
10599 * "sin()" function
10600 */
10601 static void
10602f_sin(typval_T *argvars, typval_T *rettv)
10603{
10604 float_T f = 0.0;
10605
10606 rettv->v_type = VAR_FLOAT;
10607 if (get_float_arg(argvars, &f) == OK)
10608 rettv->vval.v_float = sin(f);
10609 else
10610 rettv->vval.v_float = 0.0;
10611}
10612
10613/*
10614 * "sinh()" function
10615 */
10616 static void
10617f_sinh(typval_T *argvars, typval_T *rettv)
10618{
10619 float_T f = 0.0;
10620
10621 rettv->v_type = VAR_FLOAT;
10622 if (get_float_arg(argvars, &f) == OK)
10623 rettv->vval.v_float = sinh(f);
10624 else
10625 rettv->vval.v_float = 0.0;
10626}
10627#endif
10628
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010629/*
10630 * "soundfold({word})" function
10631 */
10632 static void
10633f_soundfold(typval_T *argvars, typval_T *rettv)
10634{
10635 char_u *s;
10636
10637 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010638 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010639#ifdef FEAT_SPELL
10640 rettv->vval.v_string = eval_soundfold(s);
10641#else
10642 rettv->vval.v_string = vim_strsave(s);
10643#endif
10644}
10645
10646/*
10647 * "spellbadword()" function
10648 */
10649 static void
10650f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10651{
10652 char_u *word = (char_u *)"";
10653 hlf_T attr = HLF_COUNT;
10654 int len = 0;
10655
10656 if (rettv_list_alloc(rettv) == FAIL)
10657 return;
10658
10659#ifdef FEAT_SPELL
10660 if (argvars[0].v_type == VAR_UNKNOWN)
10661 {
10662 /* Find the start and length of the badly spelled word. */
10663 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10664 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010665 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010666 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010667 curwin->w_set_curswant = TRUE;
10668 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010669 }
10670 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10671 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010672 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010673 int capcol = -1;
10674
10675 if (str != NULL)
10676 {
10677 /* Check the argument for spelling. */
10678 while (*str != NUL)
10679 {
10680 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10681 if (attr != HLF_COUNT)
10682 {
10683 word = str;
10684 break;
10685 }
10686 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010687 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010688 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010689 }
10690 }
10691 }
10692#endif
10693
10694 list_append_string(rettv->vval.v_list, word, len);
10695 list_append_string(rettv->vval.v_list, (char_u *)(
10696 attr == HLF_SPB ? "bad" :
10697 attr == HLF_SPR ? "rare" :
10698 attr == HLF_SPL ? "local" :
10699 attr == HLF_SPC ? "caps" :
10700 ""), -1);
10701}
10702
10703/*
10704 * "spellsuggest()" function
10705 */
10706 static void
10707f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10708{
10709#ifdef FEAT_SPELL
10710 char_u *str;
10711 int typeerr = FALSE;
10712 int maxcount;
10713 garray_T ga;
10714 int i;
10715 listitem_T *li;
10716 int need_capital = FALSE;
10717#endif
10718
10719 if (rettv_list_alloc(rettv) == FAIL)
10720 return;
10721
10722#ifdef FEAT_SPELL
10723 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10724 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010725 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010726 if (argvars[1].v_type != VAR_UNKNOWN)
10727 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010728 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010729 if (maxcount <= 0)
10730 return;
10731 if (argvars[2].v_type != VAR_UNKNOWN)
10732 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010733 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010734 if (typeerr)
10735 return;
10736 }
10737 }
10738 else
10739 maxcount = 25;
10740
10741 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10742
10743 for (i = 0; i < ga.ga_len; ++i)
10744 {
10745 str = ((char_u **)ga.ga_data)[i];
10746
10747 li = listitem_alloc();
10748 if (li == NULL)
10749 vim_free(str);
10750 else
10751 {
10752 li->li_tv.v_type = VAR_STRING;
10753 li->li_tv.v_lock = 0;
10754 li->li_tv.vval.v_string = str;
10755 list_append(rettv->vval.v_list, li);
10756 }
10757 }
10758 ga_clear(&ga);
10759 }
10760#endif
10761}
10762
10763 static void
10764f_split(typval_T *argvars, typval_T *rettv)
10765{
10766 char_u *str;
10767 char_u *end;
10768 char_u *pat = NULL;
10769 regmatch_T regmatch;
10770 char_u patbuf[NUMBUFLEN];
10771 char_u *save_cpo;
10772 int match;
10773 colnr_T col = 0;
10774 int keepempty = FALSE;
10775 int typeerr = FALSE;
10776
10777 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10778 save_cpo = p_cpo;
10779 p_cpo = (char_u *)"";
10780
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010781 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782 if (argvars[1].v_type != VAR_UNKNOWN)
10783 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010784 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010785 if (pat == NULL)
10786 typeerr = TRUE;
10787 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010788 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010789 }
10790 if (pat == NULL || *pat == NUL)
10791 pat = (char_u *)"[\\x01- ]\\+";
10792
10793 if (rettv_list_alloc(rettv) == FAIL)
10794 return;
10795 if (typeerr)
10796 return;
10797
10798 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10799 if (regmatch.regprog != NULL)
10800 {
10801 regmatch.rm_ic = FALSE;
10802 while (*str != NUL || keepempty)
10803 {
10804 if (*str == NUL)
10805 match = FALSE; /* empty item at the end */
10806 else
10807 match = vim_regexec_nl(&regmatch, str, col);
10808 if (match)
10809 end = regmatch.startp[0];
10810 else
10811 end = str + STRLEN(str);
10812 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10813 && *str != NUL && match && end < regmatch.endp[0]))
10814 {
10815 if (list_append_string(rettv->vval.v_list, str,
10816 (int)(end - str)) == FAIL)
10817 break;
10818 }
10819 if (!match)
10820 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010821 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010822 if (regmatch.endp[0] > str)
10823 col = 0;
10824 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010825 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010826 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010827 str = regmatch.endp[0];
10828 }
10829
10830 vim_regfree(regmatch.regprog);
10831 }
10832
10833 p_cpo = save_cpo;
10834}
10835
10836#ifdef FEAT_FLOAT
10837/*
10838 * "sqrt()" function
10839 */
10840 static void
10841f_sqrt(typval_T *argvars, typval_T *rettv)
10842{
10843 float_T f = 0.0;
10844
10845 rettv->v_type = VAR_FLOAT;
10846 if (get_float_arg(argvars, &f) == OK)
10847 rettv->vval.v_float = sqrt(f);
10848 else
10849 rettv->vval.v_float = 0.0;
10850}
10851
10852/*
10853 * "str2float()" function
10854 */
10855 static void
10856f_str2float(typval_T *argvars, typval_T *rettv)
10857{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010858 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010859 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010860
Bram Moolenaar08243d22017-01-10 16:12:29 +010010861 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010862 p = skipwhite(p + 1);
10863 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010864 if (isneg)
10865 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010866 rettv->v_type = VAR_FLOAT;
10867}
10868#endif
10869
10870/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010871 * "str2list()" function
10872 */
10873 static void
10874f_str2list(typval_T *argvars, typval_T *rettv)
10875{
10876 char_u *p;
10877 int utf8 = FALSE;
10878
10879 if (rettv_list_alloc(rettv) == FAIL)
10880 return;
10881
10882 if (argvars[1].v_type != VAR_UNKNOWN)
10883 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10884
10885 p = tv_get_string(&argvars[0]);
10886
10887 if (has_mbyte || utf8)
10888 {
10889 int (*ptr2len)(char_u *);
10890 int (*ptr2char)(char_u *);
10891
10892 if (utf8 || enc_utf8)
10893 {
10894 ptr2len = utf_ptr2len;
10895 ptr2char = utf_ptr2char;
10896 }
10897 else
10898 {
10899 ptr2len = mb_ptr2len;
10900 ptr2char = mb_ptr2char;
10901 }
10902
10903 for ( ; *p != NUL; p += (*ptr2len)(p))
10904 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10905 }
10906 else
10907 for ( ; *p != NUL; ++p)
10908 list_append_number(rettv->vval.v_list, *p);
10909}
10910
10911/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010912 * "str2nr()" function
10913 */
10914 static void
10915f_str2nr(typval_T *argvars, typval_T *rettv)
10916{
10917 int base = 10;
10918 char_u *p;
10919 varnumber_T n;
10920 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010921 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010922
10923 if (argvars[1].v_type != VAR_UNKNOWN)
10924 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010925 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010926 if (base != 2 && base != 8 && base != 10 && base != 16)
10927 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010928 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010929 return;
10930 }
10931 }
10932
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010933 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010934 isneg = (*p == '-');
10935 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010936 p = skipwhite(p + 1);
10937 switch (base)
10938 {
10939 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10940 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10941 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10942 default: what = 0;
10943 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010944 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10945 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010946 if (isneg)
10947 rettv->vval.v_number = -n;
10948 else
10949 rettv->vval.v_number = n;
10950
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010951}
10952
10953#ifdef HAVE_STRFTIME
10954/*
10955 * "strftime({format}[, {time}])" function
10956 */
10957 static void
10958f_strftime(typval_T *argvars, typval_T *rettv)
10959{
10960 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010961 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010962 struct tm *curtime;
10963 time_t seconds;
10964 char_u *p;
10965
10966 rettv->v_type = VAR_STRING;
10967
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010968 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010969 if (argvars[1].v_type == VAR_UNKNOWN)
10970 seconds = time(NULL);
10971 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010972 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010973 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010974 /* MSVC returns NULL for an invalid value of seconds. */
10975 if (curtime == NULL)
10976 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10977 else
10978 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010979 vimconv_T conv;
10980 char_u *enc;
10981
10982 conv.vc_type = CONV_NONE;
10983 enc = enc_locale();
10984 convert_setup(&conv, p_enc, enc);
10985 if (conv.vc_type != CONV_NONE)
10986 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010987 if (p != NULL)
10988 (void)strftime((char *)result_buf, sizeof(result_buf),
10989 (char *)p, curtime);
10990 else
10991 result_buf[0] = NUL;
10992
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010993 if (conv.vc_type != CONV_NONE)
10994 vim_free(p);
10995 convert_setup(&conv, enc, p_enc);
10996 if (conv.vc_type != CONV_NONE)
10997 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10998 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010999 rettv->vval.v_string = vim_strsave(result_buf);
11000
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011001 /* Release conversion descriptors */
11002 convert_setup(&conv, NULL, NULL);
11003 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011004 }
11005}
11006#endif
11007
11008/*
11009 * "strgetchar()" function
11010 */
11011 static void
11012f_strgetchar(typval_T *argvars, typval_T *rettv)
11013{
11014 char_u *str;
11015 int len;
11016 int error = FALSE;
11017 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010011018 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011019
11020 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011021 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011022 if (str == NULL)
11023 return;
11024 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011025 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011026 if (error)
11027 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011028
Bram Moolenaar13505972019-01-24 15:04:48 +010011029 while (charidx >= 0 && byteidx < len)
11030 {
11031 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011032 {
Bram Moolenaar13505972019-01-24 15:04:48 +010011033 rettv->vval.v_number = mb_ptr2char(str + byteidx);
11034 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011035 }
Bram Moolenaar13505972019-01-24 15:04:48 +010011036 --charidx;
11037 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011038 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011039}
11040
11041/*
11042 * "stridx()" function
11043 */
11044 static void
11045f_stridx(typval_T *argvars, typval_T *rettv)
11046{
11047 char_u buf[NUMBUFLEN];
11048 char_u *needle;
11049 char_u *haystack;
11050 char_u *save_haystack;
11051 char_u *pos;
11052 int start_idx;
11053
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011054 needle = tv_get_string_chk(&argvars[1]);
11055 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011056 rettv->vval.v_number = -1;
11057 if (needle == NULL || haystack == NULL)
11058 return; /* type error; errmsg already given */
11059
11060 if (argvars[2].v_type != VAR_UNKNOWN)
11061 {
11062 int error = FALSE;
11063
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011064 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011065 if (error || start_idx >= (int)STRLEN(haystack))
11066 return;
11067 if (start_idx >= 0)
11068 haystack += start_idx;
11069 }
11070
11071 pos = (char_u *)strstr((char *)haystack, (char *)needle);
11072 if (pos != NULL)
11073 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
11074}
11075
11076/*
11077 * "string()" function
11078 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010011079 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080f_string(typval_T *argvars, typval_T *rettv)
11081{
11082 char_u *tofree;
11083 char_u numbuf[NUMBUFLEN];
11084
11085 rettv->v_type = VAR_STRING;
11086 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
11087 get_copyID());
11088 /* Make a copy if we have a value but it's not in allocated memory. */
11089 if (rettv->vval.v_string != NULL && tofree == NULL)
11090 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
11091}
11092
11093/*
11094 * "strlen()" function
11095 */
11096 static void
11097f_strlen(typval_T *argvars, typval_T *rettv)
11098{
11099 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011100 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011101}
11102
11103/*
11104 * "strchars()" function
11105 */
11106 static void
11107f_strchars(typval_T *argvars, typval_T *rettv)
11108{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011109 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011110 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011111 varnumber_T len = 0;
11112 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011113
11114 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011115 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011116 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011117 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011118 else
11119 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011120 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
11121 while (*s != NUL)
11122 {
11123 func_mb_ptr2char_adv(&s);
11124 ++len;
11125 }
11126 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011127 }
11128}
11129
11130/*
11131 * "strdisplaywidth()" function
11132 */
11133 static void
11134f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
11135{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011136 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011137 int col = 0;
11138
11139 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011140 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011141
11142 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
11143}
11144
11145/*
11146 * "strwidth()" function
11147 */
11148 static void
11149f_strwidth(typval_T *argvars, typval_T *rettv)
11150{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011151 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152
Bram Moolenaar13505972019-01-24 15:04:48 +010011153 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011154}
11155
11156/*
11157 * "strcharpart()" function
11158 */
11159 static void
11160f_strcharpart(typval_T *argvars, typval_T *rettv)
11161{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011162 char_u *p;
11163 int nchar;
11164 int nbyte = 0;
11165 int charlen;
11166 int len = 0;
11167 int slen;
11168 int error = FALSE;
11169
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011170 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011171 slen = (int)STRLEN(p);
11172
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011173 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011174 if (!error)
11175 {
11176 if (nchar > 0)
11177 while (nchar > 0 && nbyte < slen)
11178 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011179 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011180 --nchar;
11181 }
11182 else
11183 nbyte = nchar;
11184 if (argvars[2].v_type != VAR_UNKNOWN)
11185 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011186 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011187 while (charlen > 0 && nbyte + len < slen)
11188 {
11189 int off = nbyte + len;
11190
11191 if (off < 0)
11192 len += 1;
11193 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011194 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011195 --charlen;
11196 }
11197 }
11198 else
11199 len = slen - nbyte; /* default: all bytes that are available. */
11200 }
11201
11202 /*
11203 * Only return the overlap between the specified part and the actual
11204 * string.
11205 */
11206 if (nbyte < 0)
11207 {
11208 len += nbyte;
11209 nbyte = 0;
11210 }
11211 else if (nbyte > slen)
11212 nbyte = slen;
11213 if (len < 0)
11214 len = 0;
11215 else if (nbyte + len > slen)
11216 len = slen - nbyte;
11217
11218 rettv->v_type = VAR_STRING;
11219 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011220}
11221
11222/*
11223 * "strpart()" function
11224 */
11225 static void
11226f_strpart(typval_T *argvars, typval_T *rettv)
11227{
11228 char_u *p;
11229 int n;
11230 int len;
11231 int slen;
11232 int error = FALSE;
11233
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011234 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011235 slen = (int)STRLEN(p);
11236
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011237 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011238 if (error)
11239 len = 0;
11240 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011241 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011242 else
11243 len = slen - n; /* default len: all bytes that are available. */
11244
11245 /*
11246 * Only return the overlap between the specified part and the actual
11247 * string.
11248 */
11249 if (n < 0)
11250 {
11251 len += n;
11252 n = 0;
11253 }
11254 else if (n > slen)
11255 n = slen;
11256 if (len < 0)
11257 len = 0;
11258 else if (n + len > slen)
11259 len = slen - n;
11260
11261 rettv->v_type = VAR_STRING;
11262 rettv->vval.v_string = vim_strnsave(p + n, len);
11263}
11264
11265/*
11266 * "strridx()" function
11267 */
11268 static void
11269f_strridx(typval_T *argvars, typval_T *rettv)
11270{
11271 char_u buf[NUMBUFLEN];
11272 char_u *needle;
11273 char_u *haystack;
11274 char_u *rest;
11275 char_u *lastmatch = NULL;
11276 int haystack_len, end_idx;
11277
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011278 needle = tv_get_string_chk(&argvars[1]);
11279 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011280
11281 rettv->vval.v_number = -1;
11282 if (needle == NULL || haystack == NULL)
11283 return; /* type error; errmsg already given */
11284
11285 haystack_len = (int)STRLEN(haystack);
11286 if (argvars[2].v_type != VAR_UNKNOWN)
11287 {
11288 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011289 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011290 if (end_idx < 0)
11291 return; /* can never find a match */
11292 }
11293 else
11294 end_idx = haystack_len;
11295
11296 if (*needle == NUL)
11297 {
11298 /* Empty string matches past the end. */
11299 lastmatch = haystack + end_idx;
11300 }
11301 else
11302 {
11303 for (rest = haystack; *rest != '\0'; ++rest)
11304 {
11305 rest = (char_u *)strstr((char *)rest, (char *)needle);
11306 if (rest == NULL || rest > haystack + end_idx)
11307 break;
11308 lastmatch = rest;
11309 }
11310 }
11311
11312 if (lastmatch == NULL)
11313 rettv->vval.v_number = -1;
11314 else
11315 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11316}
11317
11318/*
11319 * "strtrans()" function
11320 */
11321 static void
11322f_strtrans(typval_T *argvars, typval_T *rettv)
11323{
11324 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011325 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011326}
11327
11328/*
11329 * "submatch()" function
11330 */
11331 static void
11332f_submatch(typval_T *argvars, typval_T *rettv)
11333{
11334 int error = FALSE;
11335 int no;
11336 int retList = 0;
11337
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011338 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011339 if (error)
11340 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011341 if (no < 0 || no >= NSUBEXP)
11342 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011343 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011344 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011345 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011346 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011347 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011348 if (error)
11349 return;
11350
11351 if (retList == 0)
11352 {
11353 rettv->v_type = VAR_STRING;
11354 rettv->vval.v_string = reg_submatch(no);
11355 }
11356 else
11357 {
11358 rettv->v_type = VAR_LIST;
11359 rettv->vval.v_list = reg_submatch_list(no);
11360 }
11361}
11362
11363/*
11364 * "substitute()" function
11365 */
11366 static void
11367f_substitute(typval_T *argvars, typval_T *rettv)
11368{
11369 char_u patbuf[NUMBUFLEN];
11370 char_u subbuf[NUMBUFLEN];
11371 char_u flagsbuf[NUMBUFLEN];
11372
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011373 char_u *str = tv_get_string_chk(&argvars[0]);
11374 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011375 char_u *sub = NULL;
11376 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011377 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011378
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011379 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11380 expr = &argvars[2];
11381 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011382 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011383
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011385 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11386 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011387 rettv->vval.v_string = NULL;
11388 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011389 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011390}
11391
11392/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011393 * "swapinfo(swap_filename)" function
11394 */
11395 static void
11396f_swapinfo(typval_T *argvars, typval_T *rettv)
11397{
11398 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011399 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011400}
11401
11402/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011403 * "swapname(expr)" function
11404 */
11405 static void
11406f_swapname(typval_T *argvars, typval_T *rettv)
11407{
11408 buf_T *buf;
11409
11410 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011411 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011412 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11413 || buf->b_ml.ml_mfp->mf_fname == NULL)
11414 rettv->vval.v_string = NULL;
11415 else
11416 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11417}
11418
11419/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011420 * "synID(lnum, col, trans)" function
11421 */
11422 static void
11423f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11424{
11425 int id = 0;
11426#ifdef FEAT_SYN_HL
11427 linenr_T lnum;
11428 colnr_T col;
11429 int trans;
11430 int transerr = FALSE;
11431
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011432 lnum = tv_get_lnum(argvars); /* -1 on type error */
11433 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11434 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011435
11436 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11437 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11438 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11439#endif
11440
11441 rettv->vval.v_number = id;
11442}
11443
11444/*
11445 * "synIDattr(id, what [, mode])" function
11446 */
11447 static void
11448f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11449{
11450 char_u *p = NULL;
11451#ifdef FEAT_SYN_HL
11452 int id;
11453 char_u *what;
11454 char_u *mode;
11455 char_u modebuf[NUMBUFLEN];
11456 int modec;
11457
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011458 id = (int)tv_get_number(&argvars[0]);
11459 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011460 if (argvars[2].v_type != VAR_UNKNOWN)
11461 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011462 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011463 modec = TOLOWER_ASC(mode[0]);
11464 if (modec != 't' && modec != 'c' && modec != 'g')
11465 modec = 0; /* replace invalid with current */
11466 }
11467 else
11468 {
11469#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11470 if (USE_24BIT)
11471 modec = 'g';
11472 else
11473#endif
11474 if (t_colors > 1)
11475 modec = 'c';
11476 else
11477 modec = 't';
11478 }
11479
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011480 switch (TOLOWER_ASC(what[0]))
11481 {
11482 case 'b':
11483 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11484 p = highlight_color(id, what, modec);
11485 else /* bold */
11486 p = highlight_has_attr(id, HL_BOLD, modec);
11487 break;
11488
11489 case 'f': /* fg[#] or font */
11490 p = highlight_color(id, what, modec);
11491 break;
11492
11493 case 'i':
11494 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11495 p = highlight_has_attr(id, HL_INVERSE, modec);
11496 else /* italic */
11497 p = highlight_has_attr(id, HL_ITALIC, modec);
11498 break;
11499
11500 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011501 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011502 break;
11503
11504 case 'r': /* reverse */
11505 p = highlight_has_attr(id, HL_INVERSE, modec);
11506 break;
11507
11508 case 's':
11509 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11510 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011511 /* strikeout */
11512 else if (TOLOWER_ASC(what[1]) == 't' &&
11513 TOLOWER_ASC(what[2]) == 'r')
11514 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011515 else /* standout */
11516 p = highlight_has_attr(id, HL_STANDOUT, modec);
11517 break;
11518
11519 case 'u':
11520 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11521 /* underline */
11522 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11523 else
11524 /* undercurl */
11525 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11526 break;
11527 }
11528
11529 if (p != NULL)
11530 p = vim_strsave(p);
11531#endif
11532 rettv->v_type = VAR_STRING;
11533 rettv->vval.v_string = p;
11534}
11535
11536/*
11537 * "synIDtrans(id)" function
11538 */
11539 static void
11540f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11541{
11542 int id;
11543
11544#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011545 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011546
11547 if (id > 0)
11548 id = syn_get_final_id(id);
11549 else
11550#endif
11551 id = 0;
11552
11553 rettv->vval.v_number = id;
11554}
11555
11556/*
11557 * "synconcealed(lnum, col)" function
11558 */
11559 static void
11560f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11561{
11562#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11563 linenr_T lnum;
11564 colnr_T col;
11565 int syntax_flags = 0;
11566 int cchar;
11567 int matchid = 0;
11568 char_u str[NUMBUFLEN];
11569#endif
11570
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011571 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011572
11573#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011574 lnum = tv_get_lnum(argvars); /* -1 on type error */
11575 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011576
11577 vim_memset(str, NUL, sizeof(str));
11578
11579 if (rettv_list_alloc(rettv) != FAIL)
11580 {
11581 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11582 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11583 && curwin->w_p_cole > 0)
11584 {
11585 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11586 syntax_flags = get_syntax_info(&matchid);
11587
11588 /* get the conceal character */
11589 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11590 {
11591 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011592 if (cchar == NUL && curwin->w_p_cole == 1)
11593 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011594 if (cchar != NUL)
11595 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011596 if (has_mbyte)
11597 (*mb_char2bytes)(cchar, str);
11598 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011599 str[0] = cchar;
11600 }
11601 }
11602 }
11603
11604 list_append_number(rettv->vval.v_list,
11605 (syntax_flags & HL_CONCEAL) != 0);
11606 /* -1 to auto-determine strlen */
11607 list_append_string(rettv->vval.v_list, str, -1);
11608 list_append_number(rettv->vval.v_list, matchid);
11609 }
11610#endif
11611}
11612
11613/*
11614 * "synstack(lnum, col)" function
11615 */
11616 static void
11617f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11618{
11619#ifdef FEAT_SYN_HL
11620 linenr_T lnum;
11621 colnr_T col;
11622 int i;
11623 int id;
11624#endif
11625
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011626 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011627
11628#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011629 lnum = tv_get_lnum(argvars); /* -1 on type error */
11630 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011631
11632 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11633 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11634 && rettv_list_alloc(rettv) != FAIL)
11635 {
11636 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11637 for (i = 0; ; ++i)
11638 {
11639 id = syn_get_stack_item(i);
11640 if (id < 0)
11641 break;
11642 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11643 break;
11644 }
11645 }
11646#endif
11647}
11648
11649 static void
11650get_cmd_output_as_rettv(
11651 typval_T *argvars,
11652 typval_T *rettv,
11653 int retlist)
11654{
11655 char_u *res = NULL;
11656 char_u *p;
11657 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011658 int err = FALSE;
11659 FILE *fd;
11660 list_T *list = NULL;
11661 int flags = SHELL_SILENT;
11662
11663 rettv->v_type = VAR_STRING;
11664 rettv->vval.v_string = NULL;
11665 if (check_restricted() || check_secure())
11666 goto errret;
11667
11668 if (argvars[1].v_type != VAR_UNKNOWN)
11669 {
11670 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011671 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011672 * command.
11673 */
11674 if ((infile = vim_tempname('i', TRUE)) == NULL)
11675 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011676 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011677 goto errret;
11678 }
11679
11680 fd = mch_fopen((char *)infile, WRITEBIN);
11681 if (fd == NULL)
11682 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011683 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011684 goto errret;
11685 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011686 if (argvars[1].v_type == VAR_NUMBER)
11687 {
11688 linenr_T lnum;
11689 buf_T *buf;
11690
11691 buf = buflist_findnr(argvars[1].vval.v_number);
11692 if (buf == NULL)
11693 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011694 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011695 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011696 goto errret;
11697 }
11698
11699 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11700 {
11701 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11702 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11703 {
11704 err = TRUE;
11705 break;
11706 }
11707 if (putc(NL, fd) == EOF)
11708 {
11709 err = TRUE;
11710 break;
11711 }
11712 }
11713 }
11714 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011715 {
11716 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11717 err = TRUE;
11718 }
11719 else
11720 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011721 size_t len;
11722 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011723
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011724 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011725 if (p == NULL)
11726 {
11727 fclose(fd);
11728 goto errret; /* type error; errmsg already given */
11729 }
11730 len = STRLEN(p);
11731 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11732 err = TRUE;
11733 }
11734 if (fclose(fd) != 0)
11735 err = TRUE;
11736 if (err)
11737 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011738 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011739 goto errret;
11740 }
11741 }
11742
11743 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11744 * echoes typeahead, that messes up the display. */
11745 if (!msg_silent)
11746 flags += SHELL_COOKED;
11747
11748 if (retlist)
11749 {
11750 int len;
11751 listitem_T *li;
11752 char_u *s = NULL;
11753 char_u *start;
11754 char_u *end;
11755 int i;
11756
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011757 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011758 if (res == NULL)
11759 goto errret;
11760
11761 list = list_alloc();
11762 if (list == NULL)
11763 goto errret;
11764
11765 for (i = 0; i < len; ++i)
11766 {
11767 start = res + i;
11768 while (i < len && res[i] != NL)
11769 ++i;
11770 end = res + i;
11771
Bram Moolenaar964b3742019-05-24 18:54:09 +020011772 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011773 if (s == NULL)
11774 goto errret;
11775
11776 for (p = s; start < end; ++p, ++start)
11777 *p = *start == NUL ? NL : *start;
11778 *p = NUL;
11779
11780 li = listitem_alloc();
11781 if (li == NULL)
11782 {
11783 vim_free(s);
11784 goto errret;
11785 }
11786 li->li_tv.v_type = VAR_STRING;
11787 li->li_tv.v_lock = 0;
11788 li->li_tv.vval.v_string = s;
11789 list_append(list, li);
11790 }
11791
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011792 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011793 list = NULL;
11794 }
11795 else
11796 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011797 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011798#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011799 /* translate <CR><NL> into <NL> */
11800 if (res != NULL)
11801 {
11802 char_u *s, *d;
11803
11804 d = res;
11805 for (s = res; *s; ++s)
11806 {
11807 if (s[0] == CAR && s[1] == NL)
11808 ++s;
11809 *d++ = *s;
11810 }
11811 *d = NUL;
11812 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011813#endif
11814 rettv->vval.v_string = res;
11815 res = NULL;
11816 }
11817
11818errret:
11819 if (infile != NULL)
11820 {
11821 mch_remove(infile);
11822 vim_free(infile);
11823 }
11824 if (res != NULL)
11825 vim_free(res);
11826 if (list != NULL)
11827 list_free(list);
11828}
11829
11830/*
11831 * "system()" function
11832 */
11833 static void
11834f_system(typval_T *argvars, typval_T *rettv)
11835{
11836 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11837}
11838
11839/*
11840 * "systemlist()" function
11841 */
11842 static void
11843f_systemlist(typval_T *argvars, typval_T *rettv)
11844{
11845 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11846}
11847
11848/*
11849 * "tabpagebuflist()" function
11850 */
11851 static void
11852f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11853{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011854 tabpage_T *tp;
11855 win_T *wp = NULL;
11856
11857 if (argvars[0].v_type == VAR_UNKNOWN)
11858 wp = firstwin;
11859 else
11860 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011861 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011862 if (tp != NULL)
11863 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11864 }
11865 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11866 {
11867 for (; wp != NULL; wp = wp->w_next)
11868 if (list_append_number(rettv->vval.v_list,
11869 wp->w_buffer->b_fnum) == FAIL)
11870 break;
11871 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011872}
11873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011874/*
11875 * "tabpagenr()" function
11876 */
11877 static void
11878f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11879{
11880 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011881 char_u *arg;
11882
11883 if (argvars[0].v_type != VAR_UNKNOWN)
11884 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011885 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011886 nr = 0;
11887 if (arg != NULL)
11888 {
11889 if (STRCMP(arg, "$") == 0)
11890 nr = tabpage_index(NULL) - 1;
11891 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011892 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011893 }
11894 }
11895 else
11896 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011897 rettv->vval.v_number = nr;
11898}
11899
11900
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011901/*
11902 * Common code for tabpagewinnr() and winnr().
11903 */
11904 static int
11905get_winnr(tabpage_T *tp, typval_T *argvar)
11906{
11907 win_T *twin;
11908 int nr = 1;
11909 win_T *wp;
11910 char_u *arg;
11911
11912 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11913 if (argvar->v_type != VAR_UNKNOWN)
11914 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011915 int invalid_arg = FALSE;
11916
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011917 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011918 if (arg == NULL)
11919 nr = 0; /* type error; errmsg already given */
11920 else if (STRCMP(arg, "$") == 0)
11921 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11922 else if (STRCMP(arg, "#") == 0)
11923 {
11924 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11925 if (twin == NULL)
11926 nr = 0;
11927 }
11928 else
11929 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011930 long count;
11931 char_u *endp;
11932
11933 // Extract the window count (if specified). e.g. winnr('3j')
11934 count = strtol((char *)arg, (char **)&endp, 10);
11935 if (count <= 0)
11936 count = 1; // if count is not specified, default to 1
11937 if (endp != NULL && *endp != '\0')
11938 {
11939 if (STRCMP(endp, "j") == 0)
11940 twin = win_vert_neighbor(tp, twin, FALSE, count);
11941 else if (STRCMP(endp, "k") == 0)
11942 twin = win_vert_neighbor(tp, twin, TRUE, count);
11943 else if (STRCMP(endp, "h") == 0)
11944 twin = win_horz_neighbor(tp, twin, TRUE, count);
11945 else if (STRCMP(endp, "l") == 0)
11946 twin = win_horz_neighbor(tp, twin, FALSE, count);
11947 else
11948 invalid_arg = TRUE;
11949 }
11950 else
11951 invalid_arg = TRUE;
11952 }
11953
11954 if (invalid_arg)
11955 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011956 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011957 nr = 0;
11958 }
11959 }
11960
11961 if (nr > 0)
11962 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11963 wp != twin; wp = wp->w_next)
11964 {
11965 if (wp == NULL)
11966 {
11967 /* didn't find it in this tabpage */
11968 nr = 0;
11969 break;
11970 }
11971 ++nr;
11972 }
11973 return nr;
11974}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011975
11976/*
11977 * "tabpagewinnr()" function
11978 */
11979 static void
11980f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11981{
11982 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011983 tabpage_T *tp;
11984
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011985 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011986 if (tp == NULL)
11987 nr = 0;
11988 else
11989 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011990 rettv->vval.v_number = nr;
11991}
11992
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011993/*
11994 * "tagfiles()" function
11995 */
11996 static void
11997f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11998{
11999 char_u *fname;
12000 tagname_T tn;
12001 int first;
12002
12003 if (rettv_list_alloc(rettv) == FAIL)
12004 return;
12005 fname = alloc(MAXPATHL);
12006 if (fname == NULL)
12007 return;
12008
12009 for (first = TRUE; ; first = FALSE)
12010 if (get_tagfname(&tn, first, fname) == FAIL
12011 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
12012 break;
12013 tagname_free(&tn);
12014 vim_free(fname);
12015}
12016
12017/*
12018 * "taglist()" function
12019 */
12020 static void
12021f_taglist(typval_T *argvars, typval_T *rettv)
12022{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012023 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012024 char_u *tag_pattern;
12025
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012026 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012027
12028 rettv->vval.v_number = FALSE;
12029 if (*tag_pattern == NUL)
12030 return;
12031
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012032 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012033 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012034 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010012035 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012036}
12037
12038/*
12039 * "tempname()" function
12040 */
12041 static void
12042f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
12043{
12044 static int x = 'A';
12045
12046 rettv->v_type = VAR_STRING;
12047 rettv->vval.v_string = vim_tempname(x, FALSE);
12048
12049 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
12050 * names. Skip 'I' and 'O', they are used for shell redirection. */
12051 do
12052 {
12053 if (x == 'Z')
12054 x = '0';
12055 else if (x == '9')
12056 x = 'A';
12057 else
12058 {
12059#ifdef EBCDIC
12060 if (x == 'I')
12061 x = 'J';
12062 else if (x == 'R')
12063 x = 'S';
12064 else
12065#endif
12066 ++x;
12067 }
12068 } while (x == 'I' || x == 'O');
12069}
12070
12071#ifdef FEAT_FLOAT
12072/*
12073 * "tan()" function
12074 */
12075 static void
12076f_tan(typval_T *argvars, typval_T *rettv)
12077{
12078 float_T f = 0.0;
12079
12080 rettv->v_type = VAR_FLOAT;
12081 if (get_float_arg(argvars, &f) == OK)
12082 rettv->vval.v_float = tan(f);
12083 else
12084 rettv->vval.v_float = 0.0;
12085}
12086
12087/*
12088 * "tanh()" function
12089 */
12090 static void
12091f_tanh(typval_T *argvars, typval_T *rettv)
12092{
12093 float_T f = 0.0;
12094
12095 rettv->v_type = VAR_FLOAT;
12096 if (get_float_arg(argvars, &f) == OK)
12097 rettv->vval.v_float = tanh(f);
12098 else
12099 rettv->vval.v_float = 0.0;
12100}
12101#endif
12102
12103/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012104 * Get a callback from "arg". It can be a Funcref or a function name.
12105 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012106 * "cb_name" is not allocated.
12107 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012108 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012109 callback_T
12110get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012111{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012112 callback_T res;
12113
12114 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012115 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
12116 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012117 res.cb_partial = arg->vval.v_partial;
12118 ++res.cb_partial->pt_refcount;
12119 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012120 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012121 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012122 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012123 res.cb_partial = NULL;
12124 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
12125 {
12126 // Note that we don't make a copy of the string.
12127 res.cb_name = arg->vval.v_string;
12128 func_ref(res.cb_name);
12129 }
12130 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
12131 {
12132 res.cb_name = (char_u *)"";
12133 }
12134 else
12135 {
12136 emsg(_("E921: Invalid callback argument"));
12137 res.cb_name = NULL;
12138 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012139 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012140 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012141}
12142
12143/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012144 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012145 */
12146 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012147put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012148{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012149 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012150 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012151 tv->v_type = VAR_PARTIAL;
12152 tv->vval.v_partial = cb->cb_partial;
12153 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012154 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012155 else
12156 {
12157 tv->v_type = VAR_FUNC;
12158 tv->vval.v_string = vim_strsave(cb->cb_name);
12159 func_ref(cb->cb_name);
12160 }
12161}
12162
12163/*
12164 * Make a copy of "src" into "dest", allocating the function name if needed,
12165 * without incrementing the refcount.
12166 */
12167 void
12168set_callback(callback_T *dest, callback_T *src)
12169{
12170 if (src->cb_partial == NULL)
12171 {
12172 // just a function name, make a copy
12173 dest->cb_name = vim_strsave(src->cb_name);
12174 dest->cb_free_name = TRUE;
12175 }
12176 else
12177 {
12178 // cb_name is a pointer into cb_partial
12179 dest->cb_name = src->cb_name;
12180 dest->cb_free_name = FALSE;
12181 }
12182 dest->cb_partial = src->cb_partial;
12183}
12184
12185/*
12186 * Unref/free "callback" returned by get_callback() or set_callback().
12187 */
12188 void
12189free_callback(callback_T *callback)
12190{
12191 if (callback->cb_partial != NULL)
12192 {
12193 partial_unref(callback->cb_partial);
12194 callback->cb_partial = NULL;
12195 }
12196 else if (callback->cb_name != NULL)
12197 func_unref(callback->cb_name);
12198 if (callback->cb_free_name)
12199 {
12200 vim_free(callback->cb_name);
12201 callback->cb_free_name = FALSE;
12202 }
12203 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012204}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012205
12206#ifdef FEAT_TIMERS
12207/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012208 * "timer_info([timer])" function
12209 */
12210 static void
12211f_timer_info(typval_T *argvars, typval_T *rettv)
12212{
12213 timer_T *timer = NULL;
12214
12215 if (rettv_list_alloc(rettv) != OK)
12216 return;
12217 if (argvars[0].v_type != VAR_UNKNOWN)
12218 {
12219 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012220 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012221 else
12222 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012223 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012224 if (timer != NULL)
12225 add_timer_info(rettv, timer);
12226 }
12227 }
12228 else
12229 add_timer_info_all(rettv);
12230}
12231
12232/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012233 * "timer_pause(timer, paused)" function
12234 */
12235 static void
12236f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12237{
12238 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012239 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012240
12241 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012242 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012243 else
12244 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012245 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012246 if (timer != NULL)
12247 timer->tr_paused = paused;
12248 }
12249}
12250
12251/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012252 * "timer_start(time, callback [, options])" function
12253 */
12254 static void
12255f_timer_start(typval_T *argvars, typval_T *rettv)
12256{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012257 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012258 timer_T *timer;
12259 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012260 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012261 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012262
Bram Moolenaar75537a92016-09-05 22:45:28 +020012263 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012264 if (check_secure())
12265 return;
12266 if (argvars[2].v_type != VAR_UNKNOWN)
12267 {
12268 if (argvars[2].v_type != VAR_DICT
12269 || (dict = argvars[2].vval.v_dict) == NULL)
12270 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012271 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012272 return;
12273 }
12274 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012275 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012276 }
12277
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012278 callback = get_callback(&argvars[1]);
12279 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012280 return;
12281
12282 timer = create_timer(msec, repeat);
12283 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012284 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012285 else
12286 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012287 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012288 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012289 }
12290}
12291
12292/*
12293 * "timer_stop(timer)" function
12294 */
12295 static void
12296f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12297{
12298 timer_T *timer;
12299
12300 if (argvars[0].v_type != VAR_NUMBER)
12301 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012302 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012303 return;
12304 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012305 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012306 if (timer != NULL)
12307 stop_timer(timer);
12308}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012309
12310/*
12311 * "timer_stopall()" function
12312 */
12313 static void
12314f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12315{
12316 stop_all_timers();
12317}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012318#endif
12319
12320/*
12321 * "tolower(string)" function
12322 */
12323 static void
12324f_tolower(typval_T *argvars, typval_T *rettv)
12325{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012326 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012327 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012328}
12329
12330/*
12331 * "toupper(string)" function
12332 */
12333 static void
12334f_toupper(typval_T *argvars, typval_T *rettv)
12335{
12336 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012337 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012338}
12339
12340/*
12341 * "tr(string, fromstr, tostr)" function
12342 */
12343 static void
12344f_tr(typval_T *argvars, typval_T *rettv)
12345{
12346 char_u *in_str;
12347 char_u *fromstr;
12348 char_u *tostr;
12349 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012350 int inlen;
12351 int fromlen;
12352 int tolen;
12353 int idx;
12354 char_u *cpstr;
12355 int cplen;
12356 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357 char_u buf[NUMBUFLEN];
12358 char_u buf2[NUMBUFLEN];
12359 garray_T ga;
12360
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012361 in_str = tv_get_string(&argvars[0]);
12362 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12363 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012364
12365 /* Default return value: empty string. */
12366 rettv->v_type = VAR_STRING;
12367 rettv->vval.v_string = NULL;
12368 if (fromstr == NULL || tostr == NULL)
12369 return; /* type error; errmsg already given */
12370 ga_init2(&ga, (int)sizeof(char), 80);
12371
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012372 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012373 /* not multi-byte: fromstr and tostr must be the same length */
12374 if (STRLEN(fromstr) != STRLEN(tostr))
12375 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012376error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012377 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012378 ga_clear(&ga);
12379 return;
12380 }
12381
12382 /* fromstr and tostr have to contain the same number of chars */
12383 while (*in_str != NUL)
12384 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012385 if (has_mbyte)
12386 {
12387 inlen = (*mb_ptr2len)(in_str);
12388 cpstr = in_str;
12389 cplen = inlen;
12390 idx = 0;
12391 for (p = fromstr; *p != NUL; p += fromlen)
12392 {
12393 fromlen = (*mb_ptr2len)(p);
12394 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12395 {
12396 for (p = tostr; *p != NUL; p += tolen)
12397 {
12398 tolen = (*mb_ptr2len)(p);
12399 if (idx-- == 0)
12400 {
12401 cplen = tolen;
12402 cpstr = p;
12403 break;
12404 }
12405 }
12406 if (*p == NUL) /* tostr is shorter than fromstr */
12407 goto error;
12408 break;
12409 }
12410 ++idx;
12411 }
12412
12413 if (first && cpstr == in_str)
12414 {
12415 /* Check that fromstr and tostr have the same number of
12416 * (multi-byte) characters. Done only once when a character
12417 * of in_str doesn't appear in fromstr. */
12418 first = FALSE;
12419 for (p = tostr; *p != NUL; p += tolen)
12420 {
12421 tolen = (*mb_ptr2len)(p);
12422 --idx;
12423 }
12424 if (idx != 0)
12425 goto error;
12426 }
12427
12428 (void)ga_grow(&ga, cplen);
12429 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12430 ga.ga_len += cplen;
12431
12432 in_str += inlen;
12433 }
12434 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012435 {
12436 /* When not using multi-byte chars we can do it faster. */
12437 p = vim_strchr(fromstr, *in_str);
12438 if (p != NULL)
12439 ga_append(&ga, tostr[p - fromstr]);
12440 else
12441 ga_append(&ga, *in_str);
12442 ++in_str;
12443 }
12444 }
12445
12446 /* add a terminating NUL */
12447 (void)ga_grow(&ga, 1);
12448 ga_append(&ga, NUL);
12449
12450 rettv->vval.v_string = ga.ga_data;
12451}
12452
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012453/*
12454 * "trim({expr})" function
12455 */
12456 static void
12457f_trim(typval_T *argvars, typval_T *rettv)
12458{
12459 char_u buf1[NUMBUFLEN];
12460 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012461 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012462 char_u *mask = NULL;
12463 char_u *tail;
12464 char_u *prev;
12465 char_u *p;
12466 int c1;
12467
12468 rettv->v_type = VAR_STRING;
12469 if (head == NULL)
12470 {
12471 rettv->vval.v_string = NULL;
12472 return;
12473 }
12474
12475 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012476 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012477
12478 while (*head != NUL)
12479 {
12480 c1 = PTR2CHAR(head);
12481 if (mask == NULL)
12482 {
12483 if (c1 > ' ' && c1 != 0xa0)
12484 break;
12485 }
12486 else
12487 {
12488 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12489 if (c1 == PTR2CHAR(p))
12490 break;
12491 if (*p == NUL)
12492 break;
12493 }
12494 MB_PTR_ADV(head);
12495 }
12496
12497 for (tail = head + STRLEN(head); tail > head; tail = prev)
12498 {
12499 prev = tail;
12500 MB_PTR_BACK(head, prev);
12501 c1 = PTR2CHAR(prev);
12502 if (mask == NULL)
12503 {
12504 if (c1 > ' ' && c1 != 0xa0)
12505 break;
12506 }
12507 else
12508 {
12509 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12510 if (c1 == PTR2CHAR(p))
12511 break;
12512 if (*p == NUL)
12513 break;
12514 }
12515 }
12516 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12517}
12518
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012519#ifdef FEAT_FLOAT
12520/*
12521 * "trunc({float})" function
12522 */
12523 static void
12524f_trunc(typval_T *argvars, typval_T *rettv)
12525{
12526 float_T f = 0.0;
12527
12528 rettv->v_type = VAR_FLOAT;
12529 if (get_float_arg(argvars, &f) == OK)
12530 /* trunc() is not in C90, use floor() or ceil() instead. */
12531 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12532 else
12533 rettv->vval.v_float = 0.0;
12534}
12535#endif
12536
12537/*
12538 * "type(expr)" function
12539 */
12540 static void
12541f_type(typval_T *argvars, typval_T *rettv)
12542{
12543 int n = -1;
12544
12545 switch (argvars[0].v_type)
12546 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012547 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12548 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012549 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012550 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12551 case VAR_LIST: n = VAR_TYPE_LIST; break;
12552 case VAR_DICT: n = VAR_TYPE_DICT; break;
12553 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012554 case VAR_SPECIAL:
12555 if (argvars[0].vval.v_number == VVAL_FALSE
12556 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012557 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012558 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012559 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012560 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012561 case VAR_JOB: n = VAR_TYPE_JOB; break;
12562 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012563 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012564 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012565 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012566 n = -1;
12567 break;
12568 }
12569 rettv->vval.v_number = n;
12570}
12571
12572/*
12573 * "undofile(name)" function
12574 */
12575 static void
12576f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12577{
12578 rettv->v_type = VAR_STRING;
12579#ifdef FEAT_PERSISTENT_UNDO
12580 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012581 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012582
12583 if (*fname == NUL)
12584 {
12585 /* If there is no file name there will be no undo file. */
12586 rettv->vval.v_string = NULL;
12587 }
12588 else
12589 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012590 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012591
12592 if (ffname != NULL)
12593 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12594 vim_free(ffname);
12595 }
12596 }
12597#else
12598 rettv->vval.v_string = NULL;
12599#endif
12600}
12601
12602/*
12603 * "undotree()" function
12604 */
12605 static void
12606f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12607{
12608 if (rettv_dict_alloc(rettv) == OK)
12609 {
12610 dict_T *dict = rettv->vval.v_dict;
12611 list_T *list;
12612
Bram Moolenaare0be1672018-07-08 16:50:37 +020012613 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12614 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12615 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12616 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12617 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12618 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012619
12620 list = list_alloc();
12621 if (list != NULL)
12622 {
12623 u_eval_tree(curbuf->b_u_oldhead, list);
12624 dict_add_list(dict, "entries", list);
12625 }
12626 }
12627}
12628
12629/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012630 * "virtcol(string)" function
12631 */
12632 static void
12633f_virtcol(typval_T *argvars, typval_T *rettv)
12634{
12635 colnr_T vcol = 0;
12636 pos_T *fp;
12637 int fnum = curbuf->b_fnum;
12638
12639 fp = var2fpos(&argvars[0], FALSE, &fnum);
12640 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12641 && fnum == curbuf->b_fnum)
12642 {
12643 getvvcol(curwin, fp, NULL, NULL, &vcol);
12644 ++vcol;
12645 }
12646
12647 rettv->vval.v_number = vcol;
12648}
12649
12650/*
12651 * "visualmode()" function
12652 */
12653 static void
12654f_visualmode(typval_T *argvars, typval_T *rettv)
12655{
12656 char_u str[2];
12657
12658 rettv->v_type = VAR_STRING;
12659 str[0] = curbuf->b_visual_mode_eval;
12660 str[1] = NUL;
12661 rettv->vval.v_string = vim_strsave(str);
12662
12663 /* A non-zero number or non-empty string argument: reset mode. */
12664 if (non_zero_arg(&argvars[0]))
12665 curbuf->b_visual_mode_eval = NUL;
12666}
12667
12668/*
12669 * "wildmenumode()" function
12670 */
12671 static void
12672f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12673{
12674#ifdef FEAT_WILDMENU
12675 if (wild_menu_showing)
12676 rettv->vval.v_number = 1;
12677#endif
12678}
12679
12680/*
12681 * "winbufnr(nr)" function
12682 */
12683 static void
12684f_winbufnr(typval_T *argvars, typval_T *rettv)
12685{
12686 win_T *wp;
12687
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012688 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012689 if (wp == NULL)
12690 rettv->vval.v_number = -1;
12691 else
12692 rettv->vval.v_number = wp->w_buffer->b_fnum;
12693}
12694
12695/*
12696 * "wincol()" function
12697 */
12698 static void
12699f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12700{
12701 validate_cursor();
12702 rettv->vval.v_number = curwin->w_wcol + 1;
12703}
12704
12705/*
12706 * "winheight(nr)" function
12707 */
12708 static void
12709f_winheight(typval_T *argvars, typval_T *rettv)
12710{
12711 win_T *wp;
12712
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012713 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012714 if (wp == NULL)
12715 rettv->vval.v_number = -1;
12716 else
12717 rettv->vval.v_number = wp->w_height;
12718}
12719
12720/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012721 * "winlayout()" function
12722 */
12723 static void
12724f_winlayout(typval_T *argvars, typval_T *rettv)
12725{
12726 tabpage_T *tp;
12727
12728 if (rettv_list_alloc(rettv) != OK)
12729 return;
12730
12731 if (argvars[0].v_type == VAR_UNKNOWN)
12732 tp = curtab;
12733 else
12734 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012735 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012736 if (tp == NULL)
12737 return;
12738 }
12739
12740 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12741}
12742
12743/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012744 * "winline()" function
12745 */
12746 static void
12747f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12748{
12749 validate_cursor();
12750 rettv->vval.v_number = curwin->w_wrow + 1;
12751}
12752
12753/*
12754 * "winnr()" function
12755 */
12756 static void
12757f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12758{
12759 int nr = 1;
12760
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012762 rettv->vval.v_number = nr;
12763}
12764
12765/*
12766 * "winrestcmd()" function
12767 */
12768 static void
12769f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12770{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771 win_T *wp;
12772 int winnr = 1;
12773 garray_T ga;
12774 char_u buf[50];
12775
12776 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012777 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012778 {
12779 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12780 ga_concat(&ga, buf);
12781 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12782 ga_concat(&ga, buf);
12783 ++winnr;
12784 }
12785 ga_append(&ga, NUL);
12786
12787 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012788 rettv->v_type = VAR_STRING;
12789}
12790
12791/*
12792 * "winrestview()" function
12793 */
12794 static void
12795f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12796{
12797 dict_T *dict;
12798
12799 if (argvars[0].v_type != VAR_DICT
12800 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012801 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012802 else
12803 {
12804 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012805 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012806 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012807 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012808 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012809 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012810 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12811 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012812 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012813 curwin->w_set_curswant = FALSE;
12814 }
12815
12816 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012817 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012818#ifdef FEAT_DIFF
12819 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012820 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012821#endif
12822 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012823 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012824 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012825 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012826
12827 check_cursor();
12828 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012829 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012830 changed_window_setting();
12831
12832 if (curwin->w_topline <= 0)
12833 curwin->w_topline = 1;
12834 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12835 curwin->w_topline = curbuf->b_ml.ml_line_count;
12836#ifdef FEAT_DIFF
12837 check_topfill(curwin, TRUE);
12838#endif
12839 }
12840}
12841
12842/*
12843 * "winsaveview()" function
12844 */
12845 static void
12846f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12847{
12848 dict_T *dict;
12849
12850 if (rettv_dict_alloc(rettv) == FAIL)
12851 return;
12852 dict = rettv->vval.v_dict;
12853
Bram Moolenaare0be1672018-07-08 16:50:37 +020012854 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12855 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012856 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012857 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012858 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012859
Bram Moolenaare0be1672018-07-08 16:50:37 +020012860 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012861#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012862 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012863#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012864 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12865 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012866}
12867
12868/*
12869 * "winwidth(nr)" function
12870 */
12871 static void
12872f_winwidth(typval_T *argvars, typval_T *rettv)
12873{
12874 win_T *wp;
12875
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012876 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012877 if (wp == NULL)
12878 rettv->vval.v_number = -1;
12879 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012880 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012881}
12882
12883/*
12884 * "wordcount()" function
12885 */
12886 static void
12887f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12888{
12889 if (rettv_dict_alloc(rettv) == FAIL)
12890 return;
12891 cursor_pos_info(rettv->vval.v_dict);
12892}
12893
12894/*
12895 * "writefile()" function
12896 */
12897 static void
12898f_writefile(typval_T *argvars, typval_T *rettv)
12899{
12900 int binary = FALSE;
12901 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012902#ifdef HAVE_FSYNC
12903 int do_fsync = p_fs;
12904#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012905 char_u *fname;
12906 FILE *fd;
12907 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012908 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012909 list_T *list = NULL;
12910 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012911
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012912 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012913 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012914 return;
12915
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012916 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012917 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012918 list = argvars[0].vval.v_list;
12919 if (list == NULL)
12920 return;
12921 for (li = list->lv_first; li != NULL; li = li->li_next)
12922 if (tv_get_string_chk(&li->li_tv) == NULL)
12923 return;
12924 }
12925 else if (argvars[0].v_type == VAR_BLOB)
12926 {
12927 blob = argvars[0].vval.v_blob;
12928 if (blob == NULL)
12929 return;
12930 }
12931 else
12932 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012933 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012934 return;
12935 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012936
12937 if (argvars[2].v_type != VAR_UNKNOWN)
12938 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012939 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012940
12941 if (arg2 == NULL)
12942 return;
12943 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012944 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012945 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012946 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012947#ifdef HAVE_FSYNC
12948 if (vim_strchr(arg2, 's') != NULL)
12949 do_fsync = TRUE;
12950 else if (vim_strchr(arg2, 'S') != NULL)
12951 do_fsync = FALSE;
12952#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012953 }
12954
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012955 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012956 if (fname == NULL)
12957 return;
12958
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012959 /* Always open the file in binary mode, library functions have a mind of
12960 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012961 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12962 append ? APPENDBIN : WRITEBIN)) == NULL)
12963 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012964 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012965 ret = -1;
12966 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012967 else if (blob)
12968 {
12969 if (write_blob(fd, blob) == FAIL)
12970 ret = -1;
12971#ifdef HAVE_FSYNC
12972 else if (do_fsync)
12973 // Ignore the error, the user wouldn't know what to do about it.
12974 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012975 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012976#endif
12977 fclose(fd);
12978 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012979 else
12980 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012981 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012982 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012983#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012984 else if (do_fsync)
12985 /* Ignore the error, the user wouldn't know what to do about it.
12986 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012987 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012988#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012989 fclose(fd);
12990 }
12991
12992 rettv->vval.v_number = ret;
12993}
12994
12995/*
12996 * "xor(expr, expr)" function
12997 */
12998 static void
12999f_xor(typval_T *argvars, typval_T *rettv)
13000{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013001 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
13002 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013003}
13004
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013005#endif /* FEAT_EVAL */