blob: f302df773afb605c07cd6ce6c9c8307175d080a8 [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 Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#endif
26
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027#ifdef FEAT_FLOAT
28static void f_abs(typval_T *argvars, typval_T *rettv);
29static void f_acos(typval_T *argvars, typval_T *rettv);
30#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020031static void f_and(typval_T *argvars, typval_T *rettv);
32static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020033static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020034#ifdef FEAT_FLOAT
35static void f_asin(typval_T *argvars, typval_T *rettv);
36static void f_atan(typval_T *argvars, typval_T *rettv);
37static void f_atan2(typval_T *argvars, typval_T *rettv);
38#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020040static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010041static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010043static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010044# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010045#endif
Bram Moolenaar15e248e2019-06-30 20:21:37 +020046static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020047static void f_bufexists(typval_T *argvars, typval_T *rettv);
48static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020049static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_bufloaded(typval_T *argvars, typval_T *rettv);
51static void f_bufname(typval_T *argvars, typval_T *rettv);
52static void f_bufnr(typval_T *argvars, typval_T *rettv);
53static void f_bufwinid(typval_T *argvars, typval_T *rettv);
54static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
55static void f_byte2line(typval_T *argvars, typval_T *rettv);
56static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
57static void f_byteidx(typval_T *argvars, typval_T *rettv);
58static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
59static void f_call(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_ceil(typval_T *argvars, typval_T *rettv);
62#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020063static void f_changenr(typval_T *argvars, typval_T *rettv);
64static void f_char2nr(typval_T *argvars, typval_T *rettv);
65static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_confirm(typval_T *argvars, typval_T *rettv);
68static void f_copy(typval_T *argvars, typval_T *rettv);
69#ifdef FEAT_FLOAT
70static void f_cos(typval_T *argvars, typval_T *rettv);
71static void f_cosh(typval_T *argvars, typval_T *rettv);
72#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010074#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020075static void f_debugbreak(typval_T *argvars, typval_T *rettv);
76#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020078static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020079static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020081static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020082static void f_escape(typval_T *argvars, typval_T *rettv);
83static void f_eval(typval_T *argvars, typval_T *rettv);
84static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_exists(typval_T *argvars, typval_T *rettv);
87#ifdef FEAT_FLOAT
88static void f_exp(typval_T *argvars, typval_T *rettv);
89#endif
90static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020091static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093#ifdef FEAT_FLOAT
94static void f_float2nr(typval_T *argvars, typval_T *rettv);
95static void f_floor(typval_T *argvars, typval_T *rettv);
96static void f_fmod(typval_T *argvars, typval_T *rettv);
97#endif
98static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200100static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_function(typval_T *argvars, typval_T *rettv);
102static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
103static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200104static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_getbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100106static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_getchar(typval_T *argvars, typval_T *rettv);
108static void f_getcharmod(typval_T *argvars, typval_T *rettv);
109static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200110static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200111static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200112static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100113static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200115static void f_getpid(typval_T *argvars, typval_T *rettv);
116static void f_getcurpos(typval_T *argvars, typval_T *rettv);
117static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_getreg(typval_T *argvars, typval_T *rettv);
119static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200120static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100121static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200122static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100123static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200124static void f_getwinposx(typval_T *argvars, typval_T *rettv);
125static void f_getwinposy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200126static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
128static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_hlID(typval_T *argvars, typval_T *rettv);
130static void f_hlexists(typval_T *argvars, typval_T *rettv);
131static void f_hostname(typval_T *argvars, typval_T *rettv);
132static void f_iconv(typval_T *argvars, typval_T *rettv);
133static void f_indent(typval_T *argvars, typval_T *rettv);
134static void f_index(typval_T *argvars, typval_T *rettv);
135static void f_input(typval_T *argvars, typval_T *rettv);
136static void f_inputdialog(typval_T *argvars, typval_T *rettv);
137static void f_inputlist(typval_T *argvars, typval_T *rettv);
138static void f_inputrestore(typval_T *argvars, typval_T *rettv);
139static void f_inputsave(typval_T *argvars, typval_T *rettv);
140static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200142static void f_islocked(typval_T *argvars, typval_T *rettv);
143#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200144static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200145static void f_isnan(typval_T *argvars, typval_T *rettv);
146#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
148static void f_len(typval_T *argvars, typval_T *rettv);
149static void f_libcall(typval_T *argvars, typval_T *rettv);
150static void f_libcallnr(typval_T *argvars, typval_T *rettv);
151static void f_line(typval_T *argvars, typval_T *rettv);
152static void f_line2byte(typval_T *argvars, typval_T *rettv);
153static void f_lispindent(typval_T *argvars, typval_T *rettv);
154static void f_localtime(typval_T *argvars, typval_T *rettv);
155#ifdef FEAT_FLOAT
156static void f_log(typval_T *argvars, typval_T *rettv);
157static void f_log10(typval_T *argvars, typval_T *rettv);
158#endif
159#ifdef FEAT_LUA
160static void f_luaeval(typval_T *argvars, typval_T *rettv);
161#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200162static void f_maparg(typval_T *argvars, typval_T *rettv);
163static void f_mapcheck(typval_T *argvars, typval_T *rettv);
164static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_matchend(typval_T *argvars, typval_T *rettv);
166static void f_matchlist(typval_T *argvars, typval_T *rettv);
167static void f_matchstr(typval_T *argvars, typval_T *rettv);
168static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
169static void f_max(typval_T *argvars, typval_T *rettv);
170static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_mode(typval_T *argvars, typval_T *rettv);
172#ifdef FEAT_MZSCHEME
173static void f_mzeval(typval_T *argvars, typval_T *rettv);
174#endif
175static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
176static void f_nr2char(typval_T *argvars, typval_T *rettv);
177static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200178#ifdef FEAT_PERL
179static void f_perleval(typval_T *argvars, typval_T *rettv);
180#endif
181#ifdef FEAT_FLOAT
182static void f_pow(typval_T *argvars, typval_T *rettv);
183#endif
184static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
185static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200186static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_pumvisible(typval_T *argvars, typval_T *rettv);
188#ifdef FEAT_PYTHON3
189static void f_py3eval(typval_T *argvars, typval_T *rettv);
190#endif
191#ifdef FEAT_PYTHON
192static void f_pyeval(typval_T *argvars, typval_T *rettv);
193#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100194#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
195static void f_pyxeval(typval_T *argvars, typval_T *rettv);
196#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200198static void f_reg_executing(typval_T *argvars, typval_T *rettv);
199static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_reltime(typval_T *argvars, typval_T *rettv);
201#ifdef FEAT_FLOAT
202static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
203#endif
204static void f_reltimestr(typval_T *argvars, typval_T *rettv);
205static void f_remote_expr(typval_T *argvars, typval_T *rettv);
206static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
207static void f_remote_peek(typval_T *argvars, typval_T *rettv);
208static void f_remote_read(typval_T *argvars, typval_T *rettv);
209static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100210static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200211static void f_rename(typval_T *argvars, typval_T *rettv);
212static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213#ifdef FEAT_FLOAT
214static void f_round(typval_T *argvars, typval_T *rettv);
215#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100216#ifdef FEAT_RUBY
217static void f_rubyeval(typval_T *argvars, typval_T *rettv);
218#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219static void f_screenattr(typval_T *argvars, typval_T *rettv);
220static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100221static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_screencol(typval_T *argvars, typval_T *rettv);
223static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100224static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_search(typval_T *argvars, typval_T *rettv);
226static void f_searchdecl(typval_T *argvars, typval_T *rettv);
227static void f_searchpair(typval_T *argvars, typval_T *rettv);
228static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
229static void f_searchpos(typval_T *argvars, typval_T *rettv);
230static void f_server2client(typval_T *argvars, typval_T *rettv);
231static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200232static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200233static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200234static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_setfperm(typval_T *argvars, typval_T *rettv);
236static void f_setline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200237static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200238static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100239static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240#ifdef FEAT_CRYPT
241static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200242#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200243static void f_shellescape(typval_T *argvars, typval_T *rettv);
244static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245#ifdef FEAT_FLOAT
246static void f_sin(typval_T *argvars, typval_T *rettv);
247static void f_sinh(typval_T *argvars, typval_T *rettv);
248#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200249static void f_soundfold(typval_T *argvars, typval_T *rettv);
250static void f_spellbadword(typval_T *argvars, typval_T *rettv);
251static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
252static void f_split(typval_T *argvars, typval_T *rettv);
253#ifdef FEAT_FLOAT
254static void f_sqrt(typval_T *argvars, typval_T *rettv);
255static void f_str2float(typval_T *argvars, typval_T *rettv);
256#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200257static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200258static void f_str2nr(typval_T *argvars, typval_T *rettv);
259static void f_strchars(typval_T *argvars, typval_T *rettv);
260#ifdef HAVE_STRFTIME
261static void f_strftime(typval_T *argvars, typval_T *rettv);
262#endif
263static void f_strgetchar(typval_T *argvars, typval_T *rettv);
264static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200265static void f_strlen(typval_T *argvars, typval_T *rettv);
266static void f_strcharpart(typval_T *argvars, typval_T *rettv);
267static void f_strpart(typval_T *argvars, typval_T *rettv);
268static void f_strridx(typval_T *argvars, typval_T *rettv);
269static void f_strtrans(typval_T *argvars, typval_T *rettv);
270static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
271static void f_strwidth(typval_T *argvars, typval_T *rettv);
272static void f_submatch(typval_T *argvars, typval_T *rettv);
273static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200274static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200275static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200276static void f_synID(typval_T *argvars, typval_T *rettv);
277static void f_synIDattr(typval_T *argvars, typval_T *rettv);
278static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
279static void f_synstack(typval_T *argvars, typval_T *rettv);
280static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200281static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
282static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
283static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
284static void f_taglist(typval_T *argvars, typval_T *rettv);
285static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200286#ifdef FEAT_FLOAT
287static void f_tan(typval_T *argvars, typval_T *rettv);
288static void f_tanh(typval_T *argvars, typval_T *rettv);
289#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290static void f_tolower(typval_T *argvars, typval_T *rettv);
291static void f_toupper(typval_T *argvars, typval_T *rettv);
292static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100293static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200294#ifdef FEAT_FLOAT
295static void f_trunc(typval_T *argvars, typval_T *rettv);
296#endif
297static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200298static void f_virtcol(typval_T *argvars, typval_T *rettv);
299static void f_visualmode(typval_T *argvars, typval_T *rettv);
300static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200301static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
303static void f_win_getid(typval_T *argvars, typval_T *rettv);
304static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
305static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
306static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100307static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200308static void f_winbufnr(typval_T *argvars, typval_T *rettv);
309static void f_wincol(typval_T *argvars, typval_T *rettv);
310static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200311static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200312static void f_winline(typval_T *argvars, typval_T *rettv);
313static void f_winnr(typval_T *argvars, typval_T *rettv);
314static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
315static void f_winrestview(typval_T *argvars, typval_T *rettv);
316static void f_winsaveview(typval_T *argvars, typval_T *rettv);
317static void f_winwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200318static void f_wordcount(typval_T *argvars, typval_T *rettv);
319static void f_xor(typval_T *argvars, typval_T *rettv);
320
321/*
322 * Array with names and number of arguments of all internal functions
323 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
324 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200325typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200326{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200327 char *f_name; // function name
328 char f_min_argc; // minimal number of arguments
329 char f_max_argc; // maximal number of arguments
330 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200331 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200332 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200333} funcentry_T;
334
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200335// values for f_argtype; zero means it cannot be used as a method
336#define FEARG_1 1 // base is the first argument
337#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200338#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200339#define FEARG_LAST 9 // base is the last argument
340
Bram Moolenaarac92e252019-08-03 21:58:38 +0200341static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200342{
343#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200344 {"abs", 1, 1, FEARG_1, f_abs},
345 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200346#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200347 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200348 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200349 {"append", 2, 2, FEARG_LAST, f_append},
350 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
351 {"argc", 0, 1, 0, f_argc},
352 {"argidx", 0, 0, 0, f_argidx},
353 {"arglistid", 0, 2, 0, f_arglistid},
354 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200355#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200356 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200358 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200359 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200360 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200361 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200362 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
363 {"assert_false", 1, 2, FEARG_1, f_assert_false},
364 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
365 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200366 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200367 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200368 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200369 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200370#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200371 {"atan", 1, 1, FEARG_1, f_atan},
372 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200373#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100374#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200375 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200376 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100377# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200378 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100379# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100380#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200381 {"browse", 4, 4, 0, f_browse},
382 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200383 {"bufadd", 1, 1, FEARG_1, f_bufadd},
384 {"bufexists", 1, 1, FEARG_1, f_bufexists},
385 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200386 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
387 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200388 {"buflisted", 1, 1, FEARG_1, f_buflisted},
389 {"bufload", 1, 1, FEARG_1, f_bufload},
390 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200391 {"bufname", 0, 1, FEARG_1, f_bufname},
392 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200393 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
394 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200395 {"byte2line", 1, 1, FEARG_1, f_byte2line},
396 {"byteidx", 2, 2, FEARG_1, f_byteidx},
397 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
398 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200399#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200400 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401#endif
402#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200403 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
404 {"ch_close", 1, 1, FEARG_1, f_ch_close},
405 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
406 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
407 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
408 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
409 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
410 {"ch_info", 1, 1, FEARG_1, f_ch_info},
411 {"ch_log", 1, 2, FEARG_1, f_ch_log},
412 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
413 {"ch_open", 1, 2, FEARG_1, f_ch_open},
414 {"ch_read", 1, 2, FEARG_1, f_ch_read},
415 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
416 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
417 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
418 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
419 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
420 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200422 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200423 {"char2nr", 1, 2, FEARG_1, f_char2nr},
424 {"chdir", 1, 1, FEARG_1, f_chdir},
425 {"cindent", 1, 1, FEARG_1, f_cindent},
426 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
427 {"col", 1, 1, FEARG_1, f_col},
428 {"complete", 2, 2, FEARG_2, f_complete},
429 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200430 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200431 {"complete_info", 0, 1, FEARG_1, f_complete_info},
432 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200433 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200435 {"cos", 1, 1, FEARG_1, f_cos},
436 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200438 {"count", 2, 4, FEARG_1, f_count},
439 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200440 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100441#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200442 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200443#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200444 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
445 {"delete", 1, 2, FEARG_1, f_delete},
446 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200447 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200448 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
449 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200450 {"empty", 1, 1, FEARG_1, f_empty},
451 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200452 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200453 {"eval", 1, 1, FEARG_1, f_eval},
454 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200455 {"executable", 1, 1, FEARG_1, f_executable},
456 {"execute", 1, 2, FEARG_1, f_execute},
457 {"exepath", 1, 1, FEARG_1, f_exepath},
458 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200459#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200460 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200461#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200462 {"expand", 1, 3, FEARG_1, f_expand},
463 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200464 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200465 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
466 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
467 {"filereadable", 1, 1, FEARG_1, f_filereadable},
468 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200469 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200470 {"finddir", 1, 3, FEARG_1, f_finddir},
471 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200472#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200473 {"float2nr", 1, 1, FEARG_1, f_float2nr},
474 {"floor", 1, 1, FEARG_1, f_floor},
475 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200476#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200477 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
478 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
479 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
480 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
481 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200482 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200483 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200484 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200485 {"funcref", 1, 3, FEARG_1, f_funcref},
486 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200487 {"garbagecollect", 0, 1, 0, f_garbagecollect},
488 {"get", 2, 3, FEARG_1, f_get},
489 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200490 {"getbufline", 2, 3, FEARG_1, f_getbufline},
491 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
492 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200493 {"getchar", 0, 1, 0, f_getchar},
494 {"getcharmod", 0, 0, 0, f_getcharmod},
495 {"getcharsearch", 0, 0, 0, f_getcharsearch},
496 {"getcmdline", 0, 0, 0, f_getcmdline},
497 {"getcmdpos", 0, 0, 0, f_getcmdpos},
498 {"getcmdtype", 0, 0, 0, f_getcmdtype},
499 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200500 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200501 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200502 {"getcwd", 0, 2, FEARG_1, f_getcwd},
503 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200505 {"getfperm", 1, 1, FEARG_1, f_getfperm},
506 {"getfsize", 1, 1, FEARG_1, f_getfsize},
507 {"getftime", 1, 1, FEARG_1, f_getftime},
508 {"getftype", 1, 1, FEARG_1, f_getftype},
509 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
510 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200511 {"getloclist", 1, 2, 0, f_getloclist},
512 {"getmatches", 0, 1, 0, f_getmatches},
513 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200514 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200515 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200516 {"getreg", 0, 3, FEARG_1, f_getreg},
517 {"getregtype", 0, 1, FEARG_1, f_getregtype},
518 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
519 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
520 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200521 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
522 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
523 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200524 {"getwinposx", 0, 0, 0, f_getwinposx},
525 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200526 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
527 {"glob", 1, 4, FEARG_1, f_glob},
528 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
529 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200530 {"has", 1, 1, 0, f_has},
531 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200532 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
533 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
534 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
535 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
536 {"histadd", 2, 2, FEARG_2, f_histadd},
537 {"histdel", 1, 2, FEARG_1, f_histdel},
538 {"histget", 1, 2, FEARG_1, f_histget},
539 {"histnr", 1, 1, FEARG_1, f_histnr},
540 {"hlID", 1, 1, FEARG_1, f_hlID},
541 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200542 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200543 {"iconv", 3, 3, FEARG_1, f_iconv},
544 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200545 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200546 {"input", 1, 3, FEARG_1, f_input},
547 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
548 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200549 {"inputrestore", 0, 0, 0, f_inputrestore},
550 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200551 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200552 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200553 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200554 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200555#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200556 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200557#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200558 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200559#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200560 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200561#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200562 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200563#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200564 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
565 {"job_info", 0, 1, FEARG_1, f_job_info},
566 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
567 {"job_start", 1, 2, FEARG_1, f_job_start},
568 {"job_status", 1, 1, FEARG_1, f_job_status},
569 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200570#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200571 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200572 {"js_decode", 1, 1, FEARG_1, f_js_decode},
573 {"js_encode", 1, 1, FEARG_1, f_js_encode},
574 {"json_decode", 1, 1, FEARG_1, f_json_decode},
575 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200576 {"keys", 1, 1, FEARG_1, f_keys},
577 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
578 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200579 {"libcall", 3, 3, FEARG_3, f_libcall},
580 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200581 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200582 {"line2byte", 1, 1, FEARG_1, f_line2byte},
583 {"lispindent", 1, 1, FEARG_1, f_lispindent},
584 {"list2str", 1, 2, FEARG_1, f_list2str},
585 {"listener_add", 1, 2, FEARG_2, f_listener_add},
586 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
587 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200588 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200589#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200590 {"log", 1, 1, FEARG_1, f_log},
591 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200592#endif
593#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200594 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200595#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200596 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200597 {"maparg", 1, 4, FEARG_1, f_maparg},
598 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
599 {"match", 2, 4, FEARG_1, f_match},
600 {"matchadd", 2, 5, FEARG_1, f_matchadd},
601 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
602 {"matcharg", 1, 1, FEARG_1, f_matcharg},
603 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
604 {"matchend", 2, 4, FEARG_1, f_matchend},
605 {"matchlist", 2, 4, FEARG_1, f_matchlist},
606 {"matchstr", 2, 4, FEARG_1, f_matchstr},
607 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200608 {"max", 1, 1, FEARG_1, f_max},
609 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200610 {"mkdir", 1, 3, FEARG_1, f_mkdir},
611 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200612#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200613 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200614#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200615 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
616 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200617 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200618 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200619#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200620 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200621#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200622#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200623 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
624 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200625 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200626 {"popup_close", 1, 2, FEARG_1, f_popup_close},
627 {"popup_create", 2, 2, FEARG_1, f_popup_create},
628 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200629 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
630 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200631 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
632 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200633 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
634 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
635 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200636 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200637 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
638 {"popup_move", 2, 2, FEARG_1, f_popup_move},
639 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
640 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
641 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
642 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200643#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200645 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200646#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200647 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200648 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200649#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200650 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
651 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
652 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200653#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100654#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200655 {"prop_add", 3, 3, FEARG_1, f_prop_add},
656 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
657 {"prop_list", 1, 2, FEARG_1, f_prop_list},
658 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
659 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
660 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
661 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
662 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
663 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100664#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200665 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200666 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200667#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200668 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200669#endif
670#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200671 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200672#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100673#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200674 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100675#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200676 {"range", 1, 3, FEARG_1, f_range},
677 {"readdir", 1, 2, FEARG_1, f_readdir},
678 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200679 {"reg_executing", 0, 0, 0, f_reg_executing},
680 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200681 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200682#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200683 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200684#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200685 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
686 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
687 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
688 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
689 {"remote_read", 1, 2, FEARG_1, f_remote_read},
690 {"remote_send", 2, 3, FEARG_1, f_remote_send},
691 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200692 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200693 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200694 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200695 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200696 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200697#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200698 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200699#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100700#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200701 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100702#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200703 {"screenattr", 2, 2, FEARG_1, f_screenattr},
704 {"screenchar", 2, 2, FEARG_1, f_screenchar},
705 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200706 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200707 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200708 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200709 {"screenstring", 2, 2, FEARG_1, f_screenstring},
710 {"search", 1, 4, FEARG_1, f_search},
711 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200712 {"searchpair", 3, 7, 0, f_searchpair},
713 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200714 {"searchpos", 1, 4, FEARG_1, f_searchpos},
715 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200716 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200717 {"setbufline", 3, 3, FEARG_3, f_setbufline},
718 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
719 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
720 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
721 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200722 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200723 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200724 {"setloclist", 2, 4, 0, f_setloclist},
725 {"setmatches", 1, 2, 0, f_setmatches},
726 {"setpos", 2, 2, 0, f_setpos},
727 {"setqflist", 1, 3, 0, f_setqflist},
728 {"setreg", 2, 3, 0, f_setreg},
729 {"settabvar", 3, 3, 0, f_settabvar},
730 {"settabwinvar", 4, 4, 0, f_settabwinvar},
731 {"settagstack", 2, 3, 0, f_settagstack},
732 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200733#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200734 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200735#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200736 {"shellescape", 1, 2, 0, f_shellescape},
737 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100738#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200739 {"sign_define", 1, 2, 0, f_sign_define},
740 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
741 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
742 {"sign_jump", 3, 3, 0, f_sign_jump},
743 {"sign_place", 4, 5, 0, f_sign_place},
744 {"sign_placelist", 1, 1, 0, f_sign_placelist},
745 {"sign_undefine", 0, 1, 0, f_sign_undefine},
746 {"sign_unplace", 1, 2, 0, f_sign_unplace},
747 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100748#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200749 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200750#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200751 {"sin", 1, 1, FEARG_1, f_sin},
752 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200753#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200754 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200755#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200756 {"sound_clear", 0, 0, 0, f_sound_clear},
757 {"sound_playevent", 1, 2, 0, f_sound_playevent},
758 {"sound_playfile", 1, 2, 0, f_sound_playfile},
759 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200760#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200761 {"soundfold", 1, 1, 0, f_soundfold},
762 {"spellbadword", 0, 1, 0, f_spellbadword},
763 {"spellsuggest", 1, 3, 0, f_spellsuggest},
764 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200765#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200766 {"sqrt", 1, 1, FEARG_1, f_sqrt},
767 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200768#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200769 {"str2list", 1, 2, FEARG_1, f_str2list},
770 {"str2nr", 1, 2, 0, f_str2nr},
771 {"strcharpart", 2, 3, 0, f_strcharpart},
772 {"strchars", 1, 2, 0, f_strchars},
773 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200774#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200775 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200776#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200777 {"strgetchar", 2, 2, 0, f_strgetchar},
778 {"stridx", 2, 3, 0, f_stridx},
779 {"string", 1, 1, FEARG_1, f_string},
780 {"strlen", 1, 1, FEARG_1, f_strlen},
781 {"strpart", 2, 3, 0, f_strpart},
782 {"strridx", 2, 3, 0, f_strridx},
783 {"strtrans", 1, 1, FEARG_1, f_strtrans},
784 {"strwidth", 1, 1, FEARG_1, f_strwidth},
785 {"submatch", 1, 2, 0, f_submatch},
786 {"substitute", 4, 4, FEARG_1, f_substitute},
787 {"swapinfo", 1, 1, 0, f_swapinfo},
788 {"swapname", 1, 1, 0, f_swapname},
789 {"synID", 3, 3, 0, f_synID},
790 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
791 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
792 {"synconcealed", 2, 2, 0, f_synconcealed},
793 {"synstack", 2, 2, 0, f_synstack},
794 {"system", 1, 2, FEARG_1, f_system},
795 {"systemlist", 1, 2, FEARG_1, f_systemlist},
796 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
797 {"tabpagenr", 0, 1, 0, f_tabpagenr},
798 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
799 {"tagfiles", 0, 0, 0, f_tagfiles},
800 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200801#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200802 {"tan", 1, 1, FEARG_1, f_tan},
803 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200805 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200806#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200807 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
808 {"term_dumpload", 1, 2, 0, f_term_dumpload},
809 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
810 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200811# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200812 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200813# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200814 {"term_getattr", 2, 2, 0, f_term_getattr},
815 {"term_getcursor", 1, 1, 0, f_term_getcursor},
816 {"term_getjob", 1, 1, 0, f_term_getjob},
817 {"term_getline", 2, 2, 0, f_term_getline},
818 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
819 {"term_getsize", 1, 1, 0, f_term_getsize},
820 {"term_getstatus", 1, 1, 0, f_term_getstatus},
821 {"term_gettitle", 1, 1, 0, f_term_gettitle},
822 {"term_gettty", 1, 2, 0, f_term_gettty},
823 {"term_list", 0, 0, 0, f_term_list},
824 {"term_scrape", 2, 2, 0, f_term_scrape},
825 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200826# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200827 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200828# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200829 {"term_setkill", 2, 2, 0, f_term_setkill},
830 {"term_setrestore", 2, 2, 0, f_term_setrestore},
831 {"term_setsize", 3, 3, 0, f_term_setsize},
832 {"term_start", 1, 2, 0, f_term_start},
833 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200834#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200835 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
836 {"test_autochdir", 0, 0, 0, f_test_autochdir},
837 {"test_feedinput", 1, 1, 0, f_test_feedinput},
838 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
839 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
840 {"test_getvalue", 1, 1, 0, f_test_getvalue},
841 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
842 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200844 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200845#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200846 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200848 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200850 {"test_null_list", 0, 0, 0, f_test_null_list},
851 {"test_null_partial", 0, 0, 0, f_test_null_partial},
852 {"test_null_string", 0, 0, 0, f_test_null_string},
853 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
854 {"test_override", 2, 2, 0, f_test_override},
855 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200856#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200857 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200858#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200859#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200860 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200861#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200862 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200863#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200864 {"timer_info", 0, 1, 0, f_timer_info},
865 {"timer_pause", 2, 2, 0, f_timer_pause},
866 {"timer_start", 2, 3, 0, f_timer_start},
867 {"timer_stop", 1, 1, 0, f_timer_stop},
868 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200869#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200870 {"tolower", 1, 1, 0, f_tolower},
871 {"toupper", 1, 1, 0, f_toupper},
872 {"tr", 3, 3, 0, f_tr},
873 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200875 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200877 {"type", 1, 1, FEARG_1, f_type},
878 {"undofile", 1, 1, 0, f_undofile},
879 {"undotree", 0, 0, 0, f_undotree},
880 {"uniq", 1, 3, FEARG_1, f_uniq},
881 {"values", 1, 1, FEARG_1, f_values},
882 {"virtcol", 1, 1, 0, f_virtcol},
883 {"visualmode", 0, 1, 0, f_visualmode},
884 {"wildmenumode", 0, 0, 0, f_wildmenumode},
885 {"win_execute", 2, 3, 0, f_win_execute},
886 {"win_findbuf", 1, 1, 0, f_win_findbuf},
887 {"win_getid", 0, 2, 0, f_win_getid},
888 {"win_gotoid", 1, 1, 0, f_win_gotoid},
889 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
890 {"win_id2win", 1, 1, 0, f_win_id2win},
891 {"win_screenpos", 1, 1, 0, f_win_screenpos},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200892 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200893 {"wincol", 0, 0, 0, f_wincol},
894 {"winheight", 1, 1, 0, f_winheight},
895 {"winlayout", 0, 1, 0, f_winlayout},
896 {"winline", 0, 0, 0, f_winline},
897 {"winnr", 0, 1, 0, f_winnr},
898 {"winrestcmd", 0, 0, 0, f_winrestcmd},
899 {"winrestview", 1, 1, 0, f_winrestview},
900 {"winsaveview", 0, 0, 0, f_winsaveview},
901 {"winwidth", 1, 1, 0, f_winwidth},
902 {"wordcount", 0, 0, 0, f_wordcount},
903 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200904 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200905};
906
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200907/*
908 * Function given to ExpandGeneric() to obtain the list of internal
909 * or user defined function names.
910 */
911 char_u *
912get_function_name(expand_T *xp, int idx)
913{
914 static int intidx = -1;
915 char_u *name;
916
917 if (idx == 0)
918 intidx = -1;
919 if (intidx < 0)
920 {
921 name = get_user_func_name(xp, idx);
922 if (name != NULL)
923 return name;
924 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200925 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200927 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200929 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930 STRCAT(IObuff, ")");
931 return IObuff;
932 }
933
934 return NULL;
935}
936
937/*
938 * Function given to ExpandGeneric() to obtain the list of internal or
939 * user defined variable or function names.
940 */
941 char_u *
942get_expr_name(expand_T *xp, int idx)
943{
944 static int intidx = -1;
945 char_u *name;
946
947 if (idx == 0)
948 intidx = -1;
949 if (intidx < 0)
950 {
951 name = get_function_name(xp, idx);
952 if (name != NULL)
953 return name;
954 }
955 return get_user_var_name(xp, ++intidx);
956}
957
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200958/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200959 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200960 * Return index, or -1 if not found
961 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200962 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200963find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964{
965 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200966 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200967 int cmp;
968 int x;
969
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200970 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200971
972 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973 while (first <= last)
974 {
975 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200976 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200977 if (cmp < 0)
978 last = x - 1;
979 else if (cmp > 0)
980 first = x + 1;
981 else
982 return x;
983 }
984 return -1;
985}
986
987 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200988has_internal_func(char_u *name)
989{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200990 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200991}
992
993 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200994call_internal_func(
995 char_u *name,
996 int argcount,
997 typval_T *argvars,
998 typval_T *rettv)
999{
1000 int i;
1001
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001002 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001003 if (i < 0)
1004 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001005 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001006 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001007 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001008 return ERROR_TOOMANY;
1009 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001010 global_functions[i].f_func(argvars, rettv);
1011 return ERROR_NONE;
1012}
1013
1014/*
1015 * Invoke a method for base->method().
1016 */
1017 int
1018call_internal_method(
1019 char_u *name,
1020 int argcount,
1021 typval_T *argvars,
1022 typval_T *rettv,
1023 typval_T *basetv)
1024{
1025 int i;
1026 int fi;
1027 typval_T argv[MAX_FUNC_ARGS + 1];
1028
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001029 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001030 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001031 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001032 if (global_functions[fi].f_argtype == 0)
1033 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001034 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001035 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001036 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001037 return ERROR_TOOMANY;
1038
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001039 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001040 {
1041 // base value goes last
1042 for (i = 0; i < argcount; ++i)
1043 argv[i] = argvars[i];
1044 argv[argcount] = *basetv;
1045 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001046 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001047 {
1048 // base value goes second
1049 argv[0] = argvars[0];
1050 argv[1] = *basetv;
1051 for (i = 1; i < argcount; ++i)
1052 argv[i + 1] = argvars[i];
1053 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001054 else if (global_functions[fi].f_argtype == FEARG_3)
1055 {
1056 // base value goes third
1057 argv[0] = argvars[0];
1058 argv[1] = argvars[1];
1059 argv[2] = *basetv;
1060 for (i = 2; i < argcount; ++i)
1061 argv[i + 1] = argvars[i];
1062 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001063 else
1064 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001065 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001066 argv[0] = *basetv;
1067 for (i = 0; i < argcount; ++i)
1068 argv[i + 1] = argvars[i];
1069 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001070 argv[argcount + 1].v_type = VAR_UNKNOWN;
1071
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001072 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001073 return ERROR_NONE;
1074}
1075
1076/*
1077 * Return TRUE for a non-zero Number and a non-empty String.
1078 */
1079 static int
1080non_zero_arg(typval_T *argvars)
1081{
1082 return ((argvars[0].v_type == VAR_NUMBER
1083 && argvars[0].vval.v_number != 0)
1084 || (argvars[0].v_type == VAR_SPECIAL
1085 && argvars[0].vval.v_number == VVAL_TRUE)
1086 || (argvars[0].v_type == VAR_STRING
1087 && argvars[0].vval.v_string != NULL
1088 && *argvars[0].vval.v_string != NUL));
1089}
1090
1091/*
1092 * Get the lnum from the first argument.
1093 * Also accepts ".", "$", etc., but that only works for the current buffer.
1094 * Returns -1 on error.
1095 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001096 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001097tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001098{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001099 linenr_T lnum;
1100
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001101 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001102 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001103 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001104 int fnum;
1105 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1106
1107 if (fp != NULL)
1108 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001109 }
1110 return lnum;
1111}
1112
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001113/*
1114 * Get the lnum from the first argument.
1115 * Also accepts "$", then "buf" is used.
1116 * Returns 0 on error.
1117 */
1118 static linenr_T
1119tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1120{
1121 if (argvars[0].v_type == VAR_STRING
1122 && argvars[0].vval.v_string != NULL
1123 && argvars[0].vval.v_string[0] == '$'
1124 && buf != NULL)
1125 return buf->b_ml.ml_line_count;
1126 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1127}
1128
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001129#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001130/*
1131 * Get the float value of "argvars[0]" into "f".
1132 * Returns FAIL when the argument is not a Number or Float.
1133 */
1134 static int
1135get_float_arg(typval_T *argvars, float_T *f)
1136{
1137 if (argvars[0].v_type == VAR_FLOAT)
1138 {
1139 *f = argvars[0].vval.v_float;
1140 return OK;
1141 }
1142 if (argvars[0].v_type == VAR_NUMBER)
1143 {
1144 *f = (float_T)argvars[0].vval.v_number;
1145 return OK;
1146 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001147 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001148 return FAIL;
1149}
1150
1151/*
1152 * "abs(expr)" function
1153 */
1154 static void
1155f_abs(typval_T *argvars, typval_T *rettv)
1156{
1157 if (argvars[0].v_type == VAR_FLOAT)
1158 {
1159 rettv->v_type = VAR_FLOAT;
1160 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1161 }
1162 else
1163 {
1164 varnumber_T n;
1165 int error = FALSE;
1166
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001167 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001168 if (error)
1169 rettv->vval.v_number = -1;
1170 else if (n > 0)
1171 rettv->vval.v_number = n;
1172 else
1173 rettv->vval.v_number = -n;
1174 }
1175}
1176
1177/*
1178 * "acos()" function
1179 */
1180 static void
1181f_acos(typval_T *argvars, typval_T *rettv)
1182{
1183 float_T f = 0.0;
1184
1185 rettv->v_type = VAR_FLOAT;
1186 if (get_float_arg(argvars, &f) == OK)
1187 rettv->vval.v_float = acos(f);
1188 else
1189 rettv->vval.v_float = 0.0;
1190}
1191#endif
1192
1193/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001194 * "and(expr, expr)" function
1195 */
1196 static void
1197f_and(typval_T *argvars, typval_T *rettv)
1198{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001199 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1200 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001201}
1202
1203/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001204 * If there is a window for "curbuf", make it the current window.
1205 */
1206 static void
1207find_win_for_curbuf(void)
1208{
1209 wininfo_T *wip;
1210
1211 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1212 {
1213 if (wip->wi_win != NULL)
1214 {
1215 curwin = wip->wi_win;
1216 break;
1217 }
1218 }
1219}
1220
1221/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001222 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001223 */
1224 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001225set_buffer_lines(
1226 buf_T *buf,
1227 linenr_T lnum_arg,
1228 int append,
1229 typval_T *lines,
1230 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001231{
Bram Moolenaarca851592018-06-06 21:04:07 +02001232 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1233 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001234 list_T *l = NULL;
1235 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001236 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001237 linenr_T append_lnum;
1238 buf_T *curbuf_save = NULL;
1239 win_T *curwin_save = NULL;
1240 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001241
Bram Moolenaarca851592018-06-06 21:04:07 +02001242 /* When using the current buffer ml_mfp will be set if needed. Useful when
1243 * setline() is used on startup. For other buffers the buffer must be
1244 * loaded. */
1245 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001246 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001247 rettv->vval.v_number = 1; /* FAIL */
1248 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001249 }
1250
Bram Moolenaarca851592018-06-06 21:04:07 +02001251 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001253 curbuf_save = curbuf;
1254 curwin_save = curwin;
1255 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001256 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001257 }
1258
1259 if (append)
1260 // appendbufline() uses the line number below which we insert
1261 append_lnum = lnum - 1;
1262 else
1263 // setbufline() uses the line number above which we insert, we only
1264 // append if it's below the last line
1265 append_lnum = curbuf->b_ml.ml_line_count;
1266
1267 if (lines->v_type == VAR_LIST)
1268 {
1269 l = lines->vval.v_list;
1270 li = l->lv_first;
1271 }
1272 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001273 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001274
1275 /* default result is zero == OK */
1276 for (;;)
1277 {
1278 if (l != NULL)
1279 {
1280 /* list argument, get next string */
1281 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001282 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001283 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001284 li = li->li_next;
1285 }
1286
Bram Moolenaarca851592018-06-06 21:04:07 +02001287 rettv->vval.v_number = 1; /* FAIL */
1288 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1289 break;
1290
1291 /* When coming here from Insert mode, sync undo, so that this can be
1292 * undone separately from what was previously inserted. */
1293 if (u_sync_once == 2)
1294 {
1295 u_sync_once = 1; /* notify that u_sync() was called */
1296 u_sync(TRUE);
1297 }
1298
1299 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1300 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001301 // Existing line, replace it.
1302 // Removes any existing text properties.
1303 if (u_savesub(lnum) == OK && ml_replace_len(
1304 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001305 {
1306 changed_bytes(lnum, 0);
1307 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1308 check_cursor_col();
1309 rettv->vval.v_number = 0; /* OK */
1310 }
1311 }
1312 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1313 {
1314 /* append the line */
1315 ++added;
1316 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1317 rettv->vval.v_number = 0; /* OK */
1318 }
1319
1320 if (l == NULL) /* only one string argument */
1321 break;
1322 ++lnum;
1323 }
1324
1325 if (added > 0)
1326 {
1327 win_T *wp;
1328 tabpage_T *tp;
1329
1330 appended_lines_mark(append_lnum, added);
Bram Moolenaard2007022019-08-27 21:56:06 +02001331
1332 // Only adjust the cursor for buffers other than the current, unless it
1333 // is the current window. For curbuf and other windows it has been
1334 // done in mark_adjust_internal().
Bram Moolenaarca851592018-06-06 21:04:07 +02001335 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaard2007022019-08-27 21:56:06 +02001336 if (wp->w_buffer == buf
1337 && (wp->w_buffer != curbuf || wp == curwin)
1338 && wp->w_cursor.lnum > append_lnum)
Bram Moolenaarca851592018-06-06 21:04:07 +02001339 wp->w_cursor.lnum += added;
1340 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001341 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001342 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001343
1344 if (!is_curbuf)
1345 {
1346 curbuf = curbuf_save;
1347 curwin = curwin_save;
1348 }
1349}
1350
1351/*
1352 * "append(lnum, string/list)" function
1353 */
1354 static void
1355f_append(typval_T *argvars, typval_T *rettv)
1356{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001357 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001358
1359 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1360}
1361
1362/*
1363 * "appendbufline(buf, lnum, string/list)" function
1364 */
1365 static void
1366f_appendbufline(typval_T *argvars, typval_T *rettv)
1367{
1368 linenr_T lnum;
1369 buf_T *buf;
1370
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001371 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001372 if (buf == NULL)
1373 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001374 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001375 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001376 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001377 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1378 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001379}
1380
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001381#ifdef FEAT_FLOAT
1382/*
1383 * "asin()" function
1384 */
1385 static void
1386f_asin(typval_T *argvars, typval_T *rettv)
1387{
1388 float_T f = 0.0;
1389
1390 rettv->v_type = VAR_FLOAT;
1391 if (get_float_arg(argvars, &f) == OK)
1392 rettv->vval.v_float = asin(f);
1393 else
1394 rettv->vval.v_float = 0.0;
1395}
1396
1397/*
1398 * "atan()" function
1399 */
1400 static void
1401f_atan(typval_T *argvars, typval_T *rettv)
1402{
1403 float_T f = 0.0;
1404
1405 rettv->v_type = VAR_FLOAT;
1406 if (get_float_arg(argvars, &f) == OK)
1407 rettv->vval.v_float = atan(f);
1408 else
1409 rettv->vval.v_float = 0.0;
1410}
1411
1412/*
1413 * "atan2()" function
1414 */
1415 static void
1416f_atan2(typval_T *argvars, typval_T *rettv)
1417{
1418 float_T fx = 0.0, fy = 0.0;
1419
1420 rettv->v_type = VAR_FLOAT;
1421 if (get_float_arg(argvars, &fx) == OK
1422 && get_float_arg(&argvars[1], &fy) == OK)
1423 rettv->vval.v_float = atan2(fx, fy);
1424 else
1425 rettv->vval.v_float = 0.0;
1426}
1427#endif
1428
1429/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001430 * "balloon_show()" function
1431 */
1432#ifdef FEAT_BEVAL
1433 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001434f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1435{
1436 rettv->v_type = VAR_STRING;
1437 if (balloonEval != NULL)
1438 {
1439 if (balloonEval->msg == NULL)
1440 rettv->vval.v_string = NULL;
1441 else
1442 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1443 }
1444}
1445
1446 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001447f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1448{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001449 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001450 {
1451 if (argvars[0].v_type == VAR_LIST
1452# ifdef FEAT_GUI
1453 && !gui.in_use
1454# endif
1455 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001456 {
1457 list_T *l = argvars[0].vval.v_list;
1458
1459 // empty list removes the balloon
1460 post_balloon(balloonEval, NULL,
1461 l == NULL || l->lv_len == 0 ? NULL : l);
1462 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001463 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001464 {
1465 char_u *mesg = tv_get_string_chk(&argvars[0]);
1466
1467 if (mesg != NULL)
1468 // empty string removes the balloon
1469 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1470 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001471 }
1472}
1473
Bram Moolenaar669a8282017-11-19 20:13:05 +01001474# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001475 static void
1476f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1477{
1478 if (rettv_list_alloc(rettv) == OK)
1479 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001480 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001481
1482 if (msg != NULL)
1483 {
1484 pumitem_T *array;
1485 int size = split_message(msg, &array);
1486 int i;
1487
1488 /* Skip the first and last item, they are always empty. */
1489 for (i = 1; i < size - 1; ++i)
1490 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001491 while (size > 0)
1492 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001493 vim_free(array);
1494 }
1495 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001496}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001497# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001498#endif
1499
1500/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 * Find a buffer by number or exact name.
1502 */
1503 static buf_T *
1504find_buffer(typval_T *avar)
1505{
1506 buf_T *buf = NULL;
1507
1508 if (avar->v_type == VAR_NUMBER)
1509 buf = buflist_findnr((int)avar->vval.v_number);
1510 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1511 {
1512 buf = buflist_findname_exp(avar->vval.v_string);
1513 if (buf == NULL)
1514 {
1515 /* No full path name match, try a match with a URL or a "nofile"
1516 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001517 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001518 if (buf->b_fname != NULL
1519 && (path_with_url(buf->b_fname)
1520#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001521 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001522#endif
1523 )
1524 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1525 break;
1526 }
1527 }
1528 return buf;
1529}
1530
1531/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001532 * "bufadd(expr)" function
1533 */
1534 static void
1535f_bufadd(typval_T *argvars, typval_T *rettv)
1536{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001537 char_u *name = tv_get_string(&argvars[0]);
1538
1539 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001540}
1541
1542/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001543 * "bufexists(expr)" function
1544 */
1545 static void
1546f_bufexists(typval_T *argvars, typval_T *rettv)
1547{
1548 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1549}
1550
1551/*
1552 * "buflisted(expr)" function
1553 */
1554 static void
1555f_buflisted(typval_T *argvars, typval_T *rettv)
1556{
1557 buf_T *buf;
1558
1559 buf = find_buffer(&argvars[0]);
1560 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1561}
1562
1563/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001564 * "bufload(expr)" function
1565 */
1566 static void
1567f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1568{
1569 buf_T *buf = get_buf_arg(&argvars[0]);
1570
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001571 if (buf != NULL)
1572 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001573}
1574
1575/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 * "bufloaded(expr)" function
1577 */
1578 static void
1579f_bufloaded(typval_T *argvars, typval_T *rettv)
1580{
1581 buf_T *buf;
1582
1583 buf = find_buffer(&argvars[0]);
1584 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1585}
1586
1587 buf_T *
1588buflist_find_by_name(char_u *name, int curtab_only)
1589{
1590 int save_magic;
1591 char_u *save_cpo;
1592 buf_T *buf;
1593
1594 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1595 save_magic = p_magic;
1596 p_magic = TRUE;
1597 save_cpo = p_cpo;
1598 p_cpo = (char_u *)"";
1599
1600 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1601 TRUE, FALSE, curtab_only));
1602
1603 p_magic = save_magic;
1604 p_cpo = save_cpo;
1605 return buf;
1606}
1607
1608/*
1609 * Get buffer by number or pattern.
1610 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001611 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001612tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001613{
1614 char_u *name = tv->vval.v_string;
1615 buf_T *buf;
1616
1617 if (tv->v_type == VAR_NUMBER)
1618 return buflist_findnr((int)tv->vval.v_number);
1619 if (tv->v_type != VAR_STRING)
1620 return NULL;
1621 if (name == NULL || *name == NUL)
1622 return curbuf;
1623 if (name[0] == '$' && name[1] == NUL)
1624 return lastbuf;
1625
1626 buf = buflist_find_by_name(name, curtab_only);
1627
1628 /* If not found, try expanding the name, like done for bufexists(). */
1629 if (buf == NULL)
1630 buf = find_buffer(tv);
1631
1632 return buf;
1633}
1634
1635/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001636 * Get the buffer from "arg" and give an error and return NULL if it is not
1637 * valid.
1638 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001639 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001640get_buf_arg(typval_T *arg)
1641{
1642 buf_T *buf;
1643
1644 ++emsg_off;
1645 buf = tv_get_buf(arg, FALSE);
1646 --emsg_off;
1647 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001648 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001649 return buf;
1650}
1651
1652/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001653 * "bufname(expr)" function
1654 */
1655 static void
1656f_bufname(typval_T *argvars, typval_T *rettv)
1657{
1658 buf_T *buf;
1659
Bram Moolenaara8eee212019-08-24 22:14:58 +02001660 if (argvars[0].v_type == VAR_UNKNOWN)
1661 buf = curbuf;
1662 else
1663 {
1664 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1665 ++emsg_off;
1666 buf = tv_get_buf(&argvars[0], FALSE);
1667 --emsg_off;
1668 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001669 rettv->v_type = VAR_STRING;
1670 if (buf != NULL && buf->b_fname != NULL)
1671 rettv->vval.v_string = vim_strsave(buf->b_fname);
1672 else
1673 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001674}
1675
1676/*
1677 * "bufnr(expr)" function
1678 */
1679 static void
1680f_bufnr(typval_T *argvars, typval_T *rettv)
1681{
1682 buf_T *buf;
1683 int error = FALSE;
1684 char_u *name;
1685
Bram Moolenaara8eee212019-08-24 22:14:58 +02001686 if (argvars[0].v_type == VAR_UNKNOWN)
1687 buf = curbuf;
1688 else
1689 {
1690 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1691 ++emsg_off;
1692 buf = tv_get_buf(&argvars[0], FALSE);
1693 --emsg_off;
1694 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695
Bram Moolenaara8eee212019-08-24 22:14:58 +02001696 // If the buffer isn't found and the second argument is not zero create a
1697 // new buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001698 if (buf == NULL
1699 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001700 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001701 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001702 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001703 && !error)
1704 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1705
1706 if (buf != NULL)
1707 rettv->vval.v_number = buf->b_fnum;
1708 else
1709 rettv->vval.v_number = -1;
1710}
1711
1712 static void
1713buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1714{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001715 win_T *wp;
1716 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001717 buf_T *buf;
1718
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001719 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001721 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001722 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001723 {
1724 ++winnr;
1725 if (wp->w_buffer == buf)
1726 break;
1727 }
1728 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001729 --emsg_off;
1730}
1731
1732/*
1733 * "bufwinid(nr)" function
1734 */
1735 static void
1736f_bufwinid(typval_T *argvars, typval_T *rettv)
1737{
1738 buf_win_common(argvars, rettv, FALSE);
1739}
1740
1741/*
1742 * "bufwinnr(nr)" function
1743 */
1744 static void
1745f_bufwinnr(typval_T *argvars, typval_T *rettv)
1746{
1747 buf_win_common(argvars, rettv, TRUE);
1748}
1749
1750/*
1751 * "byte2line(byte)" function
1752 */
1753 static void
1754f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1755{
1756#ifndef FEAT_BYTEOFF
1757 rettv->vval.v_number = -1;
1758#else
1759 long boff = 0;
1760
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001761 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001762 if (boff < 0)
1763 rettv->vval.v_number = -1;
1764 else
1765 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1766 (linenr_T)0, &boff);
1767#endif
1768}
1769
1770 static void
1771byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1772{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001774 char_u *str;
1775 varnumber_T idx;
1776
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001777 str = tv_get_string_chk(&argvars[0]);
1778 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001779 rettv->vval.v_number = -1;
1780 if (str == NULL || idx < 0)
1781 return;
1782
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001783 t = str;
1784 for ( ; idx > 0; idx--)
1785 {
1786 if (*t == NUL) /* EOL reached */
1787 return;
1788 if (enc_utf8 && comp)
1789 t += utf_ptr2len(t);
1790 else
1791 t += (*mb_ptr2len)(t);
1792 }
1793 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001794}
1795
1796/*
1797 * "byteidx()" function
1798 */
1799 static void
1800f_byteidx(typval_T *argvars, typval_T *rettv)
1801{
1802 byteidx(argvars, rettv, FALSE);
1803}
1804
1805/*
1806 * "byteidxcomp()" function
1807 */
1808 static void
1809f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1810{
1811 byteidx(argvars, rettv, TRUE);
1812}
1813
1814/*
1815 * "call(func, arglist [, dict])" function
1816 */
1817 static void
1818f_call(typval_T *argvars, typval_T *rettv)
1819{
1820 char_u *func;
1821 partial_T *partial = NULL;
1822 dict_T *selfdict = NULL;
1823
1824 if (argvars[1].v_type != VAR_LIST)
1825 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001826 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001827 return;
1828 }
1829 if (argvars[1].vval.v_list == NULL)
1830 return;
1831
1832 if (argvars[0].v_type == VAR_FUNC)
1833 func = argvars[0].vval.v_string;
1834 else if (argvars[0].v_type == VAR_PARTIAL)
1835 {
1836 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001837 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001838 }
1839 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001840 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001841 if (*func == NUL)
1842 return; /* type error or empty name */
1843
1844 if (argvars[2].v_type != VAR_UNKNOWN)
1845 {
1846 if (argvars[2].v_type != VAR_DICT)
1847 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001848 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001849 return;
1850 }
1851 selfdict = argvars[2].vval.v_dict;
1852 }
1853
1854 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1855}
1856
1857#ifdef FEAT_FLOAT
1858/*
1859 * "ceil({float})" function
1860 */
1861 static void
1862f_ceil(typval_T *argvars, typval_T *rettv)
1863{
1864 float_T f = 0.0;
1865
1866 rettv->v_type = VAR_FLOAT;
1867 if (get_float_arg(argvars, &f) == OK)
1868 rettv->vval.v_float = ceil(f);
1869 else
1870 rettv->vval.v_float = 0.0;
1871}
1872#endif
1873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001874/*
1875 * "changenr()" function
1876 */
1877 static void
1878f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1879{
1880 rettv->vval.v_number = curbuf->b_u_seq_cur;
1881}
1882
1883/*
1884 * "char2nr(string)" function
1885 */
1886 static void
1887f_char2nr(typval_T *argvars, typval_T *rettv)
1888{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 if (has_mbyte)
1890 {
1891 int utf8 = 0;
1892
1893 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001894 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001895
1896 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001897 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001898 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001899 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900 }
1901 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001902 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001903}
1904
1905/*
1906 * "cindent(lnum)" function
1907 */
1908 static void
1909f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1910{
1911#ifdef FEAT_CINDENT
1912 pos_T pos;
1913 linenr_T lnum;
1914
1915 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001916 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001917 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1918 {
1919 curwin->w_cursor.lnum = lnum;
1920 rettv->vval.v_number = get_c_indent();
1921 curwin->w_cursor = pos;
1922 }
1923 else
1924#endif
1925 rettv->vval.v_number = -1;
1926}
1927
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001928 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001929get_optional_window(typval_T *argvars, int idx)
1930{
1931 win_T *win = curwin;
1932
1933 if (argvars[idx].v_type != VAR_UNKNOWN)
1934 {
1935 win = find_win_by_nr_or_id(&argvars[idx]);
1936 if (win == NULL)
1937 {
1938 emsg(_(e_invalwindow));
1939 return NULL;
1940 }
1941 }
1942 return win;
1943}
1944
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001945/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001946 * "col(string)" function
1947 */
1948 static void
1949f_col(typval_T *argvars, typval_T *rettv)
1950{
1951 colnr_T col = 0;
1952 pos_T *fp;
1953 int fnum = curbuf->b_fnum;
1954
1955 fp = var2fpos(&argvars[0], FALSE, &fnum);
1956 if (fp != NULL && fnum == curbuf->b_fnum)
1957 {
1958 if (fp->col == MAXCOL)
1959 {
1960 /* '> can be MAXCOL, get the length of the line then */
1961 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1962 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1963 else
1964 col = MAXCOL;
1965 }
1966 else
1967 {
1968 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001969 /* col(".") when the cursor is on the NUL at the end of the line
1970 * because of "coladd" can be seen as an extra column. */
1971 if (virtual_active() && fp == &curwin->w_cursor)
1972 {
1973 char_u *p = ml_get_cursor();
1974
1975 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1976 curwin->w_virtcol - curwin->w_cursor.coladd))
1977 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 int l;
1979
1980 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1981 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001982 }
1983 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001984 }
1985 }
1986 rettv->vval.v_number = col;
1987}
1988
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989/*
1990 * "confirm(message, buttons[, default [, type]])" function
1991 */
1992 static void
1993f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1994{
1995#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1996 char_u *message;
1997 char_u *buttons = NULL;
1998 char_u buf[NUMBUFLEN];
1999 char_u buf2[NUMBUFLEN];
2000 int def = 1;
2001 int type = VIM_GENERIC;
2002 char_u *typestr;
2003 int error = FALSE;
2004
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002005 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006 if (message == NULL)
2007 error = TRUE;
2008 if (argvars[1].v_type != VAR_UNKNOWN)
2009 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002010 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002011 if (buttons == NULL)
2012 error = TRUE;
2013 if (argvars[2].v_type != VAR_UNKNOWN)
2014 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002015 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002016 if (argvars[3].v_type != VAR_UNKNOWN)
2017 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002018 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 if (typestr == NULL)
2020 error = TRUE;
2021 else
2022 {
2023 switch (TOUPPER_ASC(*typestr))
2024 {
2025 case 'E': type = VIM_ERROR; break;
2026 case 'Q': type = VIM_QUESTION; break;
2027 case 'I': type = VIM_INFO; break;
2028 case 'W': type = VIM_WARNING; break;
2029 case 'G': type = VIM_GENERIC; break;
2030 }
2031 }
2032 }
2033 }
2034 }
2035
2036 if (buttons == NULL || *buttons == NUL)
2037 buttons = (char_u *)_("&Ok");
2038
2039 if (!error)
2040 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2041 def, NULL, FALSE);
2042#endif
2043}
2044
2045/*
2046 * "copy()" function
2047 */
2048 static void
2049f_copy(typval_T *argvars, typval_T *rettv)
2050{
2051 item_copy(&argvars[0], rettv, FALSE, 0);
2052}
2053
2054#ifdef FEAT_FLOAT
2055/*
2056 * "cos()" function
2057 */
2058 static void
2059f_cos(typval_T *argvars, typval_T *rettv)
2060{
2061 float_T f = 0.0;
2062
2063 rettv->v_type = VAR_FLOAT;
2064 if (get_float_arg(argvars, &f) == OK)
2065 rettv->vval.v_float = cos(f);
2066 else
2067 rettv->vval.v_float = 0.0;
2068}
2069
2070/*
2071 * "cosh()" function
2072 */
2073 static void
2074f_cosh(typval_T *argvars, typval_T *rettv)
2075{
2076 float_T f = 0.0;
2077
2078 rettv->v_type = VAR_FLOAT;
2079 if (get_float_arg(argvars, &f) == OK)
2080 rettv->vval.v_float = cosh(f);
2081 else
2082 rettv->vval.v_float = 0.0;
2083}
2084#endif
2085
2086/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002087 * "cursor(lnum, col)" function, or
2088 * "cursor(list)"
2089 *
2090 * Moves the cursor to the specified line and column.
2091 * Returns 0 when the position could be set, -1 otherwise.
2092 */
2093 static void
2094f_cursor(typval_T *argvars, typval_T *rettv)
2095{
2096 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 int set_curswant = TRUE;
2099
2100 rettv->vval.v_number = -1;
2101 if (argvars[1].v_type == VAR_UNKNOWN)
2102 {
2103 pos_T pos;
2104 colnr_T curswant = -1;
2105
2106 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2107 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002108 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002109 return;
2110 }
2111 line = pos.lnum;
2112 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002113 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002114 if (curswant >= 0)
2115 {
2116 curwin->w_curswant = curswant - 1;
2117 set_curswant = FALSE;
2118 }
2119 }
2120 else
2121 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002122 line = tv_get_lnum(argvars);
2123 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002124 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002125 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002126 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002127 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002128 return; /* type error; errmsg already given */
2129 if (line > 0)
2130 curwin->w_cursor.lnum = line;
2131 if (col > 0)
2132 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002133 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002134
2135 /* Make sure the cursor is in a valid position. */
2136 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002137 /* Correct cursor for multi-byte character. */
2138 if (has_mbyte)
2139 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002140
2141 curwin->w_set_curswant = set_curswant;
2142 rettv->vval.v_number = 0;
2143}
2144
Bram Moolenaar4f974752019-02-17 17:44:42 +01002145#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002146/*
2147 * "debugbreak()" function
2148 */
2149 static void
2150f_debugbreak(typval_T *argvars, typval_T *rettv)
2151{
2152 int pid;
2153
2154 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002155 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002156 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002157 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002158 else
2159 {
2160 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2161
2162 if (hProcess != NULL)
2163 {
2164 DebugBreakProcess(hProcess);
2165 CloseHandle(hProcess);
2166 rettv->vval.v_number = OK;
2167 }
2168 }
2169}
2170#endif
2171
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172/*
2173 * "deepcopy()" function
2174 */
2175 static void
2176f_deepcopy(typval_T *argvars, typval_T *rettv)
2177{
2178 int noref = 0;
2179 int copyID;
2180
2181 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002182 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002183 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002184 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002185 else
2186 {
2187 copyID = get_copyID();
2188 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2189 }
2190}
2191
2192/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002193 * "deletebufline()" function
2194 */
2195 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002196f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002197{
2198 buf_T *buf;
2199 linenr_T first, last;
2200 linenr_T lnum;
2201 long count;
2202 int is_curbuf;
2203 buf_T *curbuf_save = NULL;
2204 win_T *curwin_save = NULL;
2205 tabpage_T *tp;
2206 win_T *wp;
2207
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002208 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002209 if (buf == NULL)
2210 {
2211 rettv->vval.v_number = 1; /* FAIL */
2212 return;
2213 }
2214 is_curbuf = buf == curbuf;
2215
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002216 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002217 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002218 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002219 else
2220 last = first;
2221
2222 if (buf->b_ml.ml_mfp == NULL || first < 1
2223 || first > buf->b_ml.ml_line_count || last < first)
2224 {
2225 rettv->vval.v_number = 1; /* FAIL */
2226 return;
2227 }
2228
2229 if (!is_curbuf)
2230 {
2231 curbuf_save = curbuf;
2232 curwin_save = curwin;
2233 curbuf = buf;
2234 find_win_for_curbuf();
2235 }
2236 if (last > curbuf->b_ml.ml_line_count)
2237 last = curbuf->b_ml.ml_line_count;
2238 count = last - first + 1;
2239
2240 // When coming here from Insert mode, sync undo, so that this can be
2241 // undone separately from what was previously inserted.
2242 if (u_sync_once == 2)
2243 {
2244 u_sync_once = 1; // notify that u_sync() was called
2245 u_sync(TRUE);
2246 }
2247
2248 if (u_save(first - 1, last + 1) == FAIL)
2249 {
2250 rettv->vval.v_number = 1; /* FAIL */
2251 return;
2252 }
2253
2254 for (lnum = first; lnum <= last; ++lnum)
2255 ml_delete(first, TRUE);
2256
2257 FOR_ALL_TAB_WINDOWS(tp, wp)
2258 if (wp->w_buffer == buf)
2259 {
2260 if (wp->w_cursor.lnum > last)
2261 wp->w_cursor.lnum -= count;
2262 else if (wp->w_cursor.lnum> first)
2263 wp->w_cursor.lnum = first;
2264 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2265 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2266 }
2267 check_cursor_col();
2268 deleted_lines_mark(first, count);
2269
2270 if (!is_curbuf)
2271 {
2272 curbuf = curbuf_save;
2273 curwin = curwin_save;
2274 }
2275}
2276
2277/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002278 * "did_filetype()" function
2279 */
2280 static void
2281f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2282{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002283 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002284}
2285
2286/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002287 * "empty({expr})" function
2288 */
2289 static void
2290f_empty(typval_T *argvars, typval_T *rettv)
2291{
2292 int n = FALSE;
2293
2294 switch (argvars[0].v_type)
2295 {
2296 case VAR_STRING:
2297 case VAR_FUNC:
2298 n = argvars[0].vval.v_string == NULL
2299 || *argvars[0].vval.v_string == NUL;
2300 break;
2301 case VAR_PARTIAL:
2302 n = FALSE;
2303 break;
2304 case VAR_NUMBER:
2305 n = argvars[0].vval.v_number == 0;
2306 break;
2307 case VAR_FLOAT:
2308#ifdef FEAT_FLOAT
2309 n = argvars[0].vval.v_float == 0.0;
2310 break;
2311#endif
2312 case VAR_LIST:
2313 n = argvars[0].vval.v_list == NULL
2314 || argvars[0].vval.v_list->lv_first == NULL;
2315 break;
2316 case VAR_DICT:
2317 n = argvars[0].vval.v_dict == NULL
2318 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2319 break;
2320 case VAR_SPECIAL:
2321 n = argvars[0].vval.v_number != VVAL_TRUE;
2322 break;
2323
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002324 case VAR_BLOB:
2325 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002326 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2327 break;
2328
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002329 case VAR_JOB:
2330#ifdef FEAT_JOB_CHANNEL
2331 n = argvars[0].vval.v_job == NULL
2332 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2333 break;
2334#endif
2335 case VAR_CHANNEL:
2336#ifdef FEAT_JOB_CHANNEL
2337 n = argvars[0].vval.v_channel == NULL
2338 || !channel_is_open(argvars[0].vval.v_channel);
2339 break;
2340#endif
2341 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002342 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343 n = TRUE;
2344 break;
2345 }
2346
2347 rettv->vval.v_number = n;
2348}
2349
2350/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002351 * "environ()" function
2352 */
2353 static void
2354f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2355{
2356#if !defined(AMIGA)
2357 int i = 0;
2358 char_u *entry, *value;
2359# ifdef MSWIN
2360 extern wchar_t **_wenviron;
2361# else
2362 extern char **environ;
2363# endif
2364
2365 if (rettv_dict_alloc(rettv) != OK)
2366 return;
2367
2368# ifdef MSWIN
2369 if (*_wenviron == NULL)
2370 return;
2371# else
2372 if (*environ == NULL)
2373 return;
2374# endif
2375
2376 for (i = 0; ; ++i)
2377 {
2378# ifdef MSWIN
2379 short_u *p;
2380
2381 if ((p = (short_u *)_wenviron[i]) == NULL)
2382 return;
2383 entry = utf16_to_enc(p, NULL);
2384# else
2385 if ((entry = (char_u *)environ[i]) == NULL)
2386 return;
2387 entry = vim_strsave(entry);
2388# endif
2389 if (entry == NULL) // out of memory
2390 return;
2391 if ((value = vim_strchr(entry, '=')) == NULL)
2392 {
2393 vim_free(entry);
2394 continue;
2395 }
2396 *value++ = NUL;
2397 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2398 vim_free(entry);
2399 }
2400#endif
2401}
2402
2403/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002404 * "escape({string}, {chars})" function
2405 */
2406 static void
2407f_escape(typval_T *argvars, typval_T *rettv)
2408{
2409 char_u buf[NUMBUFLEN];
2410
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002411 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2412 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002413 rettv->v_type = VAR_STRING;
2414}
2415
2416/*
2417 * "eval()" function
2418 */
2419 static void
2420f_eval(typval_T *argvars, typval_T *rettv)
2421{
2422 char_u *s, *p;
2423
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002424 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002425 if (s != NULL)
2426 s = skipwhite(s);
2427
2428 p = s;
2429 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2430 {
2431 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002432 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002433 need_clr_eos = FALSE;
2434 rettv->v_type = VAR_NUMBER;
2435 rettv->vval.v_number = 0;
2436 }
2437 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002438 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002439}
2440
2441/*
2442 * "eventhandler()" function
2443 */
2444 static void
2445f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2446{
2447 rettv->vval.v_number = vgetc_busy;
2448}
2449
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450static garray_T redir_execute_ga;
2451
2452/*
2453 * Append "value[value_len]" to the execute() output.
2454 */
2455 void
2456execute_redir_str(char_u *value, int value_len)
2457{
2458 int len;
2459
2460 if (value_len == -1)
2461 len = (int)STRLEN(value); /* Append the entire string */
2462 else
2463 len = value_len; /* Append only "value_len" characters */
2464 if (ga_grow(&redir_execute_ga, len) == OK)
2465 {
2466 mch_memmove((char *)redir_execute_ga.ga_data
2467 + redir_execute_ga.ga_len, value, len);
2468 redir_execute_ga.ga_len += len;
2469 }
2470}
2471
2472/*
2473 * Get next line from a list.
2474 * Called by do_cmdline() to get the next line.
2475 * Returns allocated string, or NULL for end of function.
2476 */
2477
2478 static char_u *
2479get_list_line(
2480 int c UNUSED,
2481 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002482 int indent UNUSED,
2483 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002484{
2485 listitem_T **p = (listitem_T **)cookie;
2486 listitem_T *item = *p;
2487 char_u buf[NUMBUFLEN];
2488 char_u *s;
2489
2490 if (item == NULL)
2491 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002492 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002493 *p = item->li_next;
2494 return s == NULL ? NULL : vim_strsave(s);
2495}
2496
2497/*
2498 * "execute()" function
2499 */
2500 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002501execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002502{
2503 char_u *cmd = NULL;
2504 list_T *list = NULL;
2505 int save_msg_silent = msg_silent;
2506 int save_emsg_silent = emsg_silent;
2507 int save_emsg_noredir = emsg_noredir;
2508 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002509 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002510 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002511 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002512 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002513
2514 rettv->vval.v_string = NULL;
2515 rettv->v_type = VAR_STRING;
2516
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002517 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002518 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002519 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002520 if (list == NULL || list->lv_first == NULL)
2521 /* empty list, no commands, empty output */
2522 return;
2523 ++list->lv_refcount;
2524 }
2525 else
2526 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002527 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528 if (cmd == NULL)
2529 return;
2530 }
2531
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002532 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002533 {
2534 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002535 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002536
2537 if (s == NULL)
2538 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002539 if (*s == NUL)
2540 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 if (STRNCMP(s, "silent", 6) == 0)
2542 ++msg_silent;
2543 if (STRCMP(s, "silent!") == 0)
2544 {
2545 emsg_silent = TRUE;
2546 emsg_noredir = TRUE;
2547 }
2548 }
2549 else
2550 ++msg_silent;
2551
2552 if (redir_execute)
2553 save_ga = redir_execute_ga;
2554 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2555 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002556 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002557 if (!echo_output)
2558 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002559
2560 if (cmd != NULL)
2561 do_cmdline_cmd(cmd);
2562 else
2563 {
2564 listitem_T *item = list->lv_first;
2565
2566 do_cmdline(NULL, get_list_line, (void *)&item,
2567 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2568 --list->lv_refcount;
2569 }
2570
Bram Moolenaard297f352017-01-29 20:31:21 +01002571 /* Need to append a NUL to the result. */
2572 if (ga_grow(&redir_execute_ga, 1) == OK)
2573 {
2574 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2575 rettv->vval.v_string = redir_execute_ga.ga_data;
2576 }
2577 else
2578 {
2579 ga_clear(&redir_execute_ga);
2580 rettv->vval.v_string = NULL;
2581 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 msg_silent = save_msg_silent;
2583 emsg_silent = save_emsg_silent;
2584 emsg_noredir = save_emsg_noredir;
2585
2586 redir_execute = save_redir_execute;
2587 if (redir_execute)
2588 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002589 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002590
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002591 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002592 if (echo_output)
2593 // When not working silently: put it in column zero. A following
2594 // "echon" will overwrite the message, unavoidably.
2595 msg_col = 0;
2596 else
2597 // When working silently: Put it back where it was, since nothing
2598 // should have been written.
2599 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002600}
2601
2602/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002603 * "execute()" function
2604 */
2605 static void
2606f_execute(typval_T *argvars, typval_T *rettv)
2607{
2608 execute_common(argvars, rettv, 0);
2609}
2610
2611/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002612 * "exists()" function
2613 */
2614 static void
2615f_exists(typval_T *argvars, typval_T *rettv)
2616{
2617 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002619
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002620 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 if (*p == '$') /* environment variable */
2622 {
2623 /* first try "normal" environment variables (fast) */
2624 if (mch_getenv(p + 1) != NULL)
2625 n = TRUE;
2626 else
2627 {
2628 /* try expanding things like $VIM and ${HOME} */
2629 p = expand_env_save(p);
2630 if (p != NULL && *p != '$')
2631 n = TRUE;
2632 vim_free(p);
2633 }
2634 }
2635 else if (*p == '&' || *p == '+') /* option */
2636 {
2637 n = (get_option_tv(&p, NULL, TRUE) == OK);
2638 if (*skipwhite(p) != NUL)
2639 n = FALSE; /* trailing garbage */
2640 }
2641 else if (*p == '*') /* internal or user defined function */
2642 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002643 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002644 }
2645 else if (*p == ':')
2646 {
2647 n = cmd_exists(p + 1);
2648 }
2649 else if (*p == '#')
2650 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 if (p[1] == '#')
2652 n = autocmd_supported(p + 2);
2653 else
2654 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655 }
2656 else /* internal variable */
2657 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002658 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002659 }
2660
2661 rettv->vval.v_number = n;
2662}
2663
2664#ifdef FEAT_FLOAT
2665/*
2666 * "exp()" function
2667 */
2668 static void
2669f_exp(typval_T *argvars, typval_T *rettv)
2670{
2671 float_T f = 0.0;
2672
2673 rettv->v_type = VAR_FLOAT;
2674 if (get_float_arg(argvars, &f) == OK)
2675 rettv->vval.v_float = exp(f);
2676 else
2677 rettv->vval.v_float = 0.0;
2678}
2679#endif
2680
2681/*
2682 * "expand()" function
2683 */
2684 static void
2685f_expand(typval_T *argvars, typval_T *rettv)
2686{
2687 char_u *s;
2688 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002689 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002690 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2691 expand_T xpc;
2692 int error = FALSE;
2693 char_u *result;
2694
2695 rettv->v_type = VAR_STRING;
2696 if (argvars[1].v_type != VAR_UNKNOWN
2697 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002698 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002700 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002701
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002702 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703 if (*s == '%' || *s == '#' || *s == '<')
2704 {
2705 ++emsg_off;
2706 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2707 --emsg_off;
2708 if (rettv->v_type == VAR_LIST)
2709 {
2710 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2711 list_append_string(rettv->vval.v_list, result, -1);
2712 else
2713 vim_free(result);
2714 }
2715 else
2716 rettv->vval.v_string = result;
2717 }
2718 else
2719 {
2720 /* When the optional second argument is non-zero, don't remove matches
2721 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2722 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002723 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002724 options |= WILD_KEEP_ALL;
2725 if (!error)
2726 {
2727 ExpandInit(&xpc);
2728 xpc.xp_context = EXPAND_FILES;
2729 if (p_wic)
2730 options += WILD_ICASE;
2731 if (rettv->v_type == VAR_STRING)
2732 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2733 options, WILD_ALL);
2734 else if (rettv_list_alloc(rettv) != FAIL)
2735 {
2736 int i;
2737
2738 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2739 for (i = 0; i < xpc.xp_numfiles; i++)
2740 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2741 ExpandCleanup(&xpc);
2742 }
2743 }
2744 else
2745 rettv->vval.v_string = NULL;
2746 }
2747}
2748
2749/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002750 * "expandcmd()" function
2751 * Expand all the special characters in a command string.
2752 */
2753 static void
2754f_expandcmd(typval_T *argvars, typval_T *rettv)
2755{
2756 exarg_T eap;
2757 char_u *cmdstr;
2758 char *errormsg = NULL;
2759
2760 rettv->v_type = VAR_STRING;
2761 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2762
2763 memset(&eap, 0, sizeof(eap));
2764 eap.cmd = cmdstr;
2765 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002766 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002767 eap.usefilter = FALSE;
2768 eap.nextcmd = NULL;
2769 eap.cmdidx = CMD_USER;
2770
2771 expand_filename(&eap, &cmdstr, &errormsg);
2772 if (errormsg != NULL && *errormsg != NUL)
2773 emsg(errormsg);
2774
2775 rettv->vval.v_string = cmdstr;
2776}
2777
2778/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002779 * "feedkeys()" function
2780 */
2781 static void
2782f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2783{
2784 int remap = TRUE;
2785 int insert = FALSE;
2786 char_u *keys, *flags;
2787 char_u nbuf[NUMBUFLEN];
2788 int typed = FALSE;
2789 int execute = FALSE;
2790 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002791 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792 char_u *keys_esc;
2793
2794 /* This is not allowed in the sandbox. If the commands would still be
2795 * executed in the sandbox it would be OK, but it probably happens later,
2796 * when "sandbox" is no longer set. */
2797 if (check_secure())
2798 return;
2799
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002800 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002801
2802 if (argvars[1].v_type != VAR_UNKNOWN)
2803 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002804 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002805 for ( ; *flags != NUL; ++flags)
2806 {
2807 switch (*flags)
2808 {
2809 case 'n': remap = FALSE; break;
2810 case 'm': remap = TRUE; break;
2811 case 't': typed = TRUE; break;
2812 case 'i': insert = TRUE; break;
2813 case 'x': execute = TRUE; break;
2814 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002815 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002816 }
2817 }
2818 }
2819
2820 if (*keys != NUL || execute)
2821 {
2822 /* Need to escape K_SPECIAL and CSI before putting the string in the
2823 * typeahead buffer. */
2824 keys_esc = vim_strsave_escape_csi(keys);
2825 if (keys_esc != NULL)
2826 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002827 if (lowlevel)
2828 {
2829#ifdef USE_INPUT_BUF
2830 add_to_input_buf(keys, (int)STRLEN(keys));
2831#else
2832 emsg(_("E980: lowlevel input not supported"));
2833#endif
2834 }
2835 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002836 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002837 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002838 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002839 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002840#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002841 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002842#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002843 )
2844 typebuf_was_filled = TRUE;
2845 }
2846 vim_free(keys_esc);
2847
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848 if (execute)
2849 {
2850 int save_msg_scroll = msg_scroll;
2851
2852 /* Avoid a 1 second delay when the keys start Insert mode. */
2853 msg_scroll = FALSE;
2854
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002855 if (!dangerous)
2856 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002857 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002858 if (!dangerous)
2859 --ex_normal_busy;
2860
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002861 msg_scroll |= save_msg_scroll;
2862 }
2863 }
2864 }
2865}
2866
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002867#ifdef FEAT_FLOAT
2868/*
2869 * "float2nr({float})" function
2870 */
2871 static void
2872f_float2nr(typval_T *argvars, typval_T *rettv)
2873{
2874 float_T f = 0.0;
2875
2876 if (get_float_arg(argvars, &f) == OK)
2877 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002878 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002879 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002880 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002881 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002882 else
2883 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002884 }
2885}
2886
2887/*
2888 * "floor({float})" function
2889 */
2890 static void
2891f_floor(typval_T *argvars, typval_T *rettv)
2892{
2893 float_T f = 0.0;
2894
2895 rettv->v_type = VAR_FLOAT;
2896 if (get_float_arg(argvars, &f) == OK)
2897 rettv->vval.v_float = floor(f);
2898 else
2899 rettv->vval.v_float = 0.0;
2900}
2901
2902/*
2903 * "fmod()" function
2904 */
2905 static void
2906f_fmod(typval_T *argvars, typval_T *rettv)
2907{
2908 float_T fx = 0.0, fy = 0.0;
2909
2910 rettv->v_type = VAR_FLOAT;
2911 if (get_float_arg(argvars, &fx) == OK
2912 && get_float_arg(&argvars[1], &fy) == OK)
2913 rettv->vval.v_float = fmod(fx, fy);
2914 else
2915 rettv->vval.v_float = 0.0;
2916}
2917#endif
2918
2919/*
2920 * "fnameescape({string})" function
2921 */
2922 static void
2923f_fnameescape(typval_T *argvars, typval_T *rettv)
2924{
2925 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002926 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002927 rettv->v_type = VAR_STRING;
2928}
2929
2930/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002931 * "foreground()" function
2932 */
2933 static void
2934f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2935{
2936#ifdef FEAT_GUI
2937 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002938 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002939 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002940 return;
2941 }
2942#endif
2943#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002944 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002945#endif
2946}
2947
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002948 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002949common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002950{
2951 char_u *s;
2952 char_u *name;
2953 int use_string = FALSE;
2954 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002955 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002956
2957 if (argvars[0].v_type == VAR_FUNC)
2958 {
2959 /* function(MyFunc, [arg], dict) */
2960 s = argvars[0].vval.v_string;
2961 }
2962 else if (argvars[0].v_type == VAR_PARTIAL
2963 && argvars[0].vval.v_partial != NULL)
2964 {
2965 /* function(dict.MyFunc, [arg]) */
2966 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002967 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002968 }
2969 else
2970 {
2971 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002972 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002973 use_string = TRUE;
2974 }
2975
Bram Moolenaar843b8842016-08-21 14:36:15 +02002976 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002977 {
2978 name = s;
2979 trans_name = trans_function_name(&name, FALSE,
2980 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2981 if (*name != NUL)
2982 s = NULL;
2983 }
2984
Bram Moolenaar843b8842016-08-21 14:36:15 +02002985 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2986 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002987 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002988 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002989 else if (trans_name != NULL && (is_funcref
2990 ? find_func(trans_name) == NULL
2991 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002992 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002993 else
2994 {
2995 int dict_idx = 0;
2996 int arg_idx = 0;
2997 list_T *list = NULL;
2998
2999 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3000 {
3001 char sid_buf[25];
3002 int off = *s == 's' ? 2 : 5;
3003
3004 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3005 * also be called from another script. Using trans_function_name()
3006 * would also work, but some plugins depend on the name being
3007 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003008 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003009 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003010 if (name != NULL)
3011 {
3012 STRCPY(name, sid_buf);
3013 STRCAT(name, s + off);
3014 }
3015 }
3016 else
3017 name = vim_strsave(s);
3018
3019 if (argvars[1].v_type != VAR_UNKNOWN)
3020 {
3021 if (argvars[2].v_type != VAR_UNKNOWN)
3022 {
3023 /* function(name, [args], dict) */
3024 arg_idx = 1;
3025 dict_idx = 2;
3026 }
3027 else if (argvars[1].v_type == VAR_DICT)
3028 /* function(name, dict) */
3029 dict_idx = 1;
3030 else
3031 /* function(name, [args]) */
3032 arg_idx = 1;
3033 if (dict_idx > 0)
3034 {
3035 if (argvars[dict_idx].v_type != VAR_DICT)
3036 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003037 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003039 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003040 }
3041 if (argvars[dict_idx].vval.v_dict == NULL)
3042 dict_idx = 0;
3043 }
3044 if (arg_idx > 0)
3045 {
3046 if (argvars[arg_idx].v_type != VAR_LIST)
3047 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003048 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003049 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003050 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003051 }
3052 list = argvars[arg_idx].vval.v_list;
3053 if (list == NULL || list->lv_len == 0)
3054 arg_idx = 0;
3055 }
3056 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003057 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003059 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003060
3061 /* result is a VAR_PARTIAL */
3062 if (pt == NULL)
3063 vim_free(name);
3064 else
3065 {
3066 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3067 {
3068 listitem_T *li;
3069 int i = 0;
3070 int arg_len = 0;
3071 int lv_len = 0;
3072
3073 if (arg_pt != NULL)
3074 arg_len = arg_pt->pt_argc;
3075 if (list != NULL)
3076 lv_len = list->lv_len;
3077 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003078 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079 if (pt->pt_argv == NULL)
3080 {
3081 vim_free(pt);
3082 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003083 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003084 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003085 for (i = 0; i < arg_len; i++)
3086 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3087 if (lv_len > 0)
3088 for (li = list->lv_first; li != NULL;
3089 li = li->li_next)
3090 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003091 }
3092
3093 /* For "function(dict.func, [], dict)" and "func" is a partial
3094 * use "dict". That is backwards compatible. */
3095 if (dict_idx > 0)
3096 {
3097 /* The dict is bound explicitly, pt_auto is FALSE. */
3098 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3099 ++pt->pt_dict->dv_refcount;
3100 }
3101 else if (arg_pt != NULL)
3102 {
3103 /* If the dict was bound automatically the result is also
3104 * bound automatically. */
3105 pt->pt_dict = arg_pt->pt_dict;
3106 pt->pt_auto = arg_pt->pt_auto;
3107 if (pt->pt_dict != NULL)
3108 ++pt->pt_dict->dv_refcount;
3109 }
3110
3111 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003112 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3113 {
3114 pt->pt_func = arg_pt->pt_func;
3115 func_ptr_ref(pt->pt_func);
3116 vim_free(name);
3117 }
3118 else if (is_funcref)
3119 {
3120 pt->pt_func = find_func(trans_name);
3121 func_ptr_ref(pt->pt_func);
3122 vim_free(name);
3123 }
3124 else
3125 {
3126 pt->pt_name = name;
3127 func_ref(name);
3128 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003129 }
3130 rettv->v_type = VAR_PARTIAL;
3131 rettv->vval.v_partial = pt;
3132 }
3133 else
3134 {
3135 /* result is a VAR_FUNC */
3136 rettv->v_type = VAR_FUNC;
3137 rettv->vval.v_string = name;
3138 func_ref(name);
3139 }
3140 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003141theend:
3142 vim_free(trans_name);
3143}
3144
3145/*
3146 * "funcref()" function
3147 */
3148 static void
3149f_funcref(typval_T *argvars, typval_T *rettv)
3150{
3151 common_function(argvars, rettv, TRUE);
3152}
3153
3154/*
3155 * "function()" function
3156 */
3157 static void
3158f_function(typval_T *argvars, typval_T *rettv)
3159{
3160 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003161}
3162
3163/*
3164 * "garbagecollect()" function
3165 */
3166 static void
3167f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3168{
3169 /* This is postponed until we are back at the toplevel, because we may be
3170 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3171 want_garbage_collect = TRUE;
3172
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003173 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003174 garbage_collect_at_exit = TRUE;
3175}
3176
3177/*
3178 * "get()" function
3179 */
3180 static void
3181f_get(typval_T *argvars, typval_T *rettv)
3182{
3183 listitem_T *li;
3184 list_T *l;
3185 dictitem_T *di;
3186 dict_T *d;
3187 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003188 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003189
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003190 if (argvars[0].v_type == VAR_BLOB)
3191 {
3192 int error = FALSE;
3193 int idx = tv_get_number_chk(&argvars[1], &error);
3194
3195 if (!error)
3196 {
3197 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003198 if (idx < 0)
3199 idx = blob_len(argvars[0].vval.v_blob) + idx;
3200 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
3201 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003202 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003203 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003204 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003205 tv = rettv;
3206 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003207 }
3208 }
3209 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003210 {
3211 if ((l = argvars[0].vval.v_list) != NULL)
3212 {
3213 int error = FALSE;
3214
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003215 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216 if (!error && li != NULL)
3217 tv = &li->li_tv;
3218 }
3219 }
3220 else if (argvars[0].v_type == VAR_DICT)
3221 {
3222 if ((d = argvars[0].vval.v_dict) != NULL)
3223 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003224 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003225 if (di != NULL)
3226 tv = &di->di_tv;
3227 }
3228 }
3229 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3230 {
3231 partial_T *pt;
3232 partial_T fref_pt;
3233
3234 if (argvars[0].v_type == VAR_PARTIAL)
3235 pt = argvars[0].vval.v_partial;
3236 else
3237 {
3238 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3239 fref_pt.pt_name = argvars[0].vval.v_string;
3240 pt = &fref_pt;
3241 }
3242
3243 if (pt != NULL)
3244 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003245 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003246 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003247
3248 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3249 {
3250 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003251 n = partial_name(pt);
3252 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003253 rettv->vval.v_string = NULL;
3254 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003255 {
3256 rettv->vval.v_string = vim_strsave(n);
3257 if (rettv->v_type == VAR_FUNC)
3258 func_ref(rettv->vval.v_string);
3259 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003260 }
3261 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003262 {
3263 what_is_dict = TRUE;
3264 if (pt->pt_dict != NULL)
3265 rettv_dict_set(rettv, pt->pt_dict);
3266 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267 else if (STRCMP(what, "args") == 0)
3268 {
3269 rettv->v_type = VAR_LIST;
3270 if (rettv_list_alloc(rettv) == OK)
3271 {
3272 int i;
3273
3274 for (i = 0; i < pt->pt_argc; ++i)
3275 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3276 }
3277 }
3278 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003279 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003280
3281 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3282 // third argument
3283 if (!what_is_dict)
3284 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003285 }
3286 }
3287 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003288 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003289
3290 if (tv == NULL)
3291 {
3292 if (argvars[2].v_type != VAR_UNKNOWN)
3293 copy_tv(&argvars[2], rettv);
3294 }
3295 else
3296 copy_tv(tv, rettv);
3297}
3298
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003299/*
3300 * Returns buffer options, variables and other attributes in a dictionary.
3301 */
3302 static dict_T *
3303get_buffer_info(buf_T *buf)
3304{
3305 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003306 tabpage_T *tp;
3307 win_T *wp;
3308 list_T *windows;
3309
3310 dict = dict_alloc();
3311 if (dict == NULL)
3312 return NULL;
3313
Bram Moolenaare0be1672018-07-08 16:50:37 +02003314 dict_add_number(dict, "bufnr", buf->b_fnum);
3315 dict_add_string(dict, "name", buf->b_ffname);
3316 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
3317 : buflist_findlnum(buf));
3318 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
3319 dict_add_number(dict, "listed", buf->b_p_bl);
3320 dict_add_number(dict, "changed", bufIsChanged(buf));
3321 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
3322 dict_add_number(dict, "hidden",
3323 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003324
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003325 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02003326 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003327
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003328 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003329 windows = list_alloc();
3330 if (windows != NULL)
3331 {
3332 FOR_ALL_TAB_WINDOWS(tp, wp)
3333 if (wp->w_buffer == buf)
3334 list_append_number(windows, (varnumber_T)wp->w_id);
3335 dict_add_list(dict, "windows", windows);
3336 }
3337
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003338#ifdef FEAT_TEXT_PROP
3339 // List of popup windows displaying this buffer
3340 windows = list_alloc();
3341 if (windows != NULL)
3342 {
3343 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
3344 if (wp->w_buffer == buf)
3345 list_append_number(windows, (varnumber_T)wp->w_id);
3346 FOR_ALL_TABPAGES(tp)
3347 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
3348 if (wp->w_buffer == buf)
3349 list_append_number(windows, (varnumber_T)wp->w_id);
3350
3351 dict_add_list(dict, "popups", windows);
3352 }
3353#endif
3354
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003355#ifdef FEAT_SIGNS
3356 if (buf->b_signlist != NULL)
3357 {
3358 /* List of signs placed in this buffer */
3359 list_T *signs = list_alloc();
3360 if (signs != NULL)
3361 {
3362 get_buffer_signs(buf, signs);
3363 dict_add_list(dict, "signs", signs);
3364 }
3365 }
3366#endif
3367
3368 return dict;
3369}
3370
3371/*
3372 * "getbufinfo()" function
3373 */
3374 static void
3375f_getbufinfo(typval_T *argvars, typval_T *rettv)
3376{
3377 buf_T *buf = NULL;
3378 buf_T *argbuf = NULL;
3379 dict_T *d;
3380 int filtered = FALSE;
3381 int sel_buflisted = FALSE;
3382 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003383 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003384
3385 if (rettv_list_alloc(rettv) != OK)
3386 return;
3387
3388 /* List of all the buffers or selected buffers */
3389 if (argvars[0].v_type == VAR_DICT)
3390 {
3391 dict_T *sel_d = argvars[0].vval.v_dict;
3392
3393 if (sel_d != NULL)
3394 {
3395 dictitem_T *di;
3396
3397 filtered = TRUE;
3398
3399 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003400 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003401 sel_buflisted = TRUE;
3402
3403 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003404 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003405 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003406
3407 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003408 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003409 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003410 }
3411 }
3412 else if (argvars[0].v_type != VAR_UNKNOWN)
3413 {
3414 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003415 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003416 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003417 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003418 --emsg_off;
3419 if (argbuf == NULL)
3420 return;
3421 }
3422
3423 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02003424 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003425 {
3426 if (argbuf != NULL && argbuf != buf)
3427 continue;
3428 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003429 || (sel_buflisted && !buf->b_p_bl)
3430 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003431 continue;
3432
3433 d = get_buffer_info(buf);
3434 if (d != NULL)
3435 list_append_dict(rettv->vval.v_list, d);
3436 if (argbuf != NULL)
3437 return;
3438 }
3439}
3440
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003441/*
3442 * Get line or list of lines from buffer "buf" into "rettv".
3443 * Return a range (from start to end) of lines in rettv from the specified
3444 * buffer.
3445 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
3446 */
3447 static void
3448get_buffer_lines(
3449 buf_T *buf,
3450 linenr_T start,
3451 linenr_T end,
3452 int retlist,
3453 typval_T *rettv)
3454{
3455 char_u *p;
3456
3457 rettv->v_type = VAR_STRING;
3458 rettv->vval.v_string = NULL;
3459 if (retlist && rettv_list_alloc(rettv) == FAIL)
3460 return;
3461
3462 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
3463 return;
3464
3465 if (!retlist)
3466 {
3467 if (start >= 1 && start <= buf->b_ml.ml_line_count)
3468 p = ml_get_buf(buf, start, FALSE);
3469 else
3470 p = (char_u *)"";
3471 rettv->vval.v_string = vim_strsave(p);
3472 }
3473 else
3474 {
3475 if (end < start)
3476 return;
3477
3478 if (start < 1)
3479 start = 1;
3480 if (end > buf->b_ml.ml_line_count)
3481 end = buf->b_ml.ml_line_count;
3482 while (start <= end)
3483 if (list_append_string(rettv->vval.v_list,
3484 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
3485 break;
3486 }
3487}
3488
3489/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003490 * "getbufline()" function
3491 */
3492 static void
3493f_getbufline(typval_T *argvars, typval_T *rettv)
3494{
3495 linenr_T lnum;
3496 linenr_T end;
3497 buf_T *buf;
3498
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003499 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003501 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003502 --emsg_off;
3503
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003504 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 if (argvars[2].v_type == VAR_UNKNOWN)
3506 end = lnum;
3507 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003508 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003509
3510 get_buffer_lines(buf, lnum, end, TRUE, rettv);
3511}
3512
3513/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003514 * "getchangelist()" function
3515 */
3516 static void
3517f_getchangelist(typval_T *argvars, typval_T *rettv)
3518{
3519#ifdef FEAT_JUMPLIST
3520 buf_T *buf;
3521 int i;
3522 list_T *l;
3523 dict_T *d;
3524#endif
3525
3526 if (rettv_list_alloc(rettv) != OK)
3527 return;
3528
3529#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003530 if (argvars[0].v_type == VAR_UNKNOWN)
3531 buf = curbuf;
3532 else
3533 {
3534 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3535 ++emsg_off;
3536 buf = tv_get_buf(&argvars[0], FALSE);
3537 --emsg_off;
3538 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003539 if (buf == NULL)
3540 return;
3541
3542 l = list_alloc();
3543 if (l == NULL)
3544 return;
3545
3546 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3547 return;
3548 /*
3549 * The current window change list index tracks only the position in the
3550 * current buffer change list. For other buffers, use the change list
3551 * length as the current index.
3552 */
3553 list_append_number(rettv->vval.v_list,
3554 (varnumber_T)((buf == curwin->w_buffer)
3555 ? curwin->w_changelistidx : buf->b_changelistlen));
3556
3557 for (i = 0; i < buf->b_changelistlen; ++i)
3558 {
3559 if (buf->b_changelist[i].lnum == 0)
3560 continue;
3561 if ((d = dict_alloc()) == NULL)
3562 return;
3563 if (list_append_dict(l, d) == FAIL)
3564 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003565 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3566 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003567 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003568 }
3569#endif
3570}
3571/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572 * "getchar()" function
3573 */
3574 static void
3575f_getchar(typval_T *argvars, typval_T *rettv)
3576{
3577 varnumber_T n;
3578 int error = FALSE;
3579
Bram Moolenaar84d93902018-09-11 20:10:20 +02003580#ifdef MESSAGE_QUEUE
3581 // vpeekc() used to check for messages, but that caused problems, invoking
3582 // a callback where it was not expected. Some plugins use getchar(1) in a
3583 // loop to await a message, therefore make sure we check for messages here.
3584 parse_queued_messages();
3585#endif
3586
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003587 /* Position the cursor. Needed after a message that ends in a space. */
3588 windgoto(msg_row, msg_col);
3589
3590 ++no_mapping;
3591 ++allow_keys;
3592 for (;;)
3593 {
3594 if (argvars[0].v_type == VAR_UNKNOWN)
3595 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01003596 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003597 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003598 /* getchar(1): only check if char avail */
3599 n = vpeekc_any();
3600 else if (error || vpeekc_any() == NUL)
3601 /* illegal argument or getchar(0) and no char avail: return zero */
3602 n = 0;
3603 else
3604 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01003605 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003606
3607 if (n == K_IGNORE)
3608 continue;
3609 break;
3610 }
3611 --no_mapping;
3612 --allow_keys;
3613
3614 set_vim_var_nr(VV_MOUSE_WIN, 0);
3615 set_vim_var_nr(VV_MOUSE_WINID, 0);
3616 set_vim_var_nr(VV_MOUSE_LNUM, 0);
3617 set_vim_var_nr(VV_MOUSE_COL, 0);
3618
3619 rettv->vval.v_number = n;
3620 if (IS_SPECIAL(n) || mod_mask != 0)
3621 {
3622 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
3623 int i = 0;
3624
3625 /* Turn a special key into three bytes, plus modifier. */
3626 if (mod_mask != 0)
3627 {
3628 temp[i++] = K_SPECIAL;
3629 temp[i++] = KS_MODIFIER;
3630 temp[i++] = mod_mask;
3631 }
3632 if (IS_SPECIAL(n))
3633 {
3634 temp[i++] = K_SPECIAL;
3635 temp[i++] = K_SECOND(n);
3636 temp[i++] = K_THIRD(n);
3637 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638 else if (has_mbyte)
3639 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003640 else
3641 temp[i++] = n;
3642 temp[i++] = NUL;
3643 rettv->v_type = VAR_STRING;
3644 rettv->vval.v_string = vim_strsave(temp);
3645
3646#ifdef FEAT_MOUSE
3647 if (is_mouse_key(n))
3648 {
3649 int row = mouse_row;
3650 int col = mouse_col;
3651 win_T *win;
3652 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003653 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 int winnr = 1;
3655
3656 if (row >= 0 && col >= 0)
3657 {
3658 /* Find the window at the mouse coordinates and compute the
3659 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003660 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02003661 if (win == NULL)
3662 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02003663 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003664# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02003665 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003666 winnr = 0;
3667 else
3668# endif
3669 for (wp = firstwin; wp != win && wp != NULL;
3670 wp = wp->w_next)
3671 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003672 set_vim_var_nr(VV_MOUSE_WIN, winnr);
3673 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
3674 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
3675 set_vim_var_nr(VV_MOUSE_COL, col + 1);
3676 }
3677 }
3678#endif
3679 }
3680}
3681
3682/*
3683 * "getcharmod()" function
3684 */
3685 static void
3686f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
3687{
3688 rettv->vval.v_number = mod_mask;
3689}
3690
3691/*
3692 * "getcharsearch()" function
3693 */
3694 static void
3695f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3696{
3697 if (rettv_dict_alloc(rettv) != FAIL)
3698 {
3699 dict_T *dict = rettv->vval.v_dict;
3700
Bram Moolenaare0be1672018-07-08 16:50:37 +02003701 dict_add_string(dict, "char", last_csearch());
3702 dict_add_number(dict, "forward", last_csearch_forward());
3703 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003704 }
3705}
3706
3707/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003708 * "getcmdwintype()" function
3709 */
3710 static void
3711f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
3712{
3713 rettv->v_type = VAR_STRING;
3714 rettv->vval.v_string = NULL;
3715#ifdef FEAT_CMDWIN
3716 rettv->vval.v_string = alloc(2);
3717 if (rettv->vval.v_string != NULL)
3718 {
3719 rettv->vval.v_string[0] = cmdwin_type;
3720 rettv->vval.v_string[1] = NUL;
3721 }
3722#endif
3723}
3724
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003725/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003726 * "getenv()" function
3727 */
3728 static void
3729f_getenv(typval_T *argvars, typval_T *rettv)
3730{
3731 int mustfree = FALSE;
3732 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3733
3734 if (p == NULL)
3735 {
3736 rettv->v_type = VAR_SPECIAL;
3737 rettv->vval.v_number = VVAL_NULL;
3738 return;
3739 }
3740 if (!mustfree)
3741 p = vim_strsave(p);
3742 rettv->vval.v_string = p;
3743 rettv->v_type = VAR_STRING;
3744}
3745
3746/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747 * "getfontname()" function
3748 */
3749 static void
3750f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3751{
3752 rettv->v_type = VAR_STRING;
3753 rettv->vval.v_string = NULL;
3754#ifdef FEAT_GUI
3755 if (gui.in_use)
3756 {
3757 GuiFont font;
3758 char_u *name = NULL;
3759
3760 if (argvars[0].v_type == VAR_UNKNOWN)
3761 {
3762 /* Get the "Normal" font. Either the name saved by
3763 * hl_set_font_name() or from the font ID. */
3764 font = gui.norm_font;
3765 name = hl_get_font_name();
3766 }
3767 else
3768 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003769 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003770 if (STRCMP(name, "*") == 0) /* don't use font dialog */
3771 return;
3772 font = gui_mch_get_font(name, FALSE);
3773 if (font == NOFONT)
3774 return; /* Invalid font name, return empty string. */
3775 }
3776 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3777 if (argvars[0].v_type != VAR_UNKNOWN)
3778 gui_mch_free_font(font);
3779 }
3780#endif
3781}
3782
3783/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003784 * "getjumplist()" function
3785 */
3786 static void
3787f_getjumplist(typval_T *argvars, typval_T *rettv)
3788{
3789#ifdef FEAT_JUMPLIST
3790 win_T *wp;
3791 int i;
3792 list_T *l;
3793 dict_T *d;
3794#endif
3795
3796 if (rettv_list_alloc(rettv) != OK)
3797 return;
3798
3799#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003800 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003801 if (wp == NULL)
3802 return;
3803
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003804 cleanup_jumplist(wp, TRUE);
3805
Bram Moolenaar4f505882018-02-10 21:06:32 +01003806 l = list_alloc();
3807 if (l == NULL)
3808 return;
3809
3810 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3811 return;
3812 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3813
3814 for (i = 0; i < wp->w_jumplistlen; ++i)
3815 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003816 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3817 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003818 if ((d = dict_alloc()) == NULL)
3819 return;
3820 if (list_append_dict(l, d) == FAIL)
3821 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003822 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3823 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003824 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003825 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003826 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003827 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003828 }
3829#endif
3830}
3831
3832/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003833 * "getline(lnum, [end])" function
3834 */
3835 static void
3836f_getline(typval_T *argvars, typval_T *rettv)
3837{
3838 linenr_T lnum;
3839 linenr_T end;
3840 int retlist;
3841
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003842 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003843 if (argvars[1].v_type == VAR_UNKNOWN)
3844 {
3845 end = 0;
3846 retlist = FALSE;
3847 }
3848 else
3849 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003850 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003851 retlist = TRUE;
3852 }
3853
3854 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
3855}
3856
3857/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003858 * "getpid()" function
3859 */
3860 static void
3861f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3862{
3863 rettv->vval.v_number = mch_get_pid();
3864}
3865
3866 static void
3867getpos_both(
3868 typval_T *argvars,
3869 typval_T *rettv,
3870 int getcurpos)
3871{
3872 pos_T *fp;
3873 list_T *l;
3874 int fnum = -1;
3875
3876 if (rettv_list_alloc(rettv) == OK)
3877 {
3878 l = rettv->vval.v_list;
3879 if (getcurpos)
3880 fp = &curwin->w_cursor;
3881 else
3882 fp = var2fpos(&argvars[0], TRUE, &fnum);
3883 if (fnum != -1)
3884 list_append_number(l, (varnumber_T)fnum);
3885 else
3886 list_append_number(l, (varnumber_T)0);
3887 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3888 : (varnumber_T)0);
3889 list_append_number(l, (fp != NULL)
3890 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3891 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003892 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003893 (varnumber_T)0);
3894 if (getcurpos)
3895 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003896 int save_set_curswant = curwin->w_set_curswant;
3897 colnr_T save_curswant = curwin->w_curswant;
3898 colnr_T save_virtcol = curwin->w_virtcol;
3899
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003900 update_curswant();
3901 list_append_number(l, curwin->w_curswant == MAXCOL ?
3902 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003903
3904 // Do not change "curswant", as it is unexpected that a get
3905 // function has a side effect.
3906 if (save_set_curswant)
3907 {
3908 curwin->w_set_curswant = save_set_curswant;
3909 curwin->w_curswant = save_curswant;
3910 curwin->w_virtcol = save_virtcol;
3911 curwin->w_valid &= ~VALID_VIRTCOL;
3912 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003913 }
3914 }
3915 else
3916 rettv->vval.v_number = FALSE;
3917}
3918
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003919/*
3920 * "getcurpos()" function
3921 */
3922 static void
3923f_getcurpos(typval_T *argvars, typval_T *rettv)
3924{
3925 getpos_both(argvars, rettv, TRUE);
3926}
3927
3928/*
3929 * "getpos(string)" function
3930 */
3931 static void
3932f_getpos(typval_T *argvars, typval_T *rettv)
3933{
3934 getpos_both(argvars, rettv, FALSE);
3935}
3936
3937/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003938 * "getreg()" function
3939 */
3940 static void
3941f_getreg(typval_T *argvars, typval_T *rettv)
3942{
3943 char_u *strregname;
3944 int regname;
3945 int arg2 = FALSE;
3946 int return_list = FALSE;
3947 int error = FALSE;
3948
3949 if (argvars[0].v_type != VAR_UNKNOWN)
3950 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003951 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003952 error = strregname == NULL;
3953 if (argvars[1].v_type != VAR_UNKNOWN)
3954 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003955 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003957 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003958 }
3959 }
3960 else
3961 strregname = get_vim_var_str(VV_REG);
3962
3963 if (error)
3964 return;
3965
3966 regname = (strregname == NULL ? '"' : *strregname);
3967 if (regname == 0)
3968 regname = '"';
3969
3970 if (return_list)
3971 {
3972 rettv->v_type = VAR_LIST;
3973 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3974 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3975 if (rettv->vval.v_list == NULL)
3976 (void)rettv_list_alloc(rettv);
3977 else
3978 ++rettv->vval.v_list->lv_refcount;
3979 }
3980 else
3981 {
3982 rettv->v_type = VAR_STRING;
3983 rettv->vval.v_string = get_reg_contents(regname,
3984 arg2 ? GREG_EXPR_SRC : 0);
3985 }
3986}
3987
3988/*
3989 * "getregtype()" function
3990 */
3991 static void
3992f_getregtype(typval_T *argvars, typval_T *rettv)
3993{
3994 char_u *strregname;
3995 int regname;
3996 char_u buf[NUMBUFLEN + 2];
3997 long reglen = 0;
3998
3999 if (argvars[0].v_type != VAR_UNKNOWN)
4000 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004001 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004002 if (strregname == NULL) /* type error; errmsg already given */
4003 {
4004 rettv->v_type = VAR_STRING;
4005 rettv->vval.v_string = NULL;
4006 return;
4007 }
4008 }
4009 else
4010 /* Default to v:register */
4011 strregname = get_vim_var_str(VV_REG);
4012
4013 regname = (strregname == NULL ? '"' : *strregname);
4014 if (regname == 0)
4015 regname = '"';
4016
4017 buf[0] = NUL;
4018 buf[1] = NUL;
4019 switch (get_reg_type(regname, &reglen))
4020 {
4021 case MLINE: buf[0] = 'V'; break;
4022 case MCHAR: buf[0] = 'v'; break;
4023 case MBLOCK:
4024 buf[0] = Ctrl_V;
4025 sprintf((char *)buf + 1, "%ld", reglen + 1);
4026 break;
4027 }
4028 rettv->v_type = VAR_STRING;
4029 rettv->vval.v_string = vim_strsave(buf);
4030}
4031
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004032/*
4033 * Returns information (variables, options, etc.) about a tab page
4034 * as a dictionary.
4035 */
4036 static dict_T *
4037get_tabpage_info(tabpage_T *tp, int tp_idx)
4038{
4039 win_T *wp;
4040 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004041 list_T *l;
4042
4043 dict = dict_alloc();
4044 if (dict == NULL)
4045 return NULL;
4046
Bram Moolenaare0be1672018-07-08 16:50:37 +02004047 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004048
4049 l = list_alloc();
4050 if (l != NULL)
4051 {
4052 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004053 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004054 list_append_number(l, (varnumber_T)wp->w_id);
4055 dict_add_list(dict, "windows", l);
4056 }
4057
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004058 /* Make a reference to tabpage variables */
4059 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004060
4061 return dict;
4062}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004063
4064/*
4065 * "gettabinfo()" function
4066 */
4067 static void
4068f_gettabinfo(typval_T *argvars, typval_T *rettv)
4069{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004070 tabpage_T *tp, *tparg = NULL;
4071 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02004072 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004073
4074 if (rettv_list_alloc(rettv) != OK)
4075 return;
4076
4077 if (argvars[0].v_type != VAR_UNKNOWN)
4078 {
4079 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004080 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004081 if (tparg == NULL)
4082 return;
4083 }
4084
4085 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004086 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004087 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004088 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004089 if (tparg != NULL && tp != tparg)
4090 continue;
4091 d = get_tabpage_info(tp, tpnr);
4092 if (d != NULL)
4093 list_append_dict(rettv->vval.v_list, d);
4094 if (tparg != NULL)
4095 return;
4096 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004097}
4098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01004100 * "gettagstack()" function
4101 */
4102 static void
4103f_gettagstack(typval_T *argvars, typval_T *rettv)
4104{
4105 win_T *wp = curwin; // default is current window
4106
4107 if (rettv_dict_alloc(rettv) != OK)
4108 return;
4109
4110 if (argvars[0].v_type != VAR_UNKNOWN)
4111 {
4112 wp = find_win_by_nr_or_id(&argvars[0]);
4113 if (wp == NULL)
4114 return;
4115 }
4116
4117 get_tagstack(wp, rettv->vval.v_dict);
4118}
4119
4120/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004121 * Returns information about a window as a dictionary.
4122 */
4123 static dict_T *
4124get_win_info(win_T *wp, short tpnr, short winnr)
4125{
4126 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004127
4128 dict = dict_alloc();
4129 if (dict == NULL)
4130 return NULL;
4131
Bram Moolenaare0be1672018-07-08 16:50:37 +02004132 dict_add_number(dict, "tabnr", tpnr);
4133 dict_add_number(dict, "winnr", winnr);
4134 dict_add_number(dict, "winid", wp->w_id);
4135 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02004136 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01004137 dict_add_number(dict, "topline", wp->w_topline);
4138 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004139#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02004140 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004141#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02004142 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02004143 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004144 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004145
Bram Moolenaar69905d12017-08-13 18:14:47 +02004146#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02004147 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02004148#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02004149#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02004150 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
4151 dict_add_number(dict, "loclist",
4152 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02004153#endif
4154
Bram Moolenaar30567352016-08-27 21:25:44 +02004155 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004156 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004157
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004158 return dict;
4159}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004160
4161/*
4162 * "getwininfo()" function
4163 */
4164 static void
4165f_getwininfo(typval_T *argvars, typval_T *rettv)
4166{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004167 tabpage_T *tp;
4168 win_T *wp = NULL, *wparg = NULL;
4169 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02004170 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004171
4172 if (rettv_list_alloc(rettv) != OK)
4173 return;
4174
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004175 if (argvars[0].v_type != VAR_UNKNOWN)
4176 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01004177 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004178 if (wparg == NULL)
4179 return;
4180 }
4181
4182 /* Collect information about either all the windows across all the tab
4183 * pages or one particular window.
4184 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004185 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004186 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004187 tabnr++;
4188 winnr = 0;
4189 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004190 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004191 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004192 if (wparg != NULL && wp != wparg)
4193 continue;
4194 d = get_win_info(wp, tabnr, winnr);
4195 if (d != NULL)
4196 list_append_dict(rettv->vval.v_list, d);
4197 if (wparg != NULL)
4198 /* found information about a specific window */
4199 return;
4200 }
4201 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004202}
4203
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004204/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004205 * "win_execute()" function
4206 */
4207 static void
4208f_win_execute(typval_T *argvars, typval_T *rettv)
4209{
4210 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02004211 tabpage_T *tp;
4212 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004213 win_T *save_curwin;
4214 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004215
Bram Moolenaar820680b2019-08-09 14:56:22 +02004216 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004217 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02004218 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004219 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004220 check_cursor();
4221 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004222 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004223 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004224 }
4225}
4226
4227/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004228 * "win_findbuf()" function
4229 */
4230 static void
4231f_win_findbuf(typval_T *argvars, typval_T *rettv)
4232{
4233 if (rettv_list_alloc(rettv) != FAIL)
4234 win_findbuf(argvars, rettv->vval.v_list);
4235}
4236
4237/*
4238 * "win_getid()" function
4239 */
4240 static void
4241f_win_getid(typval_T *argvars, typval_T *rettv)
4242{
4243 rettv->vval.v_number = win_getid(argvars);
4244}
4245
4246/*
4247 * "win_gotoid()" function
4248 */
4249 static void
4250f_win_gotoid(typval_T *argvars, typval_T *rettv)
4251{
4252 rettv->vval.v_number = win_gotoid(argvars);
4253}
4254
4255/*
4256 * "win_id2tabwin()" function
4257 */
4258 static void
4259f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
4260{
4261 if (rettv_list_alloc(rettv) != FAIL)
4262 win_id2tabwin(argvars, rettv->vval.v_list);
4263}
4264
4265/*
4266 * "win_id2win()" function
4267 */
4268 static void
4269f_win_id2win(typval_T *argvars, typval_T *rettv)
4270{
4271 rettv->vval.v_number = win_id2win(argvars);
4272}
4273
4274/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01004275 * "win_screenpos()" function
4276 */
4277 static void
4278f_win_screenpos(typval_T *argvars, typval_T *rettv)
4279{
4280 win_T *wp;
4281
4282 if (rettv_list_alloc(rettv) == FAIL)
4283 return;
4284
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02004285 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01004286 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
4287 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
4288}
4289
4290/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004291 * "getwinpos({timeout})" function
4292 */
4293 static void
4294f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
4295{
4296 int x = -1;
4297 int y = -1;
4298
4299 if (rettv_list_alloc(rettv) == FAIL)
4300 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004301#if defined(FEAT_GUI) \
4302 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4303 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004304 {
4305 varnumber_T timeout = 100;
4306
4307 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004308 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004309
4310 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004311 }
4312#endif
4313 list_append_number(rettv->vval.v_list, (varnumber_T)x);
4314 list_append_number(rettv->vval.v_list, (varnumber_T)y);
4315}
4316
4317
4318/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004319 * "getwinposx()" function
4320 */
4321 static void
4322f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
4323{
4324 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004325#if defined(FEAT_GUI) \
4326 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4327 || defined(MSWIN)
4328
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004329 {
4330 int x, y;
4331
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004332 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004333 rettv->vval.v_number = x;
4334 }
4335#endif
4336}
4337
4338/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004339 * "getwinposy()" function
4340 */
4341 static void
4342f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
4343{
4344 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004345#if defined(FEAT_GUI) \
4346 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4347 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004348 {
4349 int x, y;
4350
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004351 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004352 rettv->vval.v_number = y;
4353 }
4354#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004355}
4356
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004357/* for VIM_VERSION_ defines */
4358#include "version.h"
4359
4360/*
4361 * "has()" function
4362 */
4363 static void
4364f_has(typval_T *argvars, typval_T *rettv)
4365{
4366 int i;
4367 char_u *name;
4368 int n = FALSE;
4369 static char *(has_list[]) =
4370 {
4371#ifdef AMIGA
4372 "amiga",
4373# ifdef FEAT_ARP
4374 "arp",
4375# endif
4376#endif
4377#ifdef __BEOS__
4378 "beos",
4379#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004380#if defined(BSD) && !defined(MACOS_X)
4381 "bsd",
4382#endif
4383#ifdef hpux
4384 "hpux",
4385#endif
4386#ifdef __linux__
4387 "linux",
4388#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02004389#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01004390 "mac", /* Mac OS X (and, once, Mac OS Classic) */
4391 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02004392# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01004393 "macunix", /* Mac OS X, with the darwin feature */
4394 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02004395# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004396#endif
4397#ifdef __QNX__
4398 "qnx",
4399#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004400#ifdef SUN_SYSTEM
4401 "sun",
4402#else
4403 "moon",
4404#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004405#ifdef UNIX
4406 "unix",
4407#endif
4408#ifdef VMS
4409 "vms",
4410#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004411#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004412 "win32",
4413#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01004414#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004415 "win32unix",
4416#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01004417#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004418 "win64",
4419#endif
4420#ifdef EBCDIC
4421 "ebcdic",
4422#endif
4423#ifndef CASE_INSENSITIVE_FILENAME
4424 "fname_case",
4425#endif
4426#ifdef HAVE_ACL
4427 "acl",
4428#endif
4429#ifdef FEAT_ARABIC
4430 "arabic",
4431#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004432 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004433#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004434 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004435#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01004436#ifdef FEAT_AUTOSERVERNAME
4437 "autoservername",
4438#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004439#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004440 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01004441# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004442 "balloon_multiline",
4443# endif
4444#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004445#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01004446 "balloon_eval_term",
4447#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
4449 "builtin_terms",
4450# ifdef ALL_BUILTIN_TCAPS
4451 "all_builtin_terms",
4452# endif
4453#endif
4454#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01004455 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004456 || defined(FEAT_GUI_MOTIF))
4457 "browsefilter",
4458#endif
4459#ifdef FEAT_BYTEOFF
4460 "byte_offset",
4461#endif
4462#ifdef FEAT_JOB_CHANNEL
4463 "channel",
4464#endif
4465#ifdef FEAT_CINDENT
4466 "cindent",
4467#endif
4468#ifdef FEAT_CLIENTSERVER
4469 "clientserver",
4470#endif
4471#ifdef FEAT_CLIPBOARD
4472 "clipboard",
4473#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004475 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476#ifdef FEAT_COMMENTS
4477 "comments",
4478#endif
4479#ifdef FEAT_CONCEAL
4480 "conceal",
4481#endif
4482#ifdef FEAT_CRYPT
4483 "cryptv",
4484 "crypt-blowfish",
4485 "crypt-blowfish2",
4486#endif
4487#ifdef FEAT_CSCOPE
4488 "cscope",
4489#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004490 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004491#ifdef CURSOR_SHAPE
4492 "cursorshape",
4493#endif
4494#ifdef DEBUG
4495 "debug",
4496#endif
4497#ifdef FEAT_CON_DIALOG
4498 "dialog_con",
4499#endif
4500#ifdef FEAT_GUI_DIALOG
4501 "dialog_gui",
4502#endif
4503#ifdef FEAT_DIFF
4504 "diff",
4505#endif
4506#ifdef FEAT_DIGRAPHS
4507 "digraphs",
4508#endif
4509#ifdef FEAT_DIRECTX
4510 "directx",
4511#endif
4512#ifdef FEAT_DND
4513 "dnd",
4514#endif
4515#ifdef FEAT_EMACS_TAGS
4516 "emacs_tags",
4517#endif
4518 "eval", /* always present, of course! */
4519 "ex_extra", /* graduated feature */
4520#ifdef FEAT_SEARCH_EXTRA
4521 "extra_search",
4522#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004523#ifdef FEAT_SEARCHPATH
4524 "file_in_path",
4525#endif
4526#ifdef FEAT_FILTERPIPE
4527 "filterpipe",
4528#endif
4529#ifdef FEAT_FIND_ID
4530 "find_in_path",
4531#endif
4532#ifdef FEAT_FLOAT
4533 "float",
4534#endif
4535#ifdef FEAT_FOLDING
4536 "folding",
4537#endif
4538#ifdef FEAT_FOOTER
4539 "footer",
4540#endif
4541#if !defined(USE_SYSTEM) && defined(UNIX)
4542 "fork",
4543#endif
4544#ifdef FEAT_GETTEXT
4545 "gettext",
4546#endif
4547#ifdef FEAT_GUI
4548 "gui",
4549#endif
4550#ifdef FEAT_GUI_ATHENA
4551# ifdef FEAT_GUI_NEXTAW
4552 "gui_neXtaw",
4553# else
4554 "gui_athena",
4555# endif
4556#endif
4557#ifdef FEAT_GUI_GTK
4558 "gui_gtk",
4559# ifdef USE_GTK3
4560 "gui_gtk3",
4561# else
4562 "gui_gtk2",
4563# endif
4564#endif
4565#ifdef FEAT_GUI_GNOME
4566 "gui_gnome",
4567#endif
4568#ifdef FEAT_GUI_MAC
4569 "gui_mac",
4570#endif
4571#ifdef FEAT_GUI_MOTIF
4572 "gui_motif",
4573#endif
4574#ifdef FEAT_GUI_PHOTON
4575 "gui_photon",
4576#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004577#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004578 "gui_win32",
4579#endif
4580#ifdef FEAT_HANGULIN
4581 "hangul_input",
4582#endif
4583#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
4584 "iconv",
4585#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004586 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004587#ifdef FEAT_JOB_CHANNEL
4588 "job",
4589#endif
4590#ifdef FEAT_JUMPLIST
4591 "jumplist",
4592#endif
4593#ifdef FEAT_KEYMAP
4594 "keymap",
4595#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02004596 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004597#ifdef FEAT_LANGMAP
4598 "langmap",
4599#endif
4600#ifdef FEAT_LIBCALL
4601 "libcall",
4602#endif
4603#ifdef FEAT_LINEBREAK
4604 "linebreak",
4605#endif
4606#ifdef FEAT_LISP
4607 "lispindent",
4608#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004609 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004610 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611#ifdef FEAT_LUA
4612# ifndef DYNAMIC_LUA
4613 "lua",
4614# endif
4615#endif
4616#ifdef FEAT_MENU
4617 "menu",
4618#endif
4619#ifdef FEAT_SESSION
4620 "mksession",
4621#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004623#ifdef FEAT_MOUSE
4624 "mouse",
4625#endif
4626#ifdef FEAT_MOUSESHAPE
4627 "mouseshape",
4628#endif
4629#if defined(UNIX) || defined(VMS)
4630# ifdef FEAT_MOUSE_DEC
4631 "mouse_dec",
4632# endif
4633# ifdef FEAT_MOUSE_GPM
4634 "mouse_gpm",
4635# endif
4636# ifdef FEAT_MOUSE_JSB
4637 "mouse_jsbterm",
4638# endif
4639# ifdef FEAT_MOUSE_NET
4640 "mouse_netterm",
4641# endif
4642# ifdef FEAT_MOUSE_PTERM
4643 "mouse_pterm",
4644# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004645# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004646 "mouse_sgr",
4647# endif
4648# ifdef FEAT_SYSMOUSE
4649 "mouse_sysmouse",
4650# endif
4651# ifdef FEAT_MOUSE_URXVT
4652 "mouse_urxvt",
4653# endif
4654# ifdef FEAT_MOUSE_XTERM
4655 "mouse_xterm",
4656# endif
4657#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004658 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004659#ifdef FEAT_MBYTE_IME
4660 "multi_byte_ime",
4661#endif
4662#ifdef FEAT_MULTI_LANG
4663 "multi_lang",
4664#endif
4665#ifdef FEAT_MZSCHEME
4666#ifndef DYNAMIC_MZSCHEME
4667 "mzscheme",
4668#endif
4669#endif
4670#ifdef FEAT_NUM64
4671 "num64",
4672#endif
4673#ifdef FEAT_OLE
4674 "ole",
4675#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02004676#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004677 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02004678#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004679#ifdef FEAT_PATH_EXTRA
4680 "path_extra",
4681#endif
4682#ifdef FEAT_PERL
4683#ifndef DYNAMIC_PERL
4684 "perl",
4685#endif
4686#endif
4687#ifdef FEAT_PERSISTENT_UNDO
4688 "persistent_undo",
4689#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004690#if defined(FEAT_PYTHON)
4691 "python_compiled",
4692# if defined(DYNAMIC_PYTHON)
4693 "python_dynamic",
4694# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004695 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004696 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004697# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004698#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004699#if defined(FEAT_PYTHON3)
4700 "python3_compiled",
4701# if defined(DYNAMIC_PYTHON3)
4702 "python3_dynamic",
4703# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004704 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004705 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004706# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004707#endif
4708#ifdef FEAT_POSTSCRIPT
4709 "postscript",
4710#endif
4711#ifdef FEAT_PRINTER
4712 "printer",
4713#endif
4714#ifdef FEAT_PROFILE
4715 "profile",
4716#endif
4717#ifdef FEAT_RELTIME
4718 "reltime",
4719#endif
4720#ifdef FEAT_QUICKFIX
4721 "quickfix",
4722#endif
4723#ifdef FEAT_RIGHTLEFT
4724 "rightleft",
4725#endif
4726#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4727 "ruby",
4728#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004730#ifdef FEAT_CMDL_INFO
4731 "showcmd",
4732 "cmdline_info",
4733#endif
4734#ifdef FEAT_SIGNS
4735 "signs",
4736#endif
4737#ifdef FEAT_SMARTINDENT
4738 "smartindent",
4739#endif
4740#ifdef STARTUPTIME
4741 "startuptime",
4742#endif
4743#ifdef FEAT_STL_OPT
4744 "statusline",
4745#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746#ifdef FEAT_NETBEANS_INTG
4747 "netbeans_intg",
4748#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02004749#ifdef FEAT_SOUND
4750 "sound",
4751#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004752#ifdef FEAT_SPELL
4753 "spell",
4754#endif
4755#ifdef FEAT_SYN_HL
4756 "syntax",
4757#endif
4758#if defined(USE_SYSTEM) || !defined(UNIX)
4759 "system",
4760#endif
4761#ifdef FEAT_TAG_BINS
4762 "tag_binary",
4763#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004764#ifdef FEAT_TCL
4765# ifndef DYNAMIC_TCL
4766 "tcl",
4767# endif
4768#endif
4769#ifdef FEAT_TERMGUICOLORS
4770 "termguicolors",
4771#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004772#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02004773 "terminal",
4774#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004775#ifdef TERMINFO
4776 "terminfo",
4777#endif
4778#ifdef FEAT_TERMRESPONSE
4779 "termresponse",
4780#endif
4781#ifdef FEAT_TEXTOBJ
4782 "textobjects",
4783#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01004784#ifdef FEAT_TEXT_PROP
4785 "textprop",
4786#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787#ifdef HAVE_TGETENT
4788 "tgetent",
4789#endif
4790#ifdef FEAT_TIMERS
4791 "timers",
4792#endif
4793#ifdef FEAT_TITLE
4794 "title",
4795#endif
4796#ifdef FEAT_TOOLBAR
4797 "toolbar",
4798#endif
4799#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4800 "unnamedplus",
4801#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004802 "user-commands", /* was accidentally included in 5.4 */
4803 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02004804#ifdef FEAT_VARTABS
4805 "vartabs",
4806#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004807 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004808#ifdef FEAT_VIMINFO
4809 "viminfo",
4810#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004811 "vimscript-1",
4812 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02004813 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004814 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004816 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004817 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01004818#ifdef FEAT_VTP
4819 "vtp",
4820#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004821#ifdef FEAT_WILDIGN
4822 "wildignore",
4823#endif
4824#ifdef FEAT_WILDMENU
4825 "wildmenu",
4826#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004827 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828#ifdef FEAT_WAK
4829 "winaltkeys",
4830#endif
4831#ifdef FEAT_WRITEBACKUP
4832 "writebackup",
4833#endif
4834#ifdef FEAT_XIM
4835 "xim",
4836#endif
4837#ifdef FEAT_XFONTSET
4838 "xfontset",
4839#endif
4840#ifdef FEAT_XPM_W32
4841 "xpm",
4842 "xpm_w32", /* for backward compatibility */
4843#else
4844# if defined(HAVE_XPM)
4845 "xpm",
4846# endif
4847#endif
4848#ifdef USE_XSMP
4849 "xsmp",
4850#endif
4851#ifdef USE_XSMP_INTERACT
4852 "xsmp_interact",
4853#endif
4854#ifdef FEAT_XCLIPBOARD
4855 "xterm_clipboard",
4856#endif
4857#ifdef FEAT_XTERM_SAVE
4858 "xterm_save",
4859#endif
4860#if defined(UNIX) && defined(FEAT_X11)
4861 "X11",
4862#endif
4863 NULL
4864 };
4865
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004866 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004867 for (i = 0; has_list[i] != NULL; ++i)
4868 if (STRICMP(name, has_list[i]) == 0)
4869 {
4870 n = TRUE;
4871 break;
4872 }
4873
4874 if (n == FALSE)
4875 {
4876 if (STRNICMP(name, "patch", 5) == 0)
4877 {
4878 if (name[5] == '-'
4879 && STRLEN(name) >= 11
4880 && vim_isdigit(name[6])
4881 && vim_isdigit(name[8])
4882 && vim_isdigit(name[10]))
4883 {
4884 int major = atoi((char *)name + 6);
4885 int minor = atoi((char *)name + 8);
4886
4887 /* Expect "patch-9.9.01234". */
4888 n = (major < VIM_VERSION_MAJOR
4889 || (major == VIM_VERSION_MAJOR
4890 && (minor < VIM_VERSION_MINOR
4891 || (minor == VIM_VERSION_MINOR
4892 && has_patch(atoi((char *)name + 10))))));
4893 }
4894 else
4895 n = has_patch(atoi((char *)name + 5));
4896 }
4897 else if (STRICMP(name, "vim_starting") == 0)
4898 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01004899 else if (STRICMP(name, "ttyin") == 0)
4900 n = mch_input_isatty();
4901 else if (STRICMP(name, "ttyout") == 0)
4902 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 else if (STRICMP(name, "multi_byte_encoding") == 0)
4904 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01004905#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906 else if (STRICMP(name, "balloon_multiline") == 0)
4907 n = multiline_balloon_available();
4908#endif
4909#ifdef DYNAMIC_TCL
4910 else if (STRICMP(name, "tcl") == 0)
4911 n = tcl_enabled(FALSE);
4912#endif
4913#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4914 else if (STRICMP(name, "iconv") == 0)
4915 n = iconv_enabled(FALSE);
4916#endif
4917#ifdef DYNAMIC_LUA
4918 else if (STRICMP(name, "lua") == 0)
4919 n = lua_enabled(FALSE);
4920#endif
4921#ifdef DYNAMIC_MZSCHEME
4922 else if (STRICMP(name, "mzscheme") == 0)
4923 n = mzscheme_enabled(FALSE);
4924#endif
4925#ifdef DYNAMIC_RUBY
4926 else if (STRICMP(name, "ruby") == 0)
4927 n = ruby_enabled(FALSE);
4928#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004929#ifdef DYNAMIC_PYTHON
4930 else if (STRICMP(name, "python") == 0)
4931 n = python_enabled(FALSE);
4932#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933#ifdef DYNAMIC_PYTHON3
4934 else if (STRICMP(name, "python3") == 0)
4935 n = python3_enabled(FALSE);
4936#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004937#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4938 else if (STRICMP(name, "pythonx") == 0)
4939 {
4940# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4941 if (p_pyx == 0)
4942 n = python3_enabled(FALSE) || python_enabled(FALSE);
4943 else if (p_pyx == 3)
4944 n = python3_enabled(FALSE);
4945 else if (p_pyx == 2)
4946 n = python_enabled(FALSE);
4947# elif defined(DYNAMIC_PYTHON)
4948 n = python_enabled(FALSE);
4949# elif defined(DYNAMIC_PYTHON3)
4950 n = python3_enabled(FALSE);
4951# endif
4952 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004953#endif
4954#ifdef DYNAMIC_PERL
4955 else if (STRICMP(name, "perl") == 0)
4956 n = perl_enabled(FALSE);
4957#endif
4958#ifdef FEAT_GUI
4959 else if (STRICMP(name, "gui_running") == 0)
4960 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961# ifdef FEAT_BROWSE
4962 else if (STRICMP(name, "browse") == 0)
4963 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
4964# endif
4965#endif
4966#ifdef FEAT_SYN_HL
4967 else if (STRICMP(name, "syntax_items") == 0)
4968 n = syntax_present(curwin);
4969#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01004970#ifdef FEAT_VTP
4971 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02004972 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004973#endif
4974#ifdef FEAT_NETBEANS_INTG
4975 else if (STRICMP(name, "netbeans_enabled") == 0)
4976 n = netbeans_active();
4977#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004978#ifdef FEAT_MOUSE_GPM
4979 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4980 n = gpm_enabled();
4981#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004982#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004983 else if (STRICMP(name, "terminal") == 0)
4984 n = terminal_enabled();
4985#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004986#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01004987 else if (STRICMP(name, "conpty") == 0)
4988 n = use_conpty();
4989#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02004990#ifdef FEAT_CLIPBOARD
4991 else if (STRICMP(name, "clipboard_working") == 0)
4992 n = clip_star.available;
4993#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004994 }
4995
4996 rettv->vval.v_number = n;
4997}
4998
4999/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000 * "haslocaldir()" function
5001 */
5002 static void
5003f_haslocaldir(typval_T *argvars, typval_T *rettv)
5004{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005005 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005006 win_T *wp = NULL;
5007
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005008 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
5009
5010 // Check for window-local and tab-local directories
5011 if (wp != NULL && wp->w_localdir != NULL)
5012 rettv->vval.v_number = 1;
5013 else if (tp != NULL && tp->tp_localdir != NULL)
5014 rettv->vval.v_number = 2;
5015 else
5016 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005017}
5018
5019/*
5020 * "hasmapto()" function
5021 */
5022 static void
5023f_hasmapto(typval_T *argvars, typval_T *rettv)
5024{
5025 char_u *name;
5026 char_u *mode;
5027 char_u buf[NUMBUFLEN];
5028 int abbr = FALSE;
5029
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005030 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031 if (argvars[1].v_type == VAR_UNKNOWN)
5032 mode = (char_u *)"nvo";
5033 else
5034 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005035 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005036 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005037 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005038 }
5039
5040 if (map_to_exists(name, mode, abbr))
5041 rettv->vval.v_number = TRUE;
5042 else
5043 rettv->vval.v_number = FALSE;
5044}
5045
5046/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005047 * "highlightID(name)" function
5048 */
5049 static void
5050f_hlID(typval_T *argvars, typval_T *rettv)
5051{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005052 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053}
5054
5055/*
5056 * "highlight_exists()" function
5057 */
5058 static void
5059f_hlexists(typval_T *argvars, typval_T *rettv)
5060{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005061 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005062}
5063
5064/*
5065 * "hostname()" function
5066 */
5067 static void
5068f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5069{
5070 char_u hostname[256];
5071
5072 mch_get_host_name(hostname, 256);
5073 rettv->v_type = VAR_STRING;
5074 rettv->vval.v_string = vim_strsave(hostname);
5075}
5076
5077/*
5078 * iconv() function
5079 */
5080 static void
5081f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5082{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005083 char_u buf1[NUMBUFLEN];
5084 char_u buf2[NUMBUFLEN];
5085 char_u *from, *to, *str;
5086 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005087
5088 rettv->v_type = VAR_STRING;
5089 rettv->vval.v_string = NULL;
5090
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005091 str = tv_get_string(&argvars[0]);
5092 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
5093 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094 vimconv.vc_type = CONV_NONE;
5095 convert_setup(&vimconv, from, to);
5096
5097 /* If the encodings are equal, no conversion needed. */
5098 if (vimconv.vc_type == CONV_NONE)
5099 rettv->vval.v_string = vim_strsave(str);
5100 else
5101 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5102
5103 convert_setup(&vimconv, NULL, NULL);
5104 vim_free(from);
5105 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106}
5107
5108/*
5109 * "indent()" function
5110 */
5111 static void
5112f_indent(typval_T *argvars, typval_T *rettv)
5113{
5114 linenr_T lnum;
5115
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005116 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5118 rettv->vval.v_number = get_indent_lnum(lnum);
5119 else
5120 rettv->vval.v_number = -1;
5121}
5122
5123/*
5124 * "index()" function
5125 */
5126 static void
5127f_index(typval_T *argvars, typval_T *rettv)
5128{
5129 list_T *l;
5130 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005131 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005132 long idx = 0;
5133 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005134 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135
5136 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005137 if (argvars[0].v_type == VAR_BLOB)
5138 {
5139 typval_T tv;
5140 int start = 0;
5141
5142 if (argvars[2].v_type != VAR_UNKNOWN)
5143 {
5144 start = tv_get_number_chk(&argvars[2], &error);
5145 if (error)
5146 return;
5147 }
5148 b = argvars[0].vval.v_blob;
5149 if (b == NULL)
5150 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01005151 if (start < 0)
5152 {
5153 start = blob_len(b) + start;
5154 if (start < 0)
5155 start = 0;
5156 }
5157
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005158 for (idx = start; idx < blob_len(b); ++idx)
5159 {
5160 tv.v_type = VAR_NUMBER;
5161 tv.vval.v_number = blob_get(b, idx);
5162 if (tv_equal(&tv, &argvars[1], ic, FALSE))
5163 {
5164 rettv->vval.v_number = idx;
5165 return;
5166 }
5167 }
5168 return;
5169 }
5170 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01005172 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005173 return;
5174 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005175
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005176 l = argvars[0].vval.v_list;
5177 if (l != NULL)
5178 {
5179 item = l->lv_first;
5180 if (argvars[2].v_type != VAR_UNKNOWN)
5181 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005182 /* Start at specified item. Use the cached index that list_find()
5183 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005184 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005185 idx = l->lv_idx;
5186 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005187 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005188 if (error)
5189 item = NULL;
5190 }
5191
5192 for ( ; item != NULL; item = item->li_next, ++idx)
5193 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
5194 {
5195 rettv->vval.v_number = idx;
5196 break;
5197 }
5198 }
5199}
5200
5201static int inputsecret_flag = 0;
5202
5203/*
5204 * "input()" function
5205 * Also handles inputsecret() when inputsecret is set.
5206 */
5207 static void
5208f_input(typval_T *argvars, typval_T *rettv)
5209{
5210 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5211}
5212
5213/*
5214 * "inputdialog()" function
5215 */
5216 static void
5217f_inputdialog(typval_T *argvars, typval_T *rettv)
5218{
5219#if defined(FEAT_GUI_TEXTDIALOG)
5220 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
5221 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5222 {
5223 char_u *message;
5224 char_u buf[NUMBUFLEN];
5225 char_u *defstr = (char_u *)"";
5226
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005227 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005228 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005229 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005230 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5231 else
5232 IObuff[0] = NUL;
5233 if (message != NULL && defstr != NULL
5234 && do_dialog(VIM_QUESTION, NULL, message,
5235 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5236 rettv->vval.v_string = vim_strsave(IObuff);
5237 else
5238 {
5239 if (message != NULL && defstr != NULL
5240 && argvars[1].v_type != VAR_UNKNOWN
5241 && argvars[2].v_type != VAR_UNKNOWN)
5242 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005243 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244 else
5245 rettv->vval.v_string = NULL;
5246 }
5247 rettv->v_type = VAR_STRING;
5248 }
5249 else
5250#endif
5251 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5252}
5253
5254/*
5255 * "inputlist()" function
5256 */
5257 static void
5258f_inputlist(typval_T *argvars, typval_T *rettv)
5259{
5260 listitem_T *li;
5261 int selected;
5262 int mouse_used;
5263
5264#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02005265 /* While starting up, there is no place to enter text. When running tests
5266 * with --not-a-term we assume feedkeys() will be used. */
5267 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005268 return;
5269#endif
5270 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5271 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005272 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005273 return;
5274 }
5275
5276 msg_start();
5277 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
5278 lines_left = Rows; /* avoid more prompt */
5279 msg_scroll = TRUE;
5280 msg_clr_eos();
5281
5282 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
5283 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005284 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005285 msg_putchar('\n');
5286 }
5287
5288 /* Ask for choice. */
5289 selected = prompt_for_number(&mouse_used);
5290 if (mouse_used)
5291 selected -= lines_left;
5292
5293 rettv->vval.v_number = selected;
5294}
5295
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5297
5298/*
5299 * "inputrestore()" function
5300 */
5301 static void
5302f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5303{
5304 if (ga_userinput.ga_len > 0)
5305 {
5306 --ga_userinput.ga_len;
5307 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5308 + ga_userinput.ga_len);
5309 /* default return is zero == OK */
5310 }
5311 else if (p_verbose > 1)
5312 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005313 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005314 rettv->vval.v_number = 1; /* Failed */
5315 }
5316}
5317
5318/*
5319 * "inputsave()" function
5320 */
5321 static void
5322f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5323{
5324 /* Add an entry to the stack of typeahead storage. */
5325 if (ga_grow(&ga_userinput, 1) == OK)
5326 {
5327 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5328 + ga_userinput.ga_len);
5329 ++ga_userinput.ga_len;
5330 /* default return is zero == OK */
5331 }
5332 else
5333 rettv->vval.v_number = 1; /* Failed */
5334}
5335
5336/*
5337 * "inputsecret()" function
5338 */
5339 static void
5340f_inputsecret(typval_T *argvars, typval_T *rettv)
5341{
5342 ++cmdline_star;
5343 ++inputsecret_flag;
5344 f_input(argvars, rettv);
5345 --cmdline_star;
5346 --inputsecret_flag;
5347}
5348
5349/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005350 * "invert(expr)" function
5351 */
5352 static void
5353f_invert(typval_T *argvars, typval_T *rettv)
5354{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005355 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005356}
5357
5358/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005359 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
5360 * or it refers to a List or Dictionary that is locked.
5361 */
5362 static int
5363tv_islocked(typval_T *tv)
5364{
5365 return (tv->v_lock & VAR_LOCKED)
5366 || (tv->v_type == VAR_LIST
5367 && tv->vval.v_list != NULL
5368 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
5369 || (tv->v_type == VAR_DICT
5370 && tv->vval.v_dict != NULL
5371 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
5372}
5373
5374/*
5375 * "islocked()" function
5376 */
5377 static void
5378f_islocked(typval_T *argvars, typval_T *rettv)
5379{
5380 lval_T lv;
5381 char_u *end;
5382 dictitem_T *di;
5383
5384 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005385 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005386 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005387 if (end != NULL && lv.ll_name != NULL)
5388 {
5389 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005390 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005391 else
5392 {
5393 if (lv.ll_tv == NULL)
5394 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005395 di = find_var(lv.ll_name, NULL, TRUE);
5396 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005397 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005398 /* Consider a variable locked when:
5399 * 1. the variable itself is locked
5400 * 2. the value of the variable is locked.
5401 * 3. the List or Dict value is locked.
5402 */
5403 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5404 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005405 }
5406 }
5407 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005408 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005409 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005410 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005411 else if (lv.ll_list != NULL)
5412 /* List item. */
5413 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5414 else
5415 /* Dictionary item. */
5416 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5417 }
5418 }
5419
5420 clear_lval(&lv);
5421}
5422
5423#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5424/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005425 * "isinf()" function
5426 */
5427 static void
5428f_isinf(typval_T *argvars, typval_T *rettv)
5429{
5430 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5431 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5432}
5433
5434/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005435 * "isnan()" function
5436 */
5437 static void
5438f_isnan(typval_T *argvars, typval_T *rettv)
5439{
5440 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5441 && isnan(argvars[0].vval.v_float);
5442}
5443#endif
5444
5445/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005446 * "last_buffer_nr()" function.
5447 */
5448 static void
5449f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5450{
5451 int n = 0;
5452 buf_T *buf;
5453
Bram Moolenaar29323592016-07-24 22:04:11 +02005454 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005455 if (n < buf->b_fnum)
5456 n = buf->b_fnum;
5457
5458 rettv->vval.v_number = n;
5459}
5460
5461/*
5462 * "len()" function
5463 */
5464 static void
5465f_len(typval_T *argvars, typval_T *rettv)
5466{
5467 switch (argvars[0].v_type)
5468 {
5469 case VAR_STRING:
5470 case VAR_NUMBER:
5471 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005472 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005474 case VAR_BLOB:
5475 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5476 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005477 case VAR_LIST:
5478 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5479 break;
5480 case VAR_DICT:
5481 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5482 break;
5483 case VAR_UNKNOWN:
5484 case VAR_SPECIAL:
5485 case VAR_FLOAT:
5486 case VAR_FUNC:
5487 case VAR_PARTIAL:
5488 case VAR_JOB:
5489 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005490 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491 break;
5492 }
5493}
5494
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005495 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005496libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005497{
5498#ifdef FEAT_LIBCALL
5499 char_u *string_in;
5500 char_u **string_result;
5501 int nr_result;
5502#endif
5503
5504 rettv->v_type = type;
5505 if (type != VAR_NUMBER)
5506 rettv->vval.v_string = NULL;
5507
5508 if (check_restricted() || check_secure())
5509 return;
5510
5511#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02005512 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005513 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5514 {
5515 string_in = NULL;
5516 if (argvars[2].v_type == VAR_STRING)
5517 string_in = argvars[2].vval.v_string;
5518 if (type == VAR_NUMBER)
5519 string_result = NULL;
5520 else
5521 string_result = &rettv->vval.v_string;
5522 if (mch_libcall(argvars[0].vval.v_string,
5523 argvars[1].vval.v_string,
5524 string_in,
5525 argvars[2].vval.v_number,
5526 string_result,
5527 &nr_result) == OK
5528 && type == VAR_NUMBER)
5529 rettv->vval.v_number = nr_result;
5530 }
5531#endif
5532}
5533
5534/*
5535 * "libcall()" function
5536 */
5537 static void
5538f_libcall(typval_T *argvars, typval_T *rettv)
5539{
5540 libcall_common(argvars, rettv, VAR_STRING);
5541}
5542
5543/*
5544 * "libcallnr()" function
5545 */
5546 static void
5547f_libcallnr(typval_T *argvars, typval_T *rettv)
5548{
5549 libcall_common(argvars, rettv, VAR_NUMBER);
5550}
5551
5552/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005553 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554 */
5555 static void
5556f_line(typval_T *argvars, typval_T *rettv)
5557{
5558 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005559 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005560 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005561 int id;
5562 tabpage_T *tp;
5563 win_T *wp;
5564 win_T *save_curwin;
5565 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005566
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005567 if (argvars[1].v_type != VAR_UNKNOWN)
5568 {
5569 // use window specified in the second argument
5570 id = (int)tv_get_number(&argvars[1]);
5571 wp = win_id2wp_tp(id, &tp);
5572 if (wp != NULL && tp != NULL)
5573 {
5574 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5575 == OK)
5576 {
5577 check_cursor();
5578 fp = var2fpos(&argvars[0], TRUE, &fnum);
5579 }
5580 restore_win_noblock(save_curwin, save_curtab, TRUE);
5581 }
5582 }
5583 else
5584 // use current window
5585 fp = var2fpos(&argvars[0], TRUE, &fnum);
5586
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005587 if (fp != NULL)
5588 lnum = fp->lnum;
5589 rettv->vval.v_number = lnum;
5590}
5591
5592/*
5593 * "line2byte(lnum)" function
5594 */
5595 static void
5596f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5597{
5598#ifndef FEAT_BYTEOFF
5599 rettv->vval.v_number = -1;
5600#else
5601 linenr_T lnum;
5602
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005603 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5605 rettv->vval.v_number = -1;
5606 else
5607 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5608 if (rettv->vval.v_number >= 0)
5609 ++rettv->vval.v_number;
5610#endif
5611}
5612
5613/*
5614 * "lispindent(lnum)" function
5615 */
5616 static void
5617f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
5618{
5619#ifdef FEAT_LISP
5620 pos_T pos;
5621 linenr_T lnum;
5622
5623 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005624 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5626 {
5627 curwin->w_cursor.lnum = lnum;
5628 rettv->vval.v_number = get_lisp_indent();
5629 curwin->w_cursor = pos;
5630 }
5631 else
5632#endif
5633 rettv->vval.v_number = -1;
5634}
5635
5636/*
5637 * "localtime()" function
5638 */
5639 static void
5640f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
5641{
5642 rettv->vval.v_number = (varnumber_T)time(NULL);
5643}
5644
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005645#ifdef FEAT_FLOAT
5646/*
5647 * "log()" function
5648 */
5649 static void
5650f_log(typval_T *argvars, typval_T *rettv)
5651{
5652 float_T f = 0.0;
5653
5654 rettv->v_type = VAR_FLOAT;
5655 if (get_float_arg(argvars, &f) == OK)
5656 rettv->vval.v_float = log(f);
5657 else
5658 rettv->vval.v_float = 0.0;
5659}
5660
5661/*
5662 * "log10()" function
5663 */
5664 static void
5665f_log10(typval_T *argvars, typval_T *rettv)
5666{
5667 float_T f = 0.0;
5668
5669 rettv->v_type = VAR_FLOAT;
5670 if (get_float_arg(argvars, &f) == OK)
5671 rettv->vval.v_float = log10(f);
5672 else
5673 rettv->vval.v_float = 0.0;
5674}
5675#endif
5676
5677#ifdef FEAT_LUA
5678/*
5679 * "luaeval()" function
5680 */
5681 static void
5682f_luaeval(typval_T *argvars, typval_T *rettv)
5683{
5684 char_u *str;
5685 char_u buf[NUMBUFLEN];
5686
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005687 if (check_restricted() || check_secure())
5688 return;
5689
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005690 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691 do_luaeval(str, argvars + 1, rettv);
5692}
5693#endif
5694
5695/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005696 * "maparg()" function
5697 */
5698 static void
5699f_maparg(typval_T *argvars, typval_T *rettv)
5700{
5701 get_maparg(argvars, rettv, TRUE);
5702}
5703
5704/*
5705 * "mapcheck()" function
5706 */
5707 static void
5708f_mapcheck(typval_T *argvars, typval_T *rettv)
5709{
5710 get_maparg(argvars, rettv, FALSE);
5711}
5712
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005713typedef enum
5714{
5715 MATCH_END, /* matchend() */
5716 MATCH_MATCH, /* match() */
5717 MATCH_STR, /* matchstr() */
5718 MATCH_LIST, /* matchlist() */
5719 MATCH_POS /* matchstrpos() */
5720} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005721
5722 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005723find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005724{
5725 char_u *str = NULL;
5726 long len = 0;
5727 char_u *expr = NULL;
5728 char_u *pat;
5729 regmatch_T regmatch;
5730 char_u patbuf[NUMBUFLEN];
5731 char_u strbuf[NUMBUFLEN];
5732 char_u *save_cpo;
5733 long start = 0;
5734 long nth = 1;
5735 colnr_T startcol = 0;
5736 int match = 0;
5737 list_T *l = NULL;
5738 listitem_T *li = NULL;
5739 long idx = 0;
5740 char_u *tofree = NULL;
5741
5742 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
5743 save_cpo = p_cpo;
5744 p_cpo = (char_u *)"";
5745
5746 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005747 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005748 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005749 /* type MATCH_LIST: return empty list when there are no matches.
5750 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005751 if (rettv_list_alloc(rettv) == FAIL)
5752 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005753 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005754 && (list_append_string(rettv->vval.v_list,
5755 (char_u *)"", 0) == FAIL
5756 || list_append_number(rettv->vval.v_list,
5757 (varnumber_T)-1) == FAIL
5758 || list_append_number(rettv->vval.v_list,
5759 (varnumber_T)-1) == FAIL
5760 || list_append_number(rettv->vval.v_list,
5761 (varnumber_T)-1) == FAIL))
5762 {
5763 list_free(rettv->vval.v_list);
5764 rettv->vval.v_list = NULL;
5765 goto theend;
5766 }
5767 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005768 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005769 {
5770 rettv->v_type = VAR_STRING;
5771 rettv->vval.v_string = NULL;
5772 }
5773
5774 if (argvars[0].v_type == VAR_LIST)
5775 {
5776 if ((l = argvars[0].vval.v_list) == NULL)
5777 goto theend;
5778 li = l->lv_first;
5779 }
5780 else
5781 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005782 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 len = (long)STRLEN(str);
5784 }
5785
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005786 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005787 if (pat == NULL)
5788 goto theend;
5789
5790 if (argvars[2].v_type != VAR_UNKNOWN)
5791 {
5792 int error = FALSE;
5793
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005794 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005795 if (error)
5796 goto theend;
5797 if (l != NULL)
5798 {
5799 li = list_find(l, start);
5800 if (li == NULL)
5801 goto theend;
5802 idx = l->lv_idx; /* use the cached index */
5803 }
5804 else
5805 {
5806 if (start < 0)
5807 start = 0;
5808 if (start > len)
5809 goto theend;
5810 /* When "count" argument is there ignore matches before "start",
5811 * otherwise skip part of the string. Differs when pattern is "^"
5812 * or "\<". */
5813 if (argvars[3].v_type != VAR_UNKNOWN)
5814 startcol = start;
5815 else
5816 {
5817 str += start;
5818 len -= start;
5819 }
5820 }
5821
5822 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005823 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005824 if (error)
5825 goto theend;
5826 }
5827
5828 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5829 if (regmatch.regprog != NULL)
5830 {
5831 regmatch.rm_ic = p_ic;
5832
5833 for (;;)
5834 {
5835 if (l != NULL)
5836 {
5837 if (li == NULL)
5838 {
5839 match = FALSE;
5840 break;
5841 }
5842 vim_free(tofree);
5843 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5844 if (str == NULL)
5845 break;
5846 }
5847
5848 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5849
5850 if (match && --nth <= 0)
5851 break;
5852 if (l == NULL && !match)
5853 break;
5854
5855 /* Advance to just after the match. */
5856 if (l != NULL)
5857 {
5858 li = li->li_next;
5859 ++idx;
5860 }
5861 else
5862 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005863 startcol = (colnr_T)(regmatch.startp[0]
5864 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005865 if (startcol > (colnr_T)len
5866 || str + startcol <= regmatch.startp[0])
5867 {
5868 match = FALSE;
5869 break;
5870 }
5871 }
5872 }
5873
5874 if (match)
5875 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005876 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005877 {
5878 listitem_T *li1 = rettv->vval.v_list->lv_first;
5879 listitem_T *li2 = li1->li_next;
5880 listitem_T *li3 = li2->li_next;
5881 listitem_T *li4 = li3->li_next;
5882
5883 vim_free(li1->li_tv.vval.v_string);
5884 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5885 (int)(regmatch.endp[0] - regmatch.startp[0]));
5886 li3->li_tv.vval.v_number =
5887 (varnumber_T)(regmatch.startp[0] - expr);
5888 li4->li_tv.vval.v_number =
5889 (varnumber_T)(regmatch.endp[0] - expr);
5890 if (l != NULL)
5891 li2->li_tv.vval.v_number = (varnumber_T)idx;
5892 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005893 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005894 {
5895 int i;
5896
5897 /* return list with matched string and submatches */
5898 for (i = 0; i < NSUBEXP; ++i)
5899 {
5900 if (regmatch.endp[i] == NULL)
5901 {
5902 if (list_append_string(rettv->vval.v_list,
5903 (char_u *)"", 0) == FAIL)
5904 break;
5905 }
5906 else if (list_append_string(rettv->vval.v_list,
5907 regmatch.startp[i],
5908 (int)(regmatch.endp[i] - regmatch.startp[i]))
5909 == FAIL)
5910 break;
5911 }
5912 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005913 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914 {
5915 /* return matched string */
5916 if (l != NULL)
5917 copy_tv(&li->li_tv, rettv);
5918 else
5919 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
5920 (int)(regmatch.endp[0] - regmatch.startp[0]));
5921 }
5922 else if (l != NULL)
5923 rettv->vval.v_number = idx;
5924 else
5925 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005926 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005927 rettv->vval.v_number =
5928 (varnumber_T)(regmatch.startp[0] - str);
5929 else
5930 rettv->vval.v_number =
5931 (varnumber_T)(regmatch.endp[0] - str);
5932 rettv->vval.v_number += (varnumber_T)(str - expr);
5933 }
5934 }
5935 vim_regfree(regmatch.regprog);
5936 }
5937
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005938theend:
5939 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005940 /* matchstrpos() without a list: drop the second item. */
5941 listitem_remove(rettv->vval.v_list,
5942 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005943 vim_free(tofree);
5944 p_cpo = save_cpo;
5945}
5946
5947/*
5948 * "match()" function
5949 */
5950 static void
5951f_match(typval_T *argvars, typval_T *rettv)
5952{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005953 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005954}
5955
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005956/*
5957 * "matchend()" function
5958 */
5959 static void
5960f_matchend(typval_T *argvars, typval_T *rettv)
5961{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005962 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005963}
5964
5965/*
5966 * "matchlist()" function
5967 */
5968 static void
5969f_matchlist(typval_T *argvars, typval_T *rettv)
5970{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005971 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972}
5973
5974/*
5975 * "matchstr()" function
5976 */
5977 static void
5978f_matchstr(typval_T *argvars, typval_T *rettv)
5979{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005980 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005981}
5982
5983/*
5984 * "matchstrpos()" function
5985 */
5986 static void
5987f_matchstrpos(typval_T *argvars, typval_T *rettv)
5988{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005989 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005990}
5991
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005992 static void
5993max_min(typval_T *argvars, typval_T *rettv, int domax)
5994{
5995 varnumber_T n = 0;
5996 varnumber_T i;
5997 int error = FALSE;
5998
5999 if (argvars[0].v_type == VAR_LIST)
6000 {
6001 list_T *l;
6002 listitem_T *li;
6003
6004 l = argvars[0].vval.v_list;
6005 if (l != NULL)
6006 {
6007 li = l->lv_first;
6008 if (li != NULL)
6009 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006010 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006011 for (;;)
6012 {
6013 li = li->li_next;
6014 if (li == NULL)
6015 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006016 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006017 if (domax ? i > n : i < n)
6018 n = i;
6019 }
6020 }
6021 }
6022 }
6023 else if (argvars[0].v_type == VAR_DICT)
6024 {
6025 dict_T *d;
6026 int first = TRUE;
6027 hashitem_T *hi;
6028 int todo;
6029
6030 d = argvars[0].vval.v_dict;
6031 if (d != NULL)
6032 {
6033 todo = (int)d->dv_hashtab.ht_used;
6034 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
6035 {
6036 if (!HASHITEM_EMPTY(hi))
6037 {
6038 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006039 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006040 if (first)
6041 {
6042 n = i;
6043 first = FALSE;
6044 }
6045 else if (domax ? i > n : i < n)
6046 n = i;
6047 }
6048 }
6049 }
6050 }
6051 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006052 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006053 rettv->vval.v_number = error ? 0 : n;
6054}
6055
6056/*
6057 * "max()" function
6058 */
6059 static void
6060f_max(typval_T *argvars, typval_T *rettv)
6061{
6062 max_min(argvars, rettv, TRUE);
6063}
6064
6065/*
6066 * "min()" function
6067 */
6068 static void
6069f_min(typval_T *argvars, typval_T *rettv)
6070{
6071 max_min(argvars, rettv, FALSE);
6072}
6073
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006074/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075 * "mode()" function
6076 */
6077 static void
6078f_mode(typval_T *argvars, typval_T *rettv)
6079{
Bram Moolenaar612cc382018-07-29 15:34:26 +02006080 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081
Bram Moolenaar612cc382018-07-29 15:34:26 +02006082 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083
6084 if (time_for_testing == 93784)
6085 {
6086 /* Testing the two-character code. */
6087 buf[0] = 'x';
6088 buf[1] = '!';
6089 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02006090#ifdef FEAT_TERMINAL
6091 else if (term_use_loop())
6092 buf[0] = 't';
6093#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006094 else if (VIsual_active)
6095 {
6096 if (VIsual_select)
6097 buf[0] = VIsual_mode + 's' - 'v';
6098 else
6099 buf[0] = VIsual_mode;
6100 }
6101 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
6102 || State == CONFIRM)
6103 {
6104 buf[0] = 'r';
6105 if (State == ASKMORE)
6106 buf[1] = 'm';
6107 else if (State == CONFIRM)
6108 buf[1] = '?';
6109 }
6110 else if (State == EXTERNCMD)
6111 buf[0] = '!';
6112 else if (State & INSERT)
6113 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006114 if (State & VREPLACE_FLAG)
6115 {
6116 buf[0] = 'R';
6117 buf[1] = 'v';
6118 }
6119 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01006120 {
6121 if (State & REPLACE_FLAG)
6122 buf[0] = 'R';
6123 else
6124 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006125 if (ins_compl_active())
6126 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01006127 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01006128 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006129 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006130 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01006131 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006132 {
6133 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006134 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006135 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006136 else if (exmode_active == EXMODE_NORMAL)
6137 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006138 }
6139 else
6140 {
6141 buf[0] = 'n';
6142 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01006143 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006144 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01006145 // to be able to detect force-linewise/blockwise/characterwise operations
6146 buf[2] = motion_force;
6147 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02006148 else if (restart_edit == 'I' || restart_edit == 'R'
6149 || restart_edit == 'V')
6150 {
6151 buf[1] = 'i';
6152 buf[2] = restart_edit;
6153 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006154 }
6155
6156 /* Clear out the minor mode when the argument is not a non-zero number or
6157 * non-empty string. */
6158 if (!non_zero_arg(&argvars[0]))
6159 buf[1] = NUL;
6160
6161 rettv->vval.v_string = vim_strsave(buf);
6162 rettv->v_type = VAR_STRING;
6163}
6164
6165#if defined(FEAT_MZSCHEME) || defined(PROTO)
6166/*
6167 * "mzeval()" function
6168 */
6169 static void
6170f_mzeval(typval_T *argvars, typval_T *rettv)
6171{
6172 char_u *str;
6173 char_u buf[NUMBUFLEN];
6174
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006175 if (check_restricted() || check_secure())
6176 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006177 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006178 do_mzeval(str, rettv);
6179}
6180
6181 void
6182mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
6183{
6184 typval_T argvars[3];
6185
6186 argvars[0].v_type = VAR_STRING;
6187 argvars[0].vval.v_string = name;
6188 copy_tv(args, &argvars[1]);
6189 argvars[2].v_type = VAR_UNKNOWN;
6190 f_call(argvars, rettv);
6191 clear_tv(&argvars[1]);
6192}
6193#endif
6194
6195/*
6196 * "nextnonblank()" function
6197 */
6198 static void
6199f_nextnonblank(typval_T *argvars, typval_T *rettv)
6200{
6201 linenr_T lnum;
6202
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006203 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006204 {
6205 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
6206 {
6207 lnum = 0;
6208 break;
6209 }
6210 if (*skipwhite(ml_get(lnum)) != NUL)
6211 break;
6212 }
6213 rettv->vval.v_number = lnum;
6214}
6215
6216/*
6217 * "nr2char()" function
6218 */
6219 static void
6220f_nr2char(typval_T *argvars, typval_T *rettv)
6221{
6222 char_u buf[NUMBUFLEN];
6223
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006224 if (has_mbyte)
6225 {
6226 int utf8 = 0;
6227
6228 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006229 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006230 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01006231 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006232 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006233 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006234 }
6235 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006236 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006237 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006238 buf[1] = NUL;
6239 }
6240 rettv->v_type = VAR_STRING;
6241 rettv->vval.v_string = vim_strsave(buf);
6242}
6243
6244/*
6245 * "or(expr, expr)" function
6246 */
6247 static void
6248f_or(typval_T *argvars, typval_T *rettv)
6249{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006250 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
6251 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006252}
6253
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006254#ifdef FEAT_PERL
6255/*
6256 * "perleval()" function
6257 */
6258 static void
6259f_perleval(typval_T *argvars, typval_T *rettv)
6260{
6261 char_u *str;
6262 char_u buf[NUMBUFLEN];
6263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006264 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006265 do_perleval(str, rettv);
6266}
6267#endif
6268
6269#ifdef FEAT_FLOAT
6270/*
6271 * "pow()" function
6272 */
6273 static void
6274f_pow(typval_T *argvars, typval_T *rettv)
6275{
6276 float_T fx = 0.0, fy = 0.0;
6277
6278 rettv->v_type = VAR_FLOAT;
6279 if (get_float_arg(argvars, &fx) == OK
6280 && get_float_arg(&argvars[1], &fy) == OK)
6281 rettv->vval.v_float = pow(fx, fy);
6282 else
6283 rettv->vval.v_float = 0.0;
6284}
6285#endif
6286
6287/*
6288 * "prevnonblank()" function
6289 */
6290 static void
6291f_prevnonblank(typval_T *argvars, typval_T *rettv)
6292{
6293 linenr_T lnum;
6294
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006295 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006296 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
6297 lnum = 0;
6298 else
6299 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
6300 --lnum;
6301 rettv->vval.v_number = lnum;
6302}
6303
6304/* This dummy va_list is here because:
6305 * - passing a NULL pointer doesn't work when va_list isn't a pointer
6306 * - locally in the function results in a "used before set" warning
6307 * - using va_start() to initialize it gives "function with fixed args" error */
6308static va_list ap;
6309
6310/*
6311 * "printf()" function
6312 */
6313 static void
6314f_printf(typval_T *argvars, typval_T *rettv)
6315{
6316 char_u buf[NUMBUFLEN];
6317 int len;
6318 char_u *s;
6319 int saved_did_emsg = did_emsg;
6320 char *fmt;
6321
6322 rettv->v_type = VAR_STRING;
6323 rettv->vval.v_string = NULL;
6324
6325 /* Get the required length, allocate the buffer and do it for real. */
6326 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006327 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006328 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006329 if (!did_emsg)
6330 {
6331 s = alloc(len + 1);
6332 if (s != NULL)
6333 {
6334 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006335 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
6336 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337 }
6338 }
6339 did_emsg |= saved_did_emsg;
6340}
6341
6342/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006343 * "pum_getpos()" function
6344 */
6345 static void
6346f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6347{
6348 if (rettv_dict_alloc(rettv) != OK)
6349 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006350 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006351}
6352
6353/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006354 * "pumvisible()" function
6355 */
6356 static void
6357f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6358{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006359 if (pum_visible())
6360 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361}
6362
6363#ifdef FEAT_PYTHON3
6364/*
6365 * "py3eval()" function
6366 */
6367 static void
6368f_py3eval(typval_T *argvars, typval_T *rettv)
6369{
6370 char_u *str;
6371 char_u buf[NUMBUFLEN];
6372
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006373 if (check_restricted() || check_secure())
6374 return;
6375
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006376 if (p_pyx == 0)
6377 p_pyx = 3;
6378
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006379 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006380 do_py3eval(str, rettv);
6381}
6382#endif
6383
6384#ifdef FEAT_PYTHON
6385/*
6386 * "pyeval()" function
6387 */
6388 static void
6389f_pyeval(typval_T *argvars, typval_T *rettv)
6390{
6391 char_u *str;
6392 char_u buf[NUMBUFLEN];
6393
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006394 if (check_restricted() || check_secure())
6395 return;
6396
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006397 if (p_pyx == 0)
6398 p_pyx = 2;
6399
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006400 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006401 do_pyeval(str, rettv);
6402}
6403#endif
6404
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006405#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
6406/*
6407 * "pyxeval()" function
6408 */
6409 static void
6410f_pyxeval(typval_T *argvars, typval_T *rettv)
6411{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006412 if (check_restricted() || check_secure())
6413 return;
6414
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006415# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
6416 init_pyxversion();
6417 if (p_pyx == 2)
6418 f_pyeval(argvars, rettv);
6419 else
6420 f_py3eval(argvars, rettv);
6421# elif defined(FEAT_PYTHON)
6422 f_pyeval(argvars, rettv);
6423# elif defined(FEAT_PYTHON3)
6424 f_py3eval(argvars, rettv);
6425# endif
6426}
6427#endif
6428
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006429/*
6430 * "range()" function
6431 */
6432 static void
6433f_range(typval_T *argvars, typval_T *rettv)
6434{
6435 varnumber_T start;
6436 varnumber_T end;
6437 varnumber_T stride = 1;
6438 varnumber_T i;
6439 int error = FALSE;
6440
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006441 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 if (argvars[1].v_type == VAR_UNKNOWN)
6443 {
6444 end = start - 1;
6445 start = 0;
6446 }
6447 else
6448 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006449 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006450 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006451 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006452 }
6453
6454 if (error)
6455 return; /* type error; errmsg already given */
6456 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006457 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006458 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006459 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006460 else
6461 {
6462 if (rettv_list_alloc(rettv) == OK)
6463 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6464 if (list_append_number(rettv->vval.v_list,
6465 (varnumber_T)i) == FAIL)
6466 break;
6467 }
6468}
6469
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006470 static void
6471return_register(int regname, typval_T *rettv)
6472{
6473 char_u buf[2] = {0, 0};
6474
6475 buf[0] = (char_u)regname;
6476 rettv->v_type = VAR_STRING;
6477 rettv->vval.v_string = vim_strsave(buf);
6478}
6479
6480/*
6481 * "reg_executing()" function
6482 */
6483 static void
6484f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6485{
6486 return_register(reg_executing, rettv);
6487}
6488
6489/*
6490 * "reg_recording()" function
6491 */
6492 static void
6493f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6494{
6495 return_register(reg_recording, rettv);
6496}
6497
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006498#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499/*
6500 * Convert a List to proftime_T.
6501 * Return FAIL when there is something wrong.
6502 */
6503 static int
6504list2proftime(typval_T *arg, proftime_T *tm)
6505{
6506 long n1, n2;
6507 int error = FALSE;
6508
6509 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
6510 || arg->vval.v_list->lv_len != 2)
6511 return FAIL;
6512 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
6513 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01006514# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006515 tm->HighPart = n1;
6516 tm->LowPart = n2;
6517# else
6518 tm->tv_sec = n1;
6519 tm->tv_usec = n2;
6520# endif
6521 return error ? FAIL : OK;
6522}
6523#endif /* FEAT_RELTIME */
6524
6525/*
6526 * "reltime()" function
6527 */
6528 static void
6529f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6530{
6531#ifdef FEAT_RELTIME
6532 proftime_T res;
6533 proftime_T start;
6534
6535 if (argvars[0].v_type == VAR_UNKNOWN)
6536 {
6537 /* No arguments: get current time. */
6538 profile_start(&res);
6539 }
6540 else if (argvars[1].v_type == VAR_UNKNOWN)
6541 {
6542 if (list2proftime(&argvars[0], &res) == FAIL)
6543 return;
6544 profile_end(&res);
6545 }
6546 else
6547 {
6548 /* Two arguments: compute the difference. */
6549 if (list2proftime(&argvars[0], &start) == FAIL
6550 || list2proftime(&argvars[1], &res) == FAIL)
6551 return;
6552 profile_sub(&res, &start);
6553 }
6554
6555 if (rettv_list_alloc(rettv) == OK)
6556 {
6557 long n1, n2;
6558
Bram Moolenaar4f974752019-02-17 17:44:42 +01006559# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 n1 = res.HighPart;
6561 n2 = res.LowPart;
6562# else
6563 n1 = res.tv_sec;
6564 n2 = res.tv_usec;
6565# endif
6566 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
6567 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
6568 }
6569#endif
6570}
6571
6572#ifdef FEAT_FLOAT
6573/*
6574 * "reltimefloat()" function
6575 */
6576 static void
6577f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
6578{
6579# ifdef FEAT_RELTIME
6580 proftime_T tm;
6581# endif
6582
6583 rettv->v_type = VAR_FLOAT;
6584 rettv->vval.v_float = 0;
6585# ifdef FEAT_RELTIME
6586 if (list2proftime(&argvars[0], &tm) == OK)
6587 rettv->vval.v_float = profile_float(&tm);
6588# endif
6589}
6590#endif
6591
6592/*
6593 * "reltimestr()" function
6594 */
6595 static void
6596f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
6597{
6598#ifdef FEAT_RELTIME
6599 proftime_T tm;
6600#endif
6601
6602 rettv->v_type = VAR_STRING;
6603 rettv->vval.v_string = NULL;
6604#ifdef FEAT_RELTIME
6605 if (list2proftime(&argvars[0], &tm) == OK)
6606 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
6607#endif
6608}
6609
6610#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006611 static void
6612make_connection(void)
6613{
6614 if (X_DISPLAY == NULL
6615# ifdef FEAT_GUI
6616 && !gui.in_use
6617# endif
6618 )
6619 {
6620 x_force_connect = TRUE;
6621 setup_term_clip();
6622 x_force_connect = FALSE;
6623 }
6624}
6625
6626 static int
6627check_connection(void)
6628{
6629 make_connection();
6630 if (X_DISPLAY == NULL)
6631 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006632 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006633 return FAIL;
6634 }
6635 return OK;
6636}
6637#endif
6638
6639#ifdef FEAT_CLIENTSERVER
6640 static void
6641remote_common(typval_T *argvars, typval_T *rettv, int expr)
6642{
6643 char_u *server_name;
6644 char_u *keys;
6645 char_u *r = NULL;
6646 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006647 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006648# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006649 HWND w;
6650# else
6651 Window w;
6652# endif
6653
6654 if (check_restricted() || check_secure())
6655 return;
6656
6657# ifdef FEAT_X11
6658 if (check_connection() == FAIL)
6659 return;
6660# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006661 if (argvars[2].v_type != VAR_UNKNOWN
6662 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006663 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006664
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006665 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006666 if (server_name == NULL)
6667 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006668 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01006669# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006670 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006671# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006672 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
6673 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006674# endif
6675 {
6676 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006677 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006678 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006679 vim_free(r);
6680 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006681 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006682 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683 return;
6684 }
6685
6686 rettv->vval.v_string = r;
6687
6688 if (argvars[2].v_type != VAR_UNKNOWN)
6689 {
6690 dictitem_T v;
6691 char_u str[30];
6692 char_u *idvar;
6693
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006694 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006695 if (idvar != NULL && *idvar != NUL)
6696 {
6697 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
6698 v.di_tv.v_type = VAR_STRING;
6699 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006701 vim_free(v.di_tv.vval.v_string);
6702 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006703 }
6704}
6705#endif
6706
6707/*
6708 * "remote_expr()" function
6709 */
6710 static void
6711f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
6712{
6713 rettv->v_type = VAR_STRING;
6714 rettv->vval.v_string = NULL;
6715#ifdef FEAT_CLIENTSERVER
6716 remote_common(argvars, rettv, TRUE);
6717#endif
6718}
6719
6720/*
6721 * "remote_foreground()" function
6722 */
6723 static void
6724f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6725{
6726#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006727# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006728 /* On Win32 it's done in this application. */
6729 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006730 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006731
6732 if (server_name != NULL)
6733 serverForeground(server_name);
6734 }
6735# else
6736 /* Send a foreground() expression to the server. */
6737 argvars[1].v_type = VAR_STRING;
6738 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
6739 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006740 rettv->v_type = VAR_STRING;
6741 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742 remote_common(argvars, rettv, TRUE);
6743 vim_free(argvars[1].vval.v_string);
6744# endif
6745#endif
6746}
6747
6748 static void
6749f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
6750{
6751#ifdef FEAT_CLIENTSERVER
6752 dictitem_T v;
6753 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006754# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006755 long_u n = 0;
6756# endif
6757 char_u *serverid;
6758
6759 if (check_restricted() || check_secure())
6760 {
6761 rettv->vval.v_number = -1;
6762 return;
6763 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006764 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006765 if (serverid == NULL)
6766 {
6767 rettv->vval.v_number = -1;
6768 return; /* type error; errmsg already given */
6769 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01006770# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006771 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
6772 if (n == 0)
6773 rettv->vval.v_number = -1;
6774 else
6775 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006776 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006777 rettv->vval.v_number = (s != NULL);
6778 }
6779# else
6780 if (check_connection() == FAIL)
6781 return;
6782
6783 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
6784 serverStrToWin(serverid), &s);
6785# endif
6786
6787 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
6788 {
6789 char_u *retvar;
6790
6791 v.di_tv.v_type = VAR_STRING;
6792 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006793 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 if (retvar != NULL)
6795 set_var(retvar, &v.di_tv, FALSE);
6796 vim_free(v.di_tv.vval.v_string);
6797 }
6798#else
6799 rettv->vval.v_number = -1;
6800#endif
6801}
6802
6803 static void
6804f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
6805{
6806 char_u *r = NULL;
6807
6808#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006809 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006810
6811 if (serverid != NULL && !check_restricted() && !check_secure())
6812 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006813 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006814# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01006815 /* The server's HWND is encoded in the 'id' parameter */
6816 long_u n = 0;
6817# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006818
6819 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006820 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006821
Bram Moolenaar4f974752019-02-17 17:44:42 +01006822# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006823 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
6824 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006825 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006826 if (r == NULL)
6827# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006828 if (check_connection() == FAIL
6829 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
6830 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006832 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006833 }
6834#endif
6835 rettv->v_type = VAR_STRING;
6836 rettv->vval.v_string = r;
6837}
6838
6839/*
6840 * "remote_send()" function
6841 */
6842 static void
6843f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
6844{
6845 rettv->v_type = VAR_STRING;
6846 rettv->vval.v_string = NULL;
6847#ifdef FEAT_CLIENTSERVER
6848 remote_common(argvars, rettv, FALSE);
6849#endif
6850}
6851
6852/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006853 * "remote_startserver()" function
6854 */
6855 static void
6856f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6857{
6858#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006859 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006860
6861 if (server == NULL)
6862 return; /* type error; errmsg already given */
6863 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006864 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006865 else
6866 {
6867# ifdef FEAT_X11
6868 if (check_connection() == OK)
6869 serverRegisterName(X_DISPLAY, server);
6870# else
6871 serverSetName(server);
6872# endif
6873 }
6874#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006875 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006876#endif
6877}
6878
6879/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 * "rename({from}, {to})" function
6881 */
6882 static void
6883f_rename(typval_T *argvars, typval_T *rettv)
6884{
6885 char_u buf[NUMBUFLEN];
6886
6887 if (check_restricted() || check_secure())
6888 rettv->vval.v_number = -1;
6889 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006890 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6891 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892}
6893
6894/*
6895 * "repeat()" function
6896 */
6897 static void
6898f_repeat(typval_T *argvars, typval_T *rettv)
6899{
6900 char_u *p;
6901 int n;
6902 int slen;
6903 int len;
6904 char_u *r;
6905 int i;
6906
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006907 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 if (argvars[0].v_type == VAR_LIST)
6909 {
6910 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6911 while (n-- > 0)
6912 if (list_extend(rettv->vval.v_list,
6913 argvars[0].vval.v_list, NULL) == FAIL)
6914 break;
6915 }
6916 else
6917 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006918 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006919 rettv->v_type = VAR_STRING;
6920 rettv->vval.v_string = NULL;
6921
6922 slen = (int)STRLEN(p);
6923 len = slen * n;
6924 if (len <= 0)
6925 return;
6926
6927 r = alloc(len + 1);
6928 if (r != NULL)
6929 {
6930 for (i = 0; i < n; i++)
6931 mch_memmove(r + i * slen, p, (size_t)slen);
6932 r[len] = NUL;
6933 }
6934
6935 rettv->vval.v_string = r;
6936 }
6937}
6938
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006939#define SP_NOMOVE 0x01 /* don't move cursor */
6940#define SP_REPEAT 0x02 /* repeat to find outer pair */
6941#define SP_RETCOUNT 0x04 /* return matchcount */
6942#define SP_SETPCMARK 0x08 /* set previous context mark */
6943#define SP_START 0x10 /* accept match at start position */
6944#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
6945#define SP_END 0x40 /* leave cursor at end of match */
6946#define SP_COLUMN 0x80 /* start at cursor column */
6947
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948/*
6949 * Get flags for a search function.
6950 * Possibly sets "p_ws".
6951 * Returns BACKWARD, FORWARD or zero (for an error).
6952 */
6953 static int
6954get_search_arg(typval_T *varp, int *flagsp)
6955{
6956 int dir = FORWARD;
6957 char_u *flags;
6958 char_u nbuf[NUMBUFLEN];
6959 int mask;
6960
6961 if (varp->v_type != VAR_UNKNOWN)
6962 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006963 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006964 if (flags == NULL)
6965 return 0; /* type error; errmsg already given */
6966 while (*flags != NUL)
6967 {
6968 switch (*flags)
6969 {
6970 case 'b': dir = BACKWARD; break;
6971 case 'w': p_ws = TRUE; break;
6972 case 'W': p_ws = FALSE; break;
6973 default: mask = 0;
6974 if (flagsp != NULL)
6975 switch (*flags)
6976 {
6977 case 'c': mask = SP_START; break;
6978 case 'e': mask = SP_END; break;
6979 case 'm': mask = SP_RETCOUNT; break;
6980 case 'n': mask = SP_NOMOVE; break;
6981 case 'p': mask = SP_SUBPAT; break;
6982 case 'r': mask = SP_REPEAT; break;
6983 case 's': mask = SP_SETPCMARK; break;
6984 case 'z': mask = SP_COLUMN; break;
6985 }
6986 if (mask == 0)
6987 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006988 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006989 dir = 0;
6990 }
6991 else
6992 *flagsp |= mask;
6993 }
6994 if (dir == 0)
6995 break;
6996 ++flags;
6997 }
6998 }
6999 return dir;
7000}
7001
7002/*
7003 * Shared by search() and searchpos() functions.
7004 */
7005 static int
7006search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
7007{
7008 int flags;
7009 char_u *pat;
7010 pos_T pos;
7011 pos_T save_cursor;
7012 int save_p_ws = p_ws;
7013 int dir;
7014 int retval = 0; /* default: FAIL */
7015 long lnum_stop = 0;
7016 proftime_T tm;
7017#ifdef FEAT_RELTIME
7018 long time_limit = 0;
7019#endif
7020 int options = SEARCH_KEEP;
7021 int subpatnum;
7022
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007023 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
7025 if (dir == 0)
7026 goto theend;
7027 flags = *flagsp;
7028 if (flags & SP_START)
7029 options |= SEARCH_START;
7030 if (flags & SP_END)
7031 options |= SEARCH_END;
7032 if (flags & SP_COLUMN)
7033 options |= SEARCH_COL;
7034
7035 /* Optional arguments: line number to stop searching and timeout. */
7036 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
7037 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007038 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039 if (lnum_stop < 0)
7040 goto theend;
7041#ifdef FEAT_RELTIME
7042 if (argvars[3].v_type != VAR_UNKNOWN)
7043 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007044 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007045 if (time_limit < 0)
7046 goto theend;
7047 }
7048#endif
7049 }
7050
7051#ifdef FEAT_RELTIME
7052 /* Set the time limit, if there is one. */
7053 profile_setlimit(time_limit, &tm);
7054#endif
7055
7056 /*
7057 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
7058 * Check to make sure only those flags are set.
7059 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
7060 * flags cannot be set. Check for that condition also.
7061 */
7062 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
7063 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7064 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007065 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007066 goto theend;
7067 }
7068
7069 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007070 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007071 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007072 if (subpatnum != FAIL)
7073 {
7074 if (flags & SP_SUBPAT)
7075 retval = subpatnum;
7076 else
7077 retval = pos.lnum;
7078 if (flags & SP_SETPCMARK)
7079 setpcmark();
7080 curwin->w_cursor = pos;
7081 if (match_pos != NULL)
7082 {
7083 /* Store the match cursor position */
7084 match_pos->lnum = pos.lnum;
7085 match_pos->col = pos.col + 1;
7086 }
7087 /* "/$" will put the cursor after the end of the line, may need to
7088 * correct that here */
7089 check_cursor();
7090 }
7091
7092 /* If 'n' flag is used: restore cursor position. */
7093 if (flags & SP_NOMOVE)
7094 curwin->w_cursor = save_cursor;
7095 else
7096 curwin->w_set_curswant = TRUE;
7097theend:
7098 p_ws = save_p_ws;
7099
7100 return retval;
7101}
7102
7103#ifdef FEAT_FLOAT
7104
7105/*
7106 * round() is not in C90, use ceil() or floor() instead.
7107 */
7108 float_T
7109vim_round(float_T f)
7110{
7111 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
7112}
7113
7114/*
7115 * "round({float})" function
7116 */
7117 static void
7118f_round(typval_T *argvars, typval_T *rettv)
7119{
7120 float_T f = 0.0;
7121
7122 rettv->v_type = VAR_FLOAT;
7123 if (get_float_arg(argvars, &f) == OK)
7124 rettv->vval.v_float = vim_round(f);
7125 else
7126 rettv->vval.v_float = 0.0;
7127}
7128#endif
7129
Bram Moolenaare99be0e2019-03-26 22:51:09 +01007130#ifdef FEAT_RUBY
7131/*
7132 * "rubyeval()" function
7133 */
7134 static void
7135f_rubyeval(typval_T *argvars, typval_T *rettv)
7136{
7137 char_u *str;
7138 char_u buf[NUMBUFLEN];
7139
7140 str = tv_get_string_buf(&argvars[0], buf);
7141 do_rubyeval(str, rettv);
7142}
7143#endif
7144
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007145/*
7146 * "screenattr()" function
7147 */
7148 static void
7149f_screenattr(typval_T *argvars, typval_T *rettv)
7150{
7151 int row;
7152 int col;
7153 int c;
7154
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007155 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7156 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007157 if (row < 0 || row >= screen_Rows
7158 || col < 0 || col >= screen_Columns)
7159 c = -1;
7160 else
7161 c = ScreenAttrs[LineOffset[row] + col];
7162 rettv->vval.v_number = c;
7163}
7164
7165/*
7166 * "screenchar()" function
7167 */
7168 static void
7169f_screenchar(typval_T *argvars, typval_T *rettv)
7170{
7171 int row;
7172 int col;
7173 int off;
7174 int c;
7175
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007176 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7177 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007178 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007179 c = -1;
7180 else
7181 {
7182 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007183 if (enc_utf8 && ScreenLinesUC[off] != 0)
7184 c = ScreenLinesUC[off];
7185 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007186 c = ScreenLines[off];
7187 }
7188 rettv->vval.v_number = c;
7189}
7190
7191/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007192 * "screenchars()" function
7193 */
7194 static void
7195f_screenchars(typval_T *argvars, typval_T *rettv)
7196{
7197 int row;
7198 int col;
7199 int off;
7200 int c;
7201 int i;
7202
7203 if (rettv_list_alloc(rettv) == FAIL)
7204 return;
7205 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7206 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7207 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7208 return;
7209
7210 off = LineOffset[row] + col;
7211 if (enc_utf8 && ScreenLinesUC[off] != 0)
7212 c = ScreenLinesUC[off];
7213 else
7214 c = ScreenLines[off];
7215 list_append_number(rettv->vval.v_list, (varnumber_T)c);
7216
7217 if (enc_utf8)
7218
7219 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7220 list_append_number(rettv->vval.v_list,
7221 (varnumber_T)ScreenLinesC[i][off]);
7222}
7223
7224/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007225 * "screencol()" function
7226 *
7227 * First column is 1 to be consistent with virtcol().
7228 */
7229 static void
7230f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
7231{
7232 rettv->vval.v_number = screen_screencol() + 1;
7233}
7234
7235/*
7236 * "screenrow()" function
7237 */
7238 static void
7239f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
7240{
7241 rettv->vval.v_number = screen_screenrow() + 1;
7242}
7243
7244/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007245 * "screenstring()" function
7246 */
7247 static void
7248f_screenstring(typval_T *argvars, typval_T *rettv)
7249{
7250 int row;
7251 int col;
7252 int off;
7253 int c;
7254 int i;
7255 char_u buf[MB_MAXBYTES + 1];
7256 int buflen = 0;
7257
7258 rettv->vval.v_string = NULL;
7259 rettv->v_type = VAR_STRING;
7260
7261 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7262 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7263 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7264 return;
7265
7266 off = LineOffset[row] + col;
7267 if (enc_utf8 && ScreenLinesUC[off] != 0)
7268 c = ScreenLinesUC[off];
7269 else
7270 c = ScreenLines[off];
7271 buflen += mb_char2bytes(c, buf);
7272
7273 if (enc_utf8)
7274 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7275 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
7276
7277 buf[buflen] = NUL;
7278 rettv->vval.v_string = vim_strsave(buf);
7279}
7280
7281/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007282 * "search()" function
7283 */
7284 static void
7285f_search(typval_T *argvars, typval_T *rettv)
7286{
7287 int flags = 0;
7288
7289 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
7290}
7291
7292/*
7293 * "searchdecl()" function
7294 */
7295 static void
7296f_searchdecl(typval_T *argvars, typval_T *rettv)
7297{
7298 int locally = 1;
7299 int thisblock = 0;
7300 int error = FALSE;
7301 char_u *name;
7302
7303 rettv->vval.v_number = 1; /* default: FAIL */
7304
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007305 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306 if (argvars[1].v_type != VAR_UNKNOWN)
7307 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007308 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007309 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007310 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007311 }
7312 if (!error && name != NULL)
7313 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
7314 locally, thisblock, SEARCH_KEEP) == FAIL;
7315}
7316
7317/*
7318 * Used by searchpair() and searchpairpos()
7319 */
7320 static int
7321searchpair_cmn(typval_T *argvars, pos_T *match_pos)
7322{
7323 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01007324 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 int save_p_ws = p_ws;
7326 int dir;
7327 int flags = 0;
7328 char_u nbuf1[NUMBUFLEN];
7329 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007330 int retval = 0; /* default: FAIL */
7331 long lnum_stop = 0;
7332 long time_limit = 0;
7333
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007334 /* Get the three pattern arguments: start, middle, end. Will result in an
7335 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007336 spat = tv_get_string_chk(&argvars[0]);
7337 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
7338 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007339 if (spat == NULL || mpat == NULL || epat == NULL)
7340 goto theend; /* type error */
7341
7342 /* Handle the optional fourth argument: flags */
7343 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
7344 if (dir == 0)
7345 goto theend;
7346
7347 /* Don't accept SP_END or SP_SUBPAT.
7348 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
7349 */
7350 if ((flags & (SP_END | SP_SUBPAT)) != 0
7351 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7352 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007353 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007354 goto theend;
7355 }
7356
7357 /* Using 'r' implies 'W', otherwise it doesn't work. */
7358 if (flags & SP_REPEAT)
7359 p_ws = FALSE;
7360
7361 /* Optional fifth argument: skip expression */
7362 if (argvars[3].v_type == VAR_UNKNOWN
7363 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01007364 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365 else
7366 {
Bram Moolenaar48570482017-10-30 21:48:41 +01007367 skip = &argvars[4];
7368 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
7369 && skip->v_type != VAR_STRING)
7370 {
7371 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007372 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01007373 goto theend;
7374 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007375 if (argvars[5].v_type != VAR_UNKNOWN)
7376 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007378 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007379 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007380 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007381 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007382 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383#ifdef FEAT_RELTIME
7384 if (argvars[6].v_type != VAR_UNKNOWN)
7385 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007386 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007388 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007389 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007390 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007391 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 }
7393#endif
7394 }
7395 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396
7397 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
7398 match_pos, lnum_stop, time_limit);
7399
7400theend:
7401 p_ws = save_p_ws;
7402
7403 return retval;
7404}
7405
7406/*
7407 * "searchpair()" function
7408 */
7409 static void
7410f_searchpair(typval_T *argvars, typval_T *rettv)
7411{
7412 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
7413}
7414
7415/*
7416 * "searchpairpos()" function
7417 */
7418 static void
7419f_searchpairpos(typval_T *argvars, typval_T *rettv)
7420{
7421 pos_T match_pos;
7422 int lnum = 0;
7423 int col = 0;
7424
7425 if (rettv_list_alloc(rettv) == FAIL)
7426 return;
7427
7428 if (searchpair_cmn(argvars, &match_pos) > 0)
7429 {
7430 lnum = match_pos.lnum;
7431 col = match_pos.col;
7432 }
7433
7434 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7435 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7436}
7437
7438/*
7439 * Search for a start/middle/end thing.
7440 * Used by searchpair(), see its documentation for the details.
7441 * Returns 0 or -1 for no match,
7442 */
7443 long
7444do_searchpair(
7445 char_u *spat, /* start pattern */
7446 char_u *mpat, /* middle pattern */
7447 char_u *epat, /* end pattern */
7448 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01007449 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007450 int flags, /* SP_SETPCMARK and other SP_ values */
7451 pos_T *match_pos,
7452 linenr_T lnum_stop, /* stop at this line if not zero */
7453 long time_limit UNUSED) /* stop after this many msec */
7454{
7455 char_u *save_cpo;
7456 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7457 long retval = 0;
7458 pos_T pos;
7459 pos_T firstpos;
7460 pos_T foundpos;
7461 pos_T save_cursor;
7462 pos_T save_pos;
7463 int n;
7464 int r;
7465 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007466 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007467 int err;
7468 int options = SEARCH_KEEP;
7469 proftime_T tm;
7470
7471 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7472 save_cpo = p_cpo;
7473 p_cpo = empty_option;
7474
7475#ifdef FEAT_RELTIME
7476 /* Set the time limit, if there is one. */
7477 profile_setlimit(time_limit, &tm);
7478#endif
7479
7480 /* Make two search patterns: start/end (pat2, for in nested pairs) and
7481 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02007482 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7483 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007484 if (pat2 == NULL || pat3 == NULL)
7485 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007486 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007487 if (*mpat == NUL)
7488 STRCPY(pat3, pat2);
7489 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007490 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491 spat, epat, mpat);
7492 if (flags & SP_START)
7493 options |= SEARCH_START;
7494
Bram Moolenaar48570482017-10-30 21:48:41 +01007495 if (skip != NULL)
7496 {
7497 /* Empty string means to not use the skip expression. */
7498 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
7499 use_skip = skip->vval.v_string != NULL
7500 && *skip->vval.v_string != NUL;
7501 }
7502
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503 save_cursor = curwin->w_cursor;
7504 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007505 CLEAR_POS(&firstpos);
7506 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507 pat = pat3;
7508 for (;;)
7509 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007510 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007511 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007512 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513 /* didn't find it or found the first match again: FAIL */
7514 break;
7515
7516 if (firstpos.lnum == 0)
7517 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007518 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519 {
7520 /* Found the same position again. Can happen with a pattern that
7521 * has "\zs" at the end and searching backwards. Advance one
7522 * character and try again. */
7523 if (dir == BACKWARD)
7524 decl(&pos);
7525 else
7526 incl(&pos);
7527 }
7528 foundpos = pos;
7529
7530 /* clear the start flag to avoid getting stuck here */
7531 options &= ~SEARCH_START;
7532
7533 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01007534 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007535 {
7536 save_pos = curwin->w_cursor;
7537 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007538 err = FALSE;
7539 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540 curwin->w_cursor = save_pos;
7541 if (err)
7542 {
7543 /* Evaluating {skip} caused an error, break here. */
7544 curwin->w_cursor = save_cursor;
7545 retval = -1;
7546 break;
7547 }
7548 if (r)
7549 continue;
7550 }
7551
7552 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7553 {
7554 /* Found end when searching backwards or start when searching
7555 * forward: nested pair. */
7556 ++nest;
7557 pat = pat2; /* nested, don't search for middle */
7558 }
7559 else
7560 {
7561 /* Found end when searching forward or start when searching
7562 * backward: end of (nested) pair; or found middle in outer pair. */
7563 if (--nest == 1)
7564 pat = pat3; /* outer level, search for middle */
7565 }
7566
7567 if (nest == 0)
7568 {
7569 /* Found the match: return matchcount or line number. */
7570 if (flags & SP_RETCOUNT)
7571 ++retval;
7572 else
7573 retval = pos.lnum;
7574 if (flags & SP_SETPCMARK)
7575 setpcmark();
7576 curwin->w_cursor = pos;
7577 if (!(flags & SP_REPEAT))
7578 break;
7579 nest = 1; /* search for next unmatched */
7580 }
7581 }
7582
7583 if (match_pos != NULL)
7584 {
7585 /* Store the match cursor position */
7586 match_pos->lnum = curwin->w_cursor.lnum;
7587 match_pos->col = curwin->w_cursor.col + 1;
7588 }
7589
7590 /* If 'n' flag is used or search failed: restore cursor position. */
7591 if ((flags & SP_NOMOVE) || retval == 0)
7592 curwin->w_cursor = save_cursor;
7593
7594theend:
7595 vim_free(pat2);
7596 vim_free(pat3);
7597 if (p_cpo == empty_option)
7598 p_cpo = save_cpo;
7599 else
7600 /* Darn, evaluating the {skip} expression changed the value. */
7601 free_string_option(save_cpo);
7602
7603 return retval;
7604}
7605
7606/*
7607 * "searchpos()" function
7608 */
7609 static void
7610f_searchpos(typval_T *argvars, typval_T *rettv)
7611{
7612 pos_T match_pos;
7613 int lnum = 0;
7614 int col = 0;
7615 int n;
7616 int flags = 0;
7617
7618 if (rettv_list_alloc(rettv) == FAIL)
7619 return;
7620
7621 n = search_cmn(argvars, &match_pos, &flags);
7622 if (n > 0)
7623 {
7624 lnum = match_pos.lnum;
7625 col = match_pos.col;
7626 }
7627
7628 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7629 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7630 if (flags & SP_SUBPAT)
7631 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7632}
7633
7634 static void
7635f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
7636{
7637#ifdef FEAT_CLIENTSERVER
7638 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007639 char_u *server = tv_get_string_chk(&argvars[0]);
7640 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007641
7642 rettv->vval.v_number = -1;
7643 if (server == NULL || reply == NULL)
7644 return;
7645 if (check_restricted() || check_secure())
7646 return;
7647# ifdef FEAT_X11
7648 if (check_connection() == FAIL)
7649 return;
7650# endif
7651
7652 if (serverSendReply(server, reply) < 0)
7653 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007654 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655 return;
7656 }
7657 rettv->vval.v_number = 0;
7658#else
7659 rettv->vval.v_number = -1;
7660#endif
7661}
7662
7663 static void
7664f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
7665{
7666 char_u *r = NULL;
7667
7668#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01007669# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 r = serverGetVimNames();
7671# else
7672 make_connection();
7673 if (X_DISPLAY != NULL)
7674 r = serverGetVimNames(X_DISPLAY);
7675# endif
7676#endif
7677 rettv->v_type = VAR_STRING;
7678 rettv->vval.v_string = r;
7679}
7680
7681/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007682 * "setbufline()" function
7683 */
7684 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02007685f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007686{
7687 linenr_T lnum;
7688 buf_T *buf;
7689
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007690 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007691 if (buf == NULL)
7692 rettv->vval.v_number = 1; /* FAIL */
7693 else
7694 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007695 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02007696 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007697 }
7698}
7699
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007700 static void
7701f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7702{
7703 dict_T *d;
7704 dictitem_T *di;
7705 char_u *csearch;
7706
7707 if (argvars[0].v_type != VAR_DICT)
7708 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007709 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007710 return;
7711 }
7712
7713 if ((d = argvars[0].vval.v_dict) != NULL)
7714 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007715 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716 if (csearch != NULL)
7717 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007718 if (enc_utf8)
7719 {
7720 int pcc[MAX_MCO];
7721 int c = utfc_ptr2char(csearch, pcc);
7722
7723 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7724 }
7725 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726 set_last_csearch(PTR2CHAR(csearch),
7727 csearch, MB_PTR2LEN(csearch));
7728 }
7729
7730 di = dict_find(d, (char_u *)"forward", -1);
7731 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007732 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007733 ? FORWARD : BACKWARD);
7734
7735 di = dict_find(d, (char_u *)"until", -1);
7736 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007737 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 }
7739}
7740
7741/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007742 * "setenv()" function
7743 */
7744 static void
7745f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7746{
7747 char_u namebuf[NUMBUFLEN];
7748 char_u valbuf[NUMBUFLEN];
7749 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7750
7751 if (argvars[1].v_type == VAR_SPECIAL
7752 && argvars[1].vval.v_number == VVAL_NULL)
7753 vim_unsetenv(name);
7754 else
7755 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7756}
7757
7758/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759 * "setfperm({fname}, {mode})" function
7760 */
7761 static void
7762f_setfperm(typval_T *argvars, typval_T *rettv)
7763{
7764 char_u *fname;
7765 char_u modebuf[NUMBUFLEN];
7766 char_u *mode_str;
7767 int i;
7768 int mask;
7769 int mode = 0;
7770
7771 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007772 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007773 if (fname == NULL)
7774 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007775 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 if (mode_str == NULL)
7777 return;
7778 if (STRLEN(mode_str) != 9)
7779 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007780 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007781 return;
7782 }
7783
7784 mask = 1;
7785 for (i = 8; i >= 0; --i)
7786 {
7787 if (mode_str[i] != '-')
7788 mode |= mask;
7789 mask = mask << 1;
7790 }
7791 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7792}
7793
7794/*
7795 * "setline()" function
7796 */
7797 static void
7798f_setline(typval_T *argvars, typval_T *rettv)
7799{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007800 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007801
Bram Moolenaarca851592018-06-06 21:04:07 +02007802 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007803}
7804
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007806 * "setpos()" function
7807 */
7808 static void
7809f_setpos(typval_T *argvars, typval_T *rettv)
7810{
7811 pos_T pos;
7812 int fnum;
7813 char_u *name;
7814 colnr_T curswant = -1;
7815
7816 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007817 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007818 if (name != NULL)
7819 {
7820 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7821 {
7822 if (--pos.col < 0)
7823 pos.col = 0;
7824 if (name[0] == '.' && name[1] == NUL)
7825 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007826 /* set cursor; "fnum" is ignored */
7827 curwin->w_cursor = pos;
7828 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007829 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007830 curwin->w_curswant = curswant - 1;
7831 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007833 check_cursor();
7834 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007835 }
7836 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7837 {
7838 /* set mark */
7839 if (setmark_pos(name[1], &pos, fnum) == OK)
7840 rettv->vval.v_number = 0;
7841 }
7842 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007843 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007844 }
7845 }
7846}
7847
7848/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007849 * "setreg()" function
7850 */
7851 static void
7852f_setreg(typval_T *argvars, typval_T *rettv)
7853{
7854 int regname;
7855 char_u *strregname;
7856 char_u *stropt;
7857 char_u *strval;
7858 int append;
7859 char_u yank_type;
7860 long block_len;
7861
7862 block_len = -1;
7863 yank_type = MAUTO;
7864 append = FALSE;
7865
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007866 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867 rettv->vval.v_number = 1; /* FAIL is default */
7868
7869 if (strregname == NULL)
7870 return; /* type error; errmsg already given */
7871 regname = *strregname;
7872 if (regname == 0 || regname == '@')
7873 regname = '"';
7874
7875 if (argvars[2].v_type != VAR_UNKNOWN)
7876 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007877 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007878 if (stropt == NULL)
7879 return; /* type error */
7880 for (; *stropt != NUL; ++stropt)
7881 switch (*stropt)
7882 {
7883 case 'a': case 'A': /* append */
7884 append = TRUE;
7885 break;
7886 case 'v': case 'c': /* character-wise selection */
7887 yank_type = MCHAR;
7888 break;
7889 case 'V': case 'l': /* line-wise selection */
7890 yank_type = MLINE;
7891 break;
7892 case 'b': case Ctrl_V: /* block-wise selection */
7893 yank_type = MBLOCK;
7894 if (VIM_ISDIGIT(stropt[1]))
7895 {
7896 ++stropt;
7897 block_len = getdigits(&stropt) - 1;
7898 --stropt;
7899 }
7900 break;
7901 }
7902 }
7903
7904 if (argvars[1].v_type == VAR_LIST)
7905 {
7906 char_u **lstval;
7907 char_u **allocval;
7908 char_u buf[NUMBUFLEN];
7909 char_u **curval;
7910 char_u **curallocval;
7911 list_T *ll = argvars[1].vval.v_list;
7912 listitem_T *li;
7913 int len;
7914
7915 /* If the list is NULL handle like an empty list. */
7916 len = ll == NULL ? 0 : ll->lv_len;
7917
7918 /* First half: use for pointers to result lines; second half: use for
7919 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007920 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 if (lstval == NULL)
7922 return;
7923 curval = lstval;
7924 allocval = lstval + len + 2;
7925 curallocval = allocval;
7926
7927 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
7928 li = li->li_next)
7929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007930 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931 if (strval == NULL)
7932 goto free_lstval;
7933 if (strval == buf)
7934 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007935 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 * overwrite the string. */
7937 strval = vim_strsave(buf);
7938 if (strval == NULL)
7939 goto free_lstval;
7940 *curallocval++ = strval;
7941 }
7942 *curval++ = strval;
7943 }
7944 *curval++ = NULL;
7945
7946 write_reg_contents_lst(regname, lstval, -1,
7947 append, yank_type, block_len);
7948free_lstval:
7949 while (curallocval > allocval)
7950 vim_free(*--curallocval);
7951 vim_free(lstval);
7952 }
7953 else
7954 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007955 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007956 if (strval == NULL)
7957 return;
7958 write_reg_contents_ex(regname, strval, -1,
7959 append, yank_type, block_len);
7960 }
7961 rettv->vval.v_number = 0;
7962}
7963
7964/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007965 * "settagstack()" function
7966 */
7967 static void
7968f_settagstack(typval_T *argvars, typval_T *rettv)
7969{
7970 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7971 win_T *wp;
7972 dict_T *d;
7973 int action = 'r';
7974
7975 rettv->vval.v_number = -1;
7976
7977 // first argument: window number or id
7978 wp = find_win_by_nr_or_id(&argvars[0]);
7979 if (wp == NULL)
7980 return;
7981
7982 // second argument: dict with items to set in the tag stack
7983 if (argvars[1].v_type != VAR_DICT)
7984 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007985 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007986 return;
7987 }
7988 d = argvars[1].vval.v_dict;
7989 if (d == NULL)
7990 return;
7991
7992 // third argument: action - 'a' for append and 'r' for replace.
7993 // default is to replace the stack.
7994 if (argvars[2].v_type == VAR_UNKNOWN)
7995 action = 'r';
7996 else if (argvars[2].v_type == VAR_STRING)
7997 {
7998 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007999 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008000 if (actstr == NULL)
8001 return;
8002 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
8003 action = *actstr;
8004 else
8005 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008006 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008007 return;
8008 }
8009 }
8010 else
8011 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008012 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008013 return;
8014 }
8015
8016 if (set_tagstack(wp, d, action) == OK)
8017 rettv->vval.v_number = 0;
8018}
8019
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008020#ifdef FEAT_CRYPT
8021/*
8022 * "sha256({string})" function
8023 */
8024 static void
8025f_sha256(typval_T *argvars, typval_T *rettv)
8026{
8027 char_u *p;
8028
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008029 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030 rettv->vval.v_string = vim_strsave(
8031 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
8032 rettv->v_type = VAR_STRING;
8033}
8034#endif /* FEAT_CRYPT */
8035
8036/*
8037 * "shellescape({string})" function
8038 */
8039 static void
8040f_shellescape(typval_T *argvars, typval_T *rettv)
8041{
Bram Moolenaar20615522017-06-05 18:46:26 +02008042 int do_special = non_zero_arg(&argvars[1]);
8043
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008044 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008045 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008046 rettv->v_type = VAR_STRING;
8047}
8048
8049/*
8050 * shiftwidth() function
8051 */
8052 static void
8053f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
8054{
Bram Moolenaarf9514162018-11-22 03:08:29 +01008055 rettv->vval.v_number = 0;
8056
8057 if (argvars[0].v_type != VAR_UNKNOWN)
8058 {
8059 long col;
8060
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008061 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01008062 if (col < 0)
8063 return; // type error; errmsg already given
8064#ifdef FEAT_VARTABS
8065 rettv->vval.v_number = get_sw_value_col(curbuf, col);
8066 return;
8067#endif
8068 }
8069
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070 rettv->vval.v_number = get_sw_value(curbuf);
8071}
8072
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008073#ifdef FEAT_FLOAT
8074/*
8075 * "sin()" function
8076 */
8077 static void
8078f_sin(typval_T *argvars, typval_T *rettv)
8079{
8080 float_T f = 0.0;
8081
8082 rettv->v_type = VAR_FLOAT;
8083 if (get_float_arg(argvars, &f) == OK)
8084 rettv->vval.v_float = sin(f);
8085 else
8086 rettv->vval.v_float = 0.0;
8087}
8088
8089/*
8090 * "sinh()" function
8091 */
8092 static void
8093f_sinh(typval_T *argvars, typval_T *rettv)
8094{
8095 float_T f = 0.0;
8096
8097 rettv->v_type = VAR_FLOAT;
8098 if (get_float_arg(argvars, &f) == OK)
8099 rettv->vval.v_float = sinh(f);
8100 else
8101 rettv->vval.v_float = 0.0;
8102}
8103#endif
8104
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008105/*
8106 * "soundfold({word})" function
8107 */
8108 static void
8109f_soundfold(typval_T *argvars, typval_T *rettv)
8110{
8111 char_u *s;
8112
8113 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008114 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008115#ifdef FEAT_SPELL
8116 rettv->vval.v_string = eval_soundfold(s);
8117#else
8118 rettv->vval.v_string = vim_strsave(s);
8119#endif
8120}
8121
8122/*
8123 * "spellbadword()" function
8124 */
8125 static void
8126f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
8127{
8128 char_u *word = (char_u *)"";
8129 hlf_T attr = HLF_COUNT;
8130 int len = 0;
8131
8132 if (rettv_list_alloc(rettv) == FAIL)
8133 return;
8134
8135#ifdef FEAT_SPELL
8136 if (argvars[0].v_type == VAR_UNKNOWN)
8137 {
8138 /* Find the start and length of the badly spelled word. */
8139 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
8140 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008141 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008143 curwin->w_set_curswant = TRUE;
8144 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008145 }
8146 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
8147 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008148 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008149 int capcol = -1;
8150
8151 if (str != NULL)
8152 {
8153 /* Check the argument for spelling. */
8154 while (*str != NUL)
8155 {
8156 len = spell_check(curwin, str, &attr, &capcol, FALSE);
8157 if (attr != HLF_COUNT)
8158 {
8159 word = str;
8160 break;
8161 }
8162 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02008163 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02008164 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165 }
8166 }
8167 }
8168#endif
8169
8170 list_append_string(rettv->vval.v_list, word, len);
8171 list_append_string(rettv->vval.v_list, (char_u *)(
8172 attr == HLF_SPB ? "bad" :
8173 attr == HLF_SPR ? "rare" :
8174 attr == HLF_SPL ? "local" :
8175 attr == HLF_SPC ? "caps" :
8176 ""), -1);
8177}
8178
8179/*
8180 * "spellsuggest()" function
8181 */
8182 static void
8183f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
8184{
8185#ifdef FEAT_SPELL
8186 char_u *str;
8187 int typeerr = FALSE;
8188 int maxcount;
8189 garray_T ga;
8190 int i;
8191 listitem_T *li;
8192 int need_capital = FALSE;
8193#endif
8194
8195 if (rettv_list_alloc(rettv) == FAIL)
8196 return;
8197
8198#ifdef FEAT_SPELL
8199 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
8200 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008201 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008202 if (argvars[1].v_type != VAR_UNKNOWN)
8203 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008204 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205 if (maxcount <= 0)
8206 return;
8207 if (argvars[2].v_type != VAR_UNKNOWN)
8208 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008209 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008210 if (typeerr)
8211 return;
8212 }
8213 }
8214 else
8215 maxcount = 25;
8216
8217 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
8218
8219 for (i = 0; i < ga.ga_len; ++i)
8220 {
8221 str = ((char_u **)ga.ga_data)[i];
8222
8223 li = listitem_alloc();
8224 if (li == NULL)
8225 vim_free(str);
8226 else
8227 {
8228 li->li_tv.v_type = VAR_STRING;
8229 li->li_tv.v_lock = 0;
8230 li->li_tv.vval.v_string = str;
8231 list_append(rettv->vval.v_list, li);
8232 }
8233 }
8234 ga_clear(&ga);
8235 }
8236#endif
8237}
8238
8239 static void
8240f_split(typval_T *argvars, typval_T *rettv)
8241{
8242 char_u *str;
8243 char_u *end;
8244 char_u *pat = NULL;
8245 regmatch_T regmatch;
8246 char_u patbuf[NUMBUFLEN];
8247 char_u *save_cpo;
8248 int match;
8249 colnr_T col = 0;
8250 int keepempty = FALSE;
8251 int typeerr = FALSE;
8252
8253 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8254 save_cpo = p_cpo;
8255 p_cpo = (char_u *)"";
8256
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008257 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008258 if (argvars[1].v_type != VAR_UNKNOWN)
8259 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008260 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008261 if (pat == NULL)
8262 typeerr = TRUE;
8263 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008264 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 }
8266 if (pat == NULL || *pat == NUL)
8267 pat = (char_u *)"[\\x01- ]\\+";
8268
8269 if (rettv_list_alloc(rettv) == FAIL)
8270 return;
8271 if (typeerr)
8272 return;
8273
8274 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8275 if (regmatch.regprog != NULL)
8276 {
8277 regmatch.rm_ic = FALSE;
8278 while (*str != NUL || keepempty)
8279 {
8280 if (*str == NUL)
8281 match = FALSE; /* empty item at the end */
8282 else
8283 match = vim_regexec_nl(&regmatch, str, col);
8284 if (match)
8285 end = regmatch.startp[0];
8286 else
8287 end = str + STRLEN(str);
8288 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
8289 && *str != NUL && match && end < regmatch.endp[0]))
8290 {
8291 if (list_append_string(rettv->vval.v_list, str,
8292 (int)(end - str)) == FAIL)
8293 break;
8294 }
8295 if (!match)
8296 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01008297 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008298 if (regmatch.endp[0] > str)
8299 col = 0;
8300 else
Bram Moolenaar13505972019-01-24 15:04:48 +01008301 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008303 str = regmatch.endp[0];
8304 }
8305
8306 vim_regfree(regmatch.regprog);
8307 }
8308
8309 p_cpo = save_cpo;
8310}
8311
8312#ifdef FEAT_FLOAT
8313/*
8314 * "sqrt()" function
8315 */
8316 static void
8317f_sqrt(typval_T *argvars, typval_T *rettv)
8318{
8319 float_T f = 0.0;
8320
8321 rettv->v_type = VAR_FLOAT;
8322 if (get_float_arg(argvars, &f) == OK)
8323 rettv->vval.v_float = sqrt(f);
8324 else
8325 rettv->vval.v_float = 0.0;
8326}
8327
8328/*
8329 * "str2float()" function
8330 */
8331 static void
8332f_str2float(typval_T *argvars, typval_T *rettv)
8333{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008334 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008335 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008336
Bram Moolenaar08243d22017-01-10 16:12:29 +01008337 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008338 p = skipwhite(p + 1);
8339 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01008340 if (isneg)
8341 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 rettv->v_type = VAR_FLOAT;
8343}
8344#endif
8345
8346/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02008347 * "str2list()" function
8348 */
8349 static void
8350f_str2list(typval_T *argvars, typval_T *rettv)
8351{
8352 char_u *p;
8353 int utf8 = FALSE;
8354
8355 if (rettv_list_alloc(rettv) == FAIL)
8356 return;
8357
8358 if (argvars[1].v_type != VAR_UNKNOWN)
8359 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8360
8361 p = tv_get_string(&argvars[0]);
8362
8363 if (has_mbyte || utf8)
8364 {
8365 int (*ptr2len)(char_u *);
8366 int (*ptr2char)(char_u *);
8367
8368 if (utf8 || enc_utf8)
8369 {
8370 ptr2len = utf_ptr2len;
8371 ptr2char = utf_ptr2char;
8372 }
8373 else
8374 {
8375 ptr2len = mb_ptr2len;
8376 ptr2char = mb_ptr2char;
8377 }
8378
8379 for ( ; *p != NUL; p += (*ptr2len)(p))
8380 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8381 }
8382 else
8383 for ( ; *p != NUL; ++p)
8384 list_append_number(rettv->vval.v_list, *p);
8385}
8386
8387/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 * "str2nr()" function
8389 */
8390 static void
8391f_str2nr(typval_T *argvars, typval_T *rettv)
8392{
8393 int base = 10;
8394 char_u *p;
8395 varnumber_T n;
8396 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008397 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398
8399 if (argvars[1].v_type != VAR_UNKNOWN)
8400 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008401 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 if (base != 2 && base != 8 && base != 10 && base != 16)
8403 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008404 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008405 return;
8406 }
8407 }
8408
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008409 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008410 isneg = (*p == '-');
8411 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008412 p = skipwhite(p + 1);
8413 switch (base)
8414 {
8415 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
8416 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
8417 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
8418 default: what = 0;
8419 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008420 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8421 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008422 if (isneg)
8423 rettv->vval.v_number = -n;
8424 else
8425 rettv->vval.v_number = n;
8426
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008427}
8428
8429#ifdef HAVE_STRFTIME
8430/*
8431 * "strftime({format}[, {time}])" function
8432 */
8433 static void
8434f_strftime(typval_T *argvars, typval_T *rettv)
8435{
8436 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02008437 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008438 struct tm *curtime;
8439 time_t seconds;
8440 char_u *p;
8441
8442 rettv->v_type = VAR_STRING;
8443
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008444 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008445 if (argvars[1].v_type == VAR_UNKNOWN)
8446 seconds = time(NULL);
8447 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008448 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02008449 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008450 /* MSVC returns NULL for an invalid value of seconds. */
8451 if (curtime == NULL)
8452 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
8453 else
8454 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008455 vimconv_T conv;
8456 char_u *enc;
8457
8458 conv.vc_type = CONV_NONE;
8459 enc = enc_locale();
8460 convert_setup(&conv, p_enc, enc);
8461 if (conv.vc_type != CONV_NONE)
8462 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463 if (p != NULL)
8464 (void)strftime((char *)result_buf, sizeof(result_buf),
8465 (char *)p, curtime);
8466 else
8467 result_buf[0] = NUL;
8468
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008469 if (conv.vc_type != CONV_NONE)
8470 vim_free(p);
8471 convert_setup(&conv, enc, p_enc);
8472 if (conv.vc_type != CONV_NONE)
8473 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
8474 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008475 rettv->vval.v_string = vim_strsave(result_buf);
8476
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008477 /* Release conversion descriptors */
8478 convert_setup(&conv, NULL, NULL);
8479 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480 }
8481}
8482#endif
8483
8484/*
8485 * "strgetchar()" function
8486 */
8487 static void
8488f_strgetchar(typval_T *argvars, typval_T *rettv)
8489{
8490 char_u *str;
8491 int len;
8492 int error = FALSE;
8493 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008494 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008495
8496 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008497 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008498 if (str == NULL)
8499 return;
8500 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008501 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008502 if (error)
8503 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008504
Bram Moolenaar13505972019-01-24 15:04:48 +01008505 while (charidx >= 0 && byteidx < len)
8506 {
8507 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008508 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008509 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8510 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008511 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008512 --charidx;
8513 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008514 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008515}
8516
8517/*
8518 * "stridx()" function
8519 */
8520 static void
8521f_stridx(typval_T *argvars, typval_T *rettv)
8522{
8523 char_u buf[NUMBUFLEN];
8524 char_u *needle;
8525 char_u *haystack;
8526 char_u *save_haystack;
8527 char_u *pos;
8528 int start_idx;
8529
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008530 needle = tv_get_string_chk(&argvars[1]);
8531 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008532 rettv->vval.v_number = -1;
8533 if (needle == NULL || haystack == NULL)
8534 return; /* type error; errmsg already given */
8535
8536 if (argvars[2].v_type != VAR_UNKNOWN)
8537 {
8538 int error = FALSE;
8539
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008540 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008541 if (error || start_idx >= (int)STRLEN(haystack))
8542 return;
8543 if (start_idx >= 0)
8544 haystack += start_idx;
8545 }
8546
8547 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8548 if (pos != NULL)
8549 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8550}
8551
8552/*
8553 * "string()" function
8554 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008555 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008556f_string(typval_T *argvars, typval_T *rettv)
8557{
8558 char_u *tofree;
8559 char_u numbuf[NUMBUFLEN];
8560
8561 rettv->v_type = VAR_STRING;
8562 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8563 get_copyID());
8564 /* Make a copy if we have a value but it's not in allocated memory. */
8565 if (rettv->vval.v_string != NULL && tofree == NULL)
8566 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8567}
8568
8569/*
8570 * "strlen()" function
8571 */
8572 static void
8573f_strlen(typval_T *argvars, typval_T *rettv)
8574{
8575 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008576 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008577}
8578
8579/*
8580 * "strchars()" function
8581 */
8582 static void
8583f_strchars(typval_T *argvars, typval_T *rettv)
8584{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008585 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008586 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008587 varnumber_T len = 0;
8588 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008589
8590 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008591 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008592 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008593 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008594 else
8595 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8597 while (*s != NUL)
8598 {
8599 func_mb_ptr2char_adv(&s);
8600 ++len;
8601 }
8602 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008603 }
8604}
8605
8606/*
8607 * "strdisplaywidth()" function
8608 */
8609 static void
8610f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8611{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008612 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008613 int col = 0;
8614
8615 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008616 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008617
8618 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8619}
8620
8621/*
8622 * "strwidth()" function
8623 */
8624 static void
8625f_strwidth(typval_T *argvars, typval_T *rettv)
8626{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008627 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008628
Bram Moolenaar13505972019-01-24 15:04:48 +01008629 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008630}
8631
8632/*
8633 * "strcharpart()" function
8634 */
8635 static void
8636f_strcharpart(typval_T *argvars, typval_T *rettv)
8637{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008638 char_u *p;
8639 int nchar;
8640 int nbyte = 0;
8641 int charlen;
8642 int len = 0;
8643 int slen;
8644 int error = FALSE;
8645
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008646 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008647 slen = (int)STRLEN(p);
8648
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008649 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008650 if (!error)
8651 {
8652 if (nchar > 0)
8653 while (nchar > 0 && nbyte < slen)
8654 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008655 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008656 --nchar;
8657 }
8658 else
8659 nbyte = nchar;
8660 if (argvars[2].v_type != VAR_UNKNOWN)
8661 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008662 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008663 while (charlen > 0 && nbyte + len < slen)
8664 {
8665 int off = nbyte + len;
8666
8667 if (off < 0)
8668 len += 1;
8669 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008670 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008671 --charlen;
8672 }
8673 }
8674 else
8675 len = slen - nbyte; /* default: all bytes that are available. */
8676 }
8677
8678 /*
8679 * Only return the overlap between the specified part and the actual
8680 * string.
8681 */
8682 if (nbyte < 0)
8683 {
8684 len += nbyte;
8685 nbyte = 0;
8686 }
8687 else if (nbyte > slen)
8688 nbyte = slen;
8689 if (len < 0)
8690 len = 0;
8691 else if (nbyte + len > slen)
8692 len = slen - nbyte;
8693
8694 rettv->v_type = VAR_STRING;
8695 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008696}
8697
8698/*
8699 * "strpart()" function
8700 */
8701 static void
8702f_strpart(typval_T *argvars, typval_T *rettv)
8703{
8704 char_u *p;
8705 int n;
8706 int len;
8707 int slen;
8708 int error = FALSE;
8709
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008710 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008711 slen = (int)STRLEN(p);
8712
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008713 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008714 if (error)
8715 len = 0;
8716 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008717 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008718 else
8719 len = slen - n; /* default len: all bytes that are available. */
8720
8721 /*
8722 * Only return the overlap between the specified part and the actual
8723 * string.
8724 */
8725 if (n < 0)
8726 {
8727 len += n;
8728 n = 0;
8729 }
8730 else if (n > slen)
8731 n = slen;
8732 if (len < 0)
8733 len = 0;
8734 else if (n + len > slen)
8735 len = slen - n;
8736
8737 rettv->v_type = VAR_STRING;
8738 rettv->vval.v_string = vim_strnsave(p + n, len);
8739}
8740
8741/*
8742 * "strridx()" function
8743 */
8744 static void
8745f_strridx(typval_T *argvars, typval_T *rettv)
8746{
8747 char_u buf[NUMBUFLEN];
8748 char_u *needle;
8749 char_u *haystack;
8750 char_u *rest;
8751 char_u *lastmatch = NULL;
8752 int haystack_len, end_idx;
8753
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008754 needle = tv_get_string_chk(&argvars[1]);
8755 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008756
8757 rettv->vval.v_number = -1;
8758 if (needle == NULL || haystack == NULL)
8759 return; /* type error; errmsg already given */
8760
8761 haystack_len = (int)STRLEN(haystack);
8762 if (argvars[2].v_type != VAR_UNKNOWN)
8763 {
8764 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008765 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008766 if (end_idx < 0)
8767 return; /* can never find a match */
8768 }
8769 else
8770 end_idx = haystack_len;
8771
8772 if (*needle == NUL)
8773 {
8774 /* Empty string matches past the end. */
8775 lastmatch = haystack + end_idx;
8776 }
8777 else
8778 {
8779 for (rest = haystack; *rest != '\0'; ++rest)
8780 {
8781 rest = (char_u *)strstr((char *)rest, (char *)needle);
8782 if (rest == NULL || rest > haystack + end_idx)
8783 break;
8784 lastmatch = rest;
8785 }
8786 }
8787
8788 if (lastmatch == NULL)
8789 rettv->vval.v_number = -1;
8790 else
8791 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8792}
8793
8794/*
8795 * "strtrans()" function
8796 */
8797 static void
8798f_strtrans(typval_T *argvars, typval_T *rettv)
8799{
8800 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008801 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008802}
8803
8804/*
8805 * "submatch()" function
8806 */
8807 static void
8808f_submatch(typval_T *argvars, typval_T *rettv)
8809{
8810 int error = FALSE;
8811 int no;
8812 int retList = 0;
8813
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008814 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008815 if (error)
8816 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008817 if (no < 0 || no >= NSUBEXP)
8818 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008819 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008820 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008821 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008822 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008823 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008824 if (error)
8825 return;
8826
8827 if (retList == 0)
8828 {
8829 rettv->v_type = VAR_STRING;
8830 rettv->vval.v_string = reg_submatch(no);
8831 }
8832 else
8833 {
8834 rettv->v_type = VAR_LIST;
8835 rettv->vval.v_list = reg_submatch_list(no);
8836 }
8837}
8838
8839/*
8840 * "substitute()" function
8841 */
8842 static void
8843f_substitute(typval_T *argvars, typval_T *rettv)
8844{
8845 char_u patbuf[NUMBUFLEN];
8846 char_u subbuf[NUMBUFLEN];
8847 char_u flagsbuf[NUMBUFLEN];
8848
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008849 char_u *str = tv_get_string_chk(&argvars[0]);
8850 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008851 char_u *sub = NULL;
8852 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008853 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008855 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8856 expr = &argvars[2];
8857 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008858 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008859
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008860 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008861 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8862 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008863 rettv->vval.v_string = NULL;
8864 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008865 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008866}
8867
8868/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008869 * "swapinfo(swap_filename)" function
8870 */
8871 static void
8872f_swapinfo(typval_T *argvars, typval_T *rettv)
8873{
8874 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008875 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008876}
8877
8878/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008879 * "swapname(expr)" function
8880 */
8881 static void
8882f_swapname(typval_T *argvars, typval_T *rettv)
8883{
8884 buf_T *buf;
8885
8886 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008887 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008888 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8889 || buf->b_ml.ml_mfp->mf_fname == NULL)
8890 rettv->vval.v_string = NULL;
8891 else
8892 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8893}
8894
8895/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008896 * "synID(lnum, col, trans)" function
8897 */
8898 static void
8899f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8900{
8901 int id = 0;
8902#ifdef FEAT_SYN_HL
8903 linenr_T lnum;
8904 colnr_T col;
8905 int trans;
8906 int transerr = FALSE;
8907
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008908 lnum = tv_get_lnum(argvars); /* -1 on type error */
8909 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
8910 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008911
8912 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8913 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8914 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8915#endif
8916
8917 rettv->vval.v_number = id;
8918}
8919
8920/*
8921 * "synIDattr(id, what [, mode])" function
8922 */
8923 static void
8924f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8925{
8926 char_u *p = NULL;
8927#ifdef FEAT_SYN_HL
8928 int id;
8929 char_u *what;
8930 char_u *mode;
8931 char_u modebuf[NUMBUFLEN];
8932 int modec;
8933
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008934 id = (int)tv_get_number(&argvars[0]);
8935 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008936 if (argvars[2].v_type != VAR_UNKNOWN)
8937 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008938 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008939 modec = TOLOWER_ASC(mode[0]);
8940 if (modec != 't' && modec != 'c' && modec != 'g')
8941 modec = 0; /* replace invalid with current */
8942 }
8943 else
8944 {
8945#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8946 if (USE_24BIT)
8947 modec = 'g';
8948 else
8949#endif
8950 if (t_colors > 1)
8951 modec = 'c';
8952 else
8953 modec = 't';
8954 }
8955
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008956 switch (TOLOWER_ASC(what[0]))
8957 {
8958 case 'b':
8959 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
8960 p = highlight_color(id, what, modec);
8961 else /* bold */
8962 p = highlight_has_attr(id, HL_BOLD, modec);
8963 break;
8964
8965 case 'f': /* fg[#] or font */
8966 p = highlight_color(id, what, modec);
8967 break;
8968
8969 case 'i':
8970 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
8971 p = highlight_has_attr(id, HL_INVERSE, modec);
8972 else /* italic */
8973 p = highlight_has_attr(id, HL_ITALIC, modec);
8974 break;
8975
8976 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008977 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008978 break;
8979
8980 case 'r': /* reverse */
8981 p = highlight_has_attr(id, HL_INVERSE, modec);
8982 break;
8983
8984 case 's':
8985 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
8986 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008987 /* strikeout */
8988 else if (TOLOWER_ASC(what[1]) == 't' &&
8989 TOLOWER_ASC(what[2]) == 'r')
8990 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008991 else /* standout */
8992 p = highlight_has_attr(id, HL_STANDOUT, modec);
8993 break;
8994
8995 case 'u':
8996 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
8997 /* underline */
8998 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8999 else
9000 /* undercurl */
9001 p = highlight_has_attr(id, HL_UNDERCURL, modec);
9002 break;
9003 }
9004
9005 if (p != NULL)
9006 p = vim_strsave(p);
9007#endif
9008 rettv->v_type = VAR_STRING;
9009 rettv->vval.v_string = p;
9010}
9011
9012/*
9013 * "synIDtrans(id)" function
9014 */
9015 static void
9016f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
9017{
9018 int id;
9019
9020#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009021 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009022
9023 if (id > 0)
9024 id = syn_get_final_id(id);
9025 else
9026#endif
9027 id = 0;
9028
9029 rettv->vval.v_number = id;
9030}
9031
9032/*
9033 * "synconcealed(lnum, col)" function
9034 */
9035 static void
9036f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
9037{
9038#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9039 linenr_T lnum;
9040 colnr_T col;
9041 int syntax_flags = 0;
9042 int cchar;
9043 int matchid = 0;
9044 char_u str[NUMBUFLEN];
9045#endif
9046
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009047 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009048
9049#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009050 lnum = tv_get_lnum(argvars); /* -1 on type error */
9051 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009052
9053 vim_memset(str, NUL, sizeof(str));
9054
9055 if (rettv_list_alloc(rettv) != FAIL)
9056 {
9057 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9058 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9059 && curwin->w_p_cole > 0)
9060 {
9061 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
9062 syntax_flags = get_syntax_info(&matchid);
9063
9064 /* get the conceal character */
9065 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
9066 {
9067 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02009068 if (cchar == NUL && curwin->w_p_cole == 1)
9069 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009070 if (cchar != NUL)
9071 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009072 if (has_mbyte)
9073 (*mb_char2bytes)(cchar, str);
9074 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009075 str[0] = cchar;
9076 }
9077 }
9078 }
9079
9080 list_append_number(rettv->vval.v_list,
9081 (syntax_flags & HL_CONCEAL) != 0);
9082 /* -1 to auto-determine strlen */
9083 list_append_string(rettv->vval.v_list, str, -1);
9084 list_append_number(rettv->vval.v_list, matchid);
9085 }
9086#endif
9087}
9088
9089/*
9090 * "synstack(lnum, col)" function
9091 */
9092 static void
9093f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
9094{
9095#ifdef FEAT_SYN_HL
9096 linenr_T lnum;
9097 colnr_T col;
9098 int i;
9099 int id;
9100#endif
9101
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009102 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009103
9104#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009105 lnum = tv_get_lnum(argvars); /* -1 on type error */
9106 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009107
9108 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9109 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9110 && rettv_list_alloc(rettv) != FAIL)
9111 {
9112 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
9113 for (i = 0; ; ++i)
9114 {
9115 id = syn_get_stack_item(i);
9116 if (id < 0)
9117 break;
9118 if (list_append_number(rettv->vval.v_list, id) == FAIL)
9119 break;
9120 }
9121 }
9122#endif
9123}
9124
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009125/*
9126 * "tabpagebuflist()" function
9127 */
9128 static void
9129f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9130{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009131 tabpage_T *tp;
9132 win_T *wp = NULL;
9133
9134 if (argvars[0].v_type == VAR_UNKNOWN)
9135 wp = firstwin;
9136 else
9137 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009138 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009139 if (tp != NULL)
9140 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9141 }
9142 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
9143 {
9144 for (; wp != NULL; wp = wp->w_next)
9145 if (list_append_number(rettv->vval.v_list,
9146 wp->w_buffer->b_fnum) == FAIL)
9147 break;
9148 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009149}
9150
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009151/*
9152 * "tabpagenr()" function
9153 */
9154 static void
9155f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
9156{
9157 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009158 char_u *arg;
9159
9160 if (argvars[0].v_type != VAR_UNKNOWN)
9161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009162 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009163 nr = 0;
9164 if (arg != NULL)
9165 {
9166 if (STRCMP(arg, "$") == 0)
9167 nr = tabpage_index(NULL) - 1;
9168 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009169 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009170 }
9171 }
9172 else
9173 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009174 rettv->vval.v_number = nr;
9175}
9176
9177
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009178/*
9179 * Common code for tabpagewinnr() and winnr().
9180 */
9181 static int
9182get_winnr(tabpage_T *tp, typval_T *argvar)
9183{
9184 win_T *twin;
9185 int nr = 1;
9186 win_T *wp;
9187 char_u *arg;
9188
9189 twin = (tp == curtab) ? curwin : tp->tp_curwin;
9190 if (argvar->v_type != VAR_UNKNOWN)
9191 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +02009192 int invalid_arg = FALSE;
9193
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009194 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009195 if (arg == NULL)
9196 nr = 0; /* type error; errmsg already given */
9197 else if (STRCMP(arg, "$") == 0)
9198 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
9199 else if (STRCMP(arg, "#") == 0)
9200 {
9201 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
9202 if (twin == NULL)
9203 nr = 0;
9204 }
9205 else
9206 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +02009207 long count;
9208 char_u *endp;
9209
9210 // Extract the window count (if specified). e.g. winnr('3j')
9211 count = strtol((char *)arg, (char **)&endp, 10);
9212 if (count <= 0)
9213 count = 1; // if count is not specified, default to 1
9214 if (endp != NULL && *endp != '\0')
9215 {
9216 if (STRCMP(endp, "j") == 0)
9217 twin = win_vert_neighbor(tp, twin, FALSE, count);
9218 else if (STRCMP(endp, "k") == 0)
9219 twin = win_vert_neighbor(tp, twin, TRUE, count);
9220 else if (STRCMP(endp, "h") == 0)
9221 twin = win_horz_neighbor(tp, twin, TRUE, count);
9222 else if (STRCMP(endp, "l") == 0)
9223 twin = win_horz_neighbor(tp, twin, FALSE, count);
9224 else
9225 invalid_arg = TRUE;
9226 }
9227 else
9228 invalid_arg = TRUE;
9229 }
9230
9231 if (invalid_arg)
9232 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009233 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009234 nr = 0;
9235 }
9236 }
9237
9238 if (nr > 0)
9239 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9240 wp != twin; wp = wp->w_next)
9241 {
9242 if (wp == NULL)
9243 {
9244 /* didn't find it in this tabpage */
9245 nr = 0;
9246 break;
9247 }
9248 ++nr;
9249 }
9250 return nr;
9251}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009252
9253/*
9254 * "tabpagewinnr()" function
9255 */
9256 static void
9257f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
9258{
9259 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009260 tabpage_T *tp;
9261
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009262 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009263 if (tp == NULL)
9264 nr = 0;
9265 else
9266 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009267 rettv->vval.v_number = nr;
9268}
9269
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009270/*
9271 * "tagfiles()" function
9272 */
9273 static void
9274f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
9275{
9276 char_u *fname;
9277 tagname_T tn;
9278 int first;
9279
9280 if (rettv_list_alloc(rettv) == FAIL)
9281 return;
9282 fname = alloc(MAXPATHL);
9283 if (fname == NULL)
9284 return;
9285
9286 for (first = TRUE; ; first = FALSE)
9287 if (get_tagfname(&tn, first, fname) == FAIL
9288 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
9289 break;
9290 tagname_free(&tn);
9291 vim_free(fname);
9292}
9293
9294/*
9295 * "taglist()" function
9296 */
9297 static void
9298f_taglist(typval_T *argvars, typval_T *rettv)
9299{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009300 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009301 char_u *tag_pattern;
9302
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009303 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009304
9305 rettv->vval.v_number = FALSE;
9306 if (*tag_pattern == NUL)
9307 return;
9308
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009309 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009310 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009311 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009312 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009313}
9314
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009315#ifdef FEAT_FLOAT
9316/*
9317 * "tan()" function
9318 */
9319 static void
9320f_tan(typval_T *argvars, typval_T *rettv)
9321{
9322 float_T f = 0.0;
9323
9324 rettv->v_type = VAR_FLOAT;
9325 if (get_float_arg(argvars, &f) == OK)
9326 rettv->vval.v_float = tan(f);
9327 else
9328 rettv->vval.v_float = 0.0;
9329}
9330
9331/*
9332 * "tanh()" function
9333 */
9334 static void
9335f_tanh(typval_T *argvars, typval_T *rettv)
9336{
9337 float_T f = 0.0;
9338
9339 rettv->v_type = VAR_FLOAT;
9340 if (get_float_arg(argvars, &f) == OK)
9341 rettv->vval.v_float = tanh(f);
9342 else
9343 rettv->vval.v_float = 0.0;
9344}
9345#endif
9346
9347/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009348 * "tolower(string)" function
9349 */
9350 static void
9351f_tolower(typval_T *argvars, typval_T *rettv)
9352{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009353 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009354 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009355}
9356
9357/*
9358 * "toupper(string)" function
9359 */
9360 static void
9361f_toupper(typval_T *argvars, typval_T *rettv)
9362{
9363 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009364 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009365}
9366
9367/*
9368 * "tr(string, fromstr, tostr)" function
9369 */
9370 static void
9371f_tr(typval_T *argvars, typval_T *rettv)
9372{
9373 char_u *in_str;
9374 char_u *fromstr;
9375 char_u *tostr;
9376 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009377 int inlen;
9378 int fromlen;
9379 int tolen;
9380 int idx;
9381 char_u *cpstr;
9382 int cplen;
9383 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009384 char_u buf[NUMBUFLEN];
9385 char_u buf2[NUMBUFLEN];
9386 garray_T ga;
9387
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009388 in_str = tv_get_string(&argvars[0]);
9389 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
9390 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009391
9392 /* Default return value: empty string. */
9393 rettv->v_type = VAR_STRING;
9394 rettv->vval.v_string = NULL;
9395 if (fromstr == NULL || tostr == NULL)
9396 return; /* type error; errmsg already given */
9397 ga_init2(&ga, (int)sizeof(char), 80);
9398
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009399 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009400 /* not multi-byte: fromstr and tostr must be the same length */
9401 if (STRLEN(fromstr) != STRLEN(tostr))
9402 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009403error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009404 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009405 ga_clear(&ga);
9406 return;
9407 }
9408
9409 /* fromstr and tostr have to contain the same number of chars */
9410 while (*in_str != NUL)
9411 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009412 if (has_mbyte)
9413 {
9414 inlen = (*mb_ptr2len)(in_str);
9415 cpstr = in_str;
9416 cplen = inlen;
9417 idx = 0;
9418 for (p = fromstr; *p != NUL; p += fromlen)
9419 {
9420 fromlen = (*mb_ptr2len)(p);
9421 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
9422 {
9423 for (p = tostr; *p != NUL; p += tolen)
9424 {
9425 tolen = (*mb_ptr2len)(p);
9426 if (idx-- == 0)
9427 {
9428 cplen = tolen;
9429 cpstr = p;
9430 break;
9431 }
9432 }
9433 if (*p == NUL) /* tostr is shorter than fromstr */
9434 goto error;
9435 break;
9436 }
9437 ++idx;
9438 }
9439
9440 if (first && cpstr == in_str)
9441 {
9442 /* Check that fromstr and tostr have the same number of
9443 * (multi-byte) characters. Done only once when a character
9444 * of in_str doesn't appear in fromstr. */
9445 first = FALSE;
9446 for (p = tostr; *p != NUL; p += tolen)
9447 {
9448 tolen = (*mb_ptr2len)(p);
9449 --idx;
9450 }
9451 if (idx != 0)
9452 goto error;
9453 }
9454
9455 (void)ga_grow(&ga, cplen);
9456 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
9457 ga.ga_len += cplen;
9458
9459 in_str += inlen;
9460 }
9461 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009462 {
9463 /* When not using multi-byte chars we can do it faster. */
9464 p = vim_strchr(fromstr, *in_str);
9465 if (p != NULL)
9466 ga_append(&ga, tostr[p - fromstr]);
9467 else
9468 ga_append(&ga, *in_str);
9469 ++in_str;
9470 }
9471 }
9472
9473 /* add a terminating NUL */
9474 (void)ga_grow(&ga, 1);
9475 ga_append(&ga, NUL);
9476
9477 rettv->vval.v_string = ga.ga_data;
9478}
9479
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009480/*
9481 * "trim({expr})" function
9482 */
9483 static void
9484f_trim(typval_T *argvars, typval_T *rettv)
9485{
9486 char_u buf1[NUMBUFLEN];
9487 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009488 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009489 char_u *mask = NULL;
9490 char_u *tail;
9491 char_u *prev;
9492 char_u *p;
9493 int c1;
9494
9495 rettv->v_type = VAR_STRING;
9496 if (head == NULL)
9497 {
9498 rettv->vval.v_string = NULL;
9499 return;
9500 }
9501
9502 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009503 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009504
9505 while (*head != NUL)
9506 {
9507 c1 = PTR2CHAR(head);
9508 if (mask == NULL)
9509 {
9510 if (c1 > ' ' && c1 != 0xa0)
9511 break;
9512 }
9513 else
9514 {
9515 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9516 if (c1 == PTR2CHAR(p))
9517 break;
9518 if (*p == NUL)
9519 break;
9520 }
9521 MB_PTR_ADV(head);
9522 }
9523
9524 for (tail = head + STRLEN(head); tail > head; tail = prev)
9525 {
9526 prev = tail;
9527 MB_PTR_BACK(head, prev);
9528 c1 = PTR2CHAR(prev);
9529 if (mask == NULL)
9530 {
9531 if (c1 > ' ' && c1 != 0xa0)
9532 break;
9533 }
9534 else
9535 {
9536 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9537 if (c1 == PTR2CHAR(p))
9538 break;
9539 if (*p == NUL)
9540 break;
9541 }
9542 }
9543 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
9544}
9545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009546#ifdef FEAT_FLOAT
9547/*
9548 * "trunc({float})" function
9549 */
9550 static void
9551f_trunc(typval_T *argvars, typval_T *rettv)
9552{
9553 float_T f = 0.0;
9554
9555 rettv->v_type = VAR_FLOAT;
9556 if (get_float_arg(argvars, &f) == OK)
9557 /* trunc() is not in C90, use floor() or ceil() instead. */
9558 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
9559 else
9560 rettv->vval.v_float = 0.0;
9561}
9562#endif
9563
9564/*
9565 * "type(expr)" function
9566 */
9567 static void
9568f_type(typval_T *argvars, typval_T *rettv)
9569{
9570 int n = -1;
9571
9572 switch (argvars[0].v_type)
9573 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02009574 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
9575 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009576 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02009577 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
9578 case VAR_LIST: n = VAR_TYPE_LIST; break;
9579 case VAR_DICT: n = VAR_TYPE_DICT; break;
9580 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009581 case VAR_SPECIAL:
9582 if (argvars[0].vval.v_number == VVAL_FALSE
9583 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02009584 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009585 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02009586 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009587 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02009588 case VAR_JOB: n = VAR_TYPE_JOB; break;
9589 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009590 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009591 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01009592 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009593 n = -1;
9594 break;
9595 }
9596 rettv->vval.v_number = n;
9597}
9598
9599/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009600 * "virtcol(string)" function
9601 */
9602 static void
9603f_virtcol(typval_T *argvars, typval_T *rettv)
9604{
9605 colnr_T vcol = 0;
9606 pos_T *fp;
9607 int fnum = curbuf->b_fnum;
9608
9609 fp = var2fpos(&argvars[0], FALSE, &fnum);
9610 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9611 && fnum == curbuf->b_fnum)
9612 {
9613 getvvcol(curwin, fp, NULL, NULL, &vcol);
9614 ++vcol;
9615 }
9616
9617 rettv->vval.v_number = vcol;
9618}
9619
9620/*
9621 * "visualmode()" function
9622 */
9623 static void
9624f_visualmode(typval_T *argvars, typval_T *rettv)
9625{
9626 char_u str[2];
9627
9628 rettv->v_type = VAR_STRING;
9629 str[0] = curbuf->b_visual_mode_eval;
9630 str[1] = NUL;
9631 rettv->vval.v_string = vim_strsave(str);
9632
9633 /* A non-zero number or non-empty string argument: reset mode. */
9634 if (non_zero_arg(&argvars[0]))
9635 curbuf->b_visual_mode_eval = NUL;
9636}
9637
9638/*
9639 * "wildmenumode()" function
9640 */
9641 static void
9642f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9643{
9644#ifdef FEAT_WILDMENU
9645 if (wild_menu_showing)
9646 rettv->vval.v_number = 1;
9647#endif
9648}
9649
9650/*
9651 * "winbufnr(nr)" function
9652 */
9653 static void
9654f_winbufnr(typval_T *argvars, typval_T *rettv)
9655{
9656 win_T *wp;
9657
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02009658 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009659 if (wp == NULL)
9660 rettv->vval.v_number = -1;
9661 else
9662 rettv->vval.v_number = wp->w_buffer->b_fnum;
9663}
9664
9665/*
9666 * "wincol()" function
9667 */
9668 static void
9669f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
9670{
9671 validate_cursor();
9672 rettv->vval.v_number = curwin->w_wcol + 1;
9673}
9674
9675/*
9676 * "winheight(nr)" function
9677 */
9678 static void
9679f_winheight(typval_T *argvars, typval_T *rettv)
9680{
9681 win_T *wp;
9682
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02009683 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009684 if (wp == NULL)
9685 rettv->vval.v_number = -1;
9686 else
9687 rettv->vval.v_number = wp->w_height;
9688}
9689
9690/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02009691 * "winlayout()" function
9692 */
9693 static void
9694f_winlayout(typval_T *argvars, typval_T *rettv)
9695{
9696 tabpage_T *tp;
9697
9698 if (rettv_list_alloc(rettv) != OK)
9699 return;
9700
9701 if (argvars[0].v_type == VAR_UNKNOWN)
9702 tp = curtab;
9703 else
9704 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009705 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02009706 if (tp == NULL)
9707 return;
9708 }
9709
9710 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
9711}
9712
9713/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009714 * "winline()" function
9715 */
9716 static void
9717f_winline(typval_T *argvars UNUSED, typval_T *rettv)
9718{
9719 validate_cursor();
9720 rettv->vval.v_number = curwin->w_wrow + 1;
9721}
9722
9723/*
9724 * "winnr()" function
9725 */
9726 static void
9727f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
9728{
9729 int nr = 1;
9730
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009731 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009732 rettv->vval.v_number = nr;
9733}
9734
9735/*
9736 * "winrestcmd()" function
9737 */
9738 static void
9739f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
9740{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009741 win_T *wp;
9742 int winnr = 1;
9743 garray_T ga;
9744 char_u buf[50];
9745
9746 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +02009747 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009748 {
9749 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
9750 ga_concat(&ga, buf);
9751 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
9752 ga_concat(&ga, buf);
9753 ++winnr;
9754 }
9755 ga_append(&ga, NUL);
9756
9757 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009758 rettv->v_type = VAR_STRING;
9759}
9760
9761/*
9762 * "winrestview()" function
9763 */
9764 static void
9765f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
9766{
9767 dict_T *dict;
9768
9769 if (argvars[0].v_type != VAR_DICT
9770 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009771 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009772 else
9773 {
9774 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009775 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009776 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009777 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009778 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009779 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009780 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
9781 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009782 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009783 curwin->w_set_curswant = FALSE;
9784 }
9785
9786 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009787 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009788#ifdef FEAT_DIFF
9789 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009790 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009791#endif
9792 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009793 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009794 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009795 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009796
9797 check_cursor();
9798 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +02009799 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009800 changed_window_setting();
9801
9802 if (curwin->w_topline <= 0)
9803 curwin->w_topline = 1;
9804 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
9805 curwin->w_topline = curbuf->b_ml.ml_line_count;
9806#ifdef FEAT_DIFF
9807 check_topfill(curwin, TRUE);
9808#endif
9809 }
9810}
9811
9812/*
9813 * "winsaveview()" function
9814 */
9815 static void
9816f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
9817{
9818 dict_T *dict;
9819
9820 if (rettv_dict_alloc(rettv) == FAIL)
9821 return;
9822 dict = rettv->vval.v_dict;
9823
Bram Moolenaare0be1672018-07-08 16:50:37 +02009824 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
9825 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02009826 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009827 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +02009828 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009829
Bram Moolenaare0be1672018-07-08 16:50:37 +02009830 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009831#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +02009832 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009833#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02009834 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
9835 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009836}
9837
9838/*
9839 * "winwidth(nr)" function
9840 */
9841 static void
9842f_winwidth(typval_T *argvars, typval_T *rettv)
9843{
9844 win_T *wp;
9845
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02009846 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009847 if (wp == NULL)
9848 rettv->vval.v_number = -1;
9849 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009850 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009851}
9852
9853/*
9854 * "wordcount()" function
9855 */
9856 static void
9857f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
9858{
9859 if (rettv_dict_alloc(rettv) == FAIL)
9860 return;
9861 cursor_pos_info(rettv->vval.v_dict);
9862}
9863
9864/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009865 * "xor(expr, expr)" function
9866 */
9867 static void
9868f_xor(typval_T *argvars, typval_T *rettv)
9869{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009870 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9871 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009872}
9873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009874#endif /* FEAT_EVAL */