blob: b352ea9f8998d653f6fc7e98151dcf4b48271938 [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);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020032#ifdef FEAT_FLOAT
33static void f_asin(typval_T *argvars, typval_T *rettv);
34static void f_atan(typval_T *argvars, typval_T *rettv);
35static void f_atan2(typval_T *argvars, typval_T *rettv);
36#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010037#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020038static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010039static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010040# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010041static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_byte2line(typval_T *argvars, typval_T *rettv);
45static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
46static void f_byteidx(typval_T *argvars, typval_T *rettv);
47static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
48static void f_call(typval_T *argvars, typval_T *rettv);
49#ifdef FEAT_FLOAT
50static void f_ceil(typval_T *argvars, typval_T *rettv);
51#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_changenr(typval_T *argvars, typval_T *rettv);
53static void f_char2nr(typval_T *argvars, typval_T *rettv);
54static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020056static void f_confirm(typval_T *argvars, typval_T *rettv);
57static void f_copy(typval_T *argvars, typval_T *rettv);
58#ifdef FEAT_FLOAT
59static void f_cos(typval_T *argvars, typval_T *rettv);
60static void f_cosh(typval_T *argvars, typval_T *rettv);
61#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010063#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020064static void f_debugbreak(typval_T *argvars, typval_T *rettv);
65#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020068static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020069static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_escape(typval_T *argvars, typval_T *rettv);
71static void f_eval(typval_T *argvars, typval_T *rettv);
72static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020074static void f_exists(typval_T *argvars, typval_T *rettv);
75#ifdef FEAT_FLOAT
76static void f_exp(typval_T *argvars, typval_T *rettv);
77#endif
78static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020079static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020081#ifdef FEAT_FLOAT
82static void f_float2nr(typval_T *argvars, typval_T *rettv);
83static void f_floor(typval_T *argvars, typval_T *rettv);
84static void f_fmod(typval_T *argvars, typval_T *rettv);
85#endif
86static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020087static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020088static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_function(typval_T *argvars, typval_T *rettv);
90static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
91static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010092static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getchar(typval_T *argvars, typval_T *rettv);
94static void f_getcharmod(typval_T *argvars, typval_T *rettv);
95static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020097static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020098static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010099static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_getpid(typval_T *argvars, typval_T *rettv);
101static void f_getcurpos(typval_T *argvars, typval_T *rettv);
102static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_getreg(typval_T *argvars, typval_T *rettv);
104static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100105static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
108static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200109static void f_hlID(typval_T *argvars, typval_T *rettv);
110static void f_hlexists(typval_T *argvars, typval_T *rettv);
111static void f_hostname(typval_T *argvars, typval_T *rettv);
112static void f_iconv(typval_T *argvars, typval_T *rettv);
113static void f_indent(typval_T *argvars, typval_T *rettv);
114static void f_index(typval_T *argvars, typval_T *rettv);
115static void f_input(typval_T *argvars, typval_T *rettv);
116static void f_inputdialog(typval_T *argvars, typval_T *rettv);
117static void f_inputlist(typval_T *argvars, typval_T *rettv);
118static void f_inputrestore(typval_T *argvars, typval_T *rettv);
119static void f_inputsave(typval_T *argvars, typval_T *rettv);
120static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200122static void f_islocked(typval_T *argvars, typval_T *rettv);
123#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200124static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125static void f_isnan(typval_T *argvars, typval_T *rettv);
126#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
128static void f_len(typval_T *argvars, typval_T *rettv);
129static void f_libcall(typval_T *argvars, typval_T *rettv);
130static void f_libcallnr(typval_T *argvars, typval_T *rettv);
131static void f_line(typval_T *argvars, typval_T *rettv);
132static void f_line2byte(typval_T *argvars, typval_T *rettv);
133static void f_lispindent(typval_T *argvars, typval_T *rettv);
134static void f_localtime(typval_T *argvars, typval_T *rettv);
135#ifdef FEAT_FLOAT
136static void f_log(typval_T *argvars, typval_T *rettv);
137static void f_log10(typval_T *argvars, typval_T *rettv);
138#endif
139#ifdef FEAT_LUA
140static void f_luaeval(typval_T *argvars, typval_T *rettv);
141#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200142static void f_maparg(typval_T *argvars, typval_T *rettv);
143static void f_mapcheck(typval_T *argvars, typval_T *rettv);
144static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200145static void f_matchend(typval_T *argvars, typval_T *rettv);
146static void f_matchlist(typval_T *argvars, typval_T *rettv);
147static void f_matchstr(typval_T *argvars, typval_T *rettv);
148static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
149static void f_max(typval_T *argvars, typval_T *rettv);
150static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200151static void f_mode(typval_T *argvars, typval_T *rettv);
152#ifdef FEAT_MZSCHEME
153static void f_mzeval(typval_T *argvars, typval_T *rettv);
154#endif
155static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
156static void f_nr2char(typval_T *argvars, typval_T *rettv);
157static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200158#ifdef FEAT_PERL
159static void f_perleval(typval_T *argvars, typval_T *rettv);
160#endif
161#ifdef FEAT_FLOAT
162static void f_pow(typval_T *argvars, typval_T *rettv);
163#endif
164static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
165static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200166static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200167static void f_pumvisible(typval_T *argvars, typval_T *rettv);
168#ifdef FEAT_PYTHON3
169static void f_py3eval(typval_T *argvars, typval_T *rettv);
170#endif
171#ifdef FEAT_PYTHON
172static void f_pyeval(typval_T *argvars, typval_T *rettv);
173#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100174#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
175static void f_pyxeval(typval_T *argvars, typval_T *rettv);
176#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200178static void f_reg_executing(typval_T *argvars, typval_T *rettv);
179static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200180static void f_reltime(typval_T *argvars, typval_T *rettv);
181#ifdef FEAT_FLOAT
182static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
183#endif
184static void f_reltimestr(typval_T *argvars, typval_T *rettv);
185static void f_remote_expr(typval_T *argvars, typval_T *rettv);
186static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
187static void f_remote_peek(typval_T *argvars, typval_T *rettv);
188static void f_remote_read(typval_T *argvars, typval_T *rettv);
189static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100190static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_rename(typval_T *argvars, typval_T *rettv);
192static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193#ifdef FEAT_FLOAT
194static void f_round(typval_T *argvars, typval_T *rettv);
195#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100196#ifdef FEAT_RUBY
197static void f_rubyeval(typval_T *argvars, typval_T *rettv);
198#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200199static void f_screenattr(typval_T *argvars, typval_T *rettv);
200static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100201static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_screencol(typval_T *argvars, typval_T *rettv);
203static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100204static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200205static void f_search(typval_T *argvars, typval_T *rettv);
206static void f_searchdecl(typval_T *argvars, typval_T *rettv);
207static void f_searchpair(typval_T *argvars, typval_T *rettv);
208static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
209static void f_searchpos(typval_T *argvars, typval_T *rettv);
210static void f_server2client(typval_T *argvars, typval_T *rettv);
211static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200213static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200214static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200215static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200216static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100217static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200218#ifdef FEAT_CRYPT
219static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200220#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_shellescape(typval_T *argvars, typval_T *rettv);
222static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200223#ifdef FEAT_FLOAT
224static void f_sin(typval_T *argvars, typval_T *rettv);
225static void f_sinh(typval_T *argvars, typval_T *rettv);
226#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200227static void f_soundfold(typval_T *argvars, typval_T *rettv);
228static void f_spellbadword(typval_T *argvars, typval_T *rettv);
229static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
230static void f_split(typval_T *argvars, typval_T *rettv);
231#ifdef FEAT_FLOAT
232static void f_sqrt(typval_T *argvars, typval_T *rettv);
233static void f_str2float(typval_T *argvars, typval_T *rettv);
234#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200235static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200236static void f_str2nr(typval_T *argvars, typval_T *rettv);
237static void f_strchars(typval_T *argvars, typval_T *rettv);
238#ifdef HAVE_STRFTIME
239static void f_strftime(typval_T *argvars, typval_T *rettv);
240#endif
241static void f_strgetchar(typval_T *argvars, typval_T *rettv);
242static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200243static void f_strlen(typval_T *argvars, typval_T *rettv);
244static void f_strcharpart(typval_T *argvars, typval_T *rettv);
245static void f_strpart(typval_T *argvars, typval_T *rettv);
246static void f_strridx(typval_T *argvars, typval_T *rettv);
247static void f_strtrans(typval_T *argvars, typval_T *rettv);
248static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
249static void f_strwidth(typval_T *argvars, typval_T *rettv);
250static void f_submatch(typval_T *argvars, typval_T *rettv);
251static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200252static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200253static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200254static void f_synID(typval_T *argvars, typval_T *rettv);
255static void f_synIDattr(typval_T *argvars, typval_T *rettv);
256static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
257static void f_synstack(typval_T *argvars, typval_T *rettv);
258static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200259static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_taglist(typval_T *argvars, typval_T *rettv);
261static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200262#ifdef FEAT_FLOAT
263static void f_tan(typval_T *argvars, typval_T *rettv);
264static void f_tanh(typval_T *argvars, typval_T *rettv);
265#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200266static void f_tolower(typval_T *argvars, typval_T *rettv);
267static void f_toupper(typval_T *argvars, typval_T *rettv);
268static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100269static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200270#ifdef FEAT_FLOAT
271static void f_trunc(typval_T *argvars, typval_T *rettv);
272#endif
273static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200274static void f_virtcol(typval_T *argvars, typval_T *rettv);
275static void f_visualmode(typval_T *argvars, typval_T *rettv);
276static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200277static void f_wordcount(typval_T *argvars, typval_T *rettv);
278static void f_xor(typval_T *argvars, typval_T *rettv);
279
280/*
281 * Array with names and number of arguments of all internal functions
282 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
283 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200284typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200285{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200286 char *f_name; // function name
287 char f_min_argc; // minimal number of arguments
288 char f_max_argc; // maximal number of arguments
289 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200291 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200292} funcentry_T;
293
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200294// values for f_argtype; zero means it cannot be used as a method
295#define FEARG_1 1 // base is the first argument
296#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200297#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200298#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200299#define FEARG_LAST 9 // base is the last argument
300
Bram Moolenaarac92e252019-08-03 21:58:38 +0200301static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302{
303#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200304 {"abs", 1, 1, FEARG_1, f_abs},
305 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200307 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200308 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200309 {"append", 2, 2, FEARG_LAST, f_append},
310 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
311 {"argc", 0, 1, 0, f_argc},
312 {"argidx", 0, 0, 0, f_argidx},
313 {"arglistid", 0, 2, 0, f_arglistid},
314 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200316 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200318 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200319 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200320 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200321 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200322 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
323 {"assert_false", 1, 2, FEARG_1, f_assert_false},
324 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
325 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200326 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200327 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200328 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200329 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200330#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200331 {"atan", 1, 1, FEARG_1, f_atan},
332 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200333#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100334#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200335 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200336 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100337# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200338 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100339# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100340#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200341 {"browse", 4, 4, 0, f_browse},
342 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200343 {"bufadd", 1, 1, FEARG_1, f_bufadd},
344 {"bufexists", 1, 1, FEARG_1, f_bufexists},
345 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200346 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
347 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200348 {"buflisted", 1, 1, FEARG_1, f_buflisted},
349 {"bufload", 1, 1, FEARG_1, f_bufload},
350 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200351 {"bufname", 0, 1, FEARG_1, f_bufname},
352 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200353 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
354 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200355 {"byte2line", 1, 1, FEARG_1, f_byte2line},
356 {"byteidx", 2, 2, FEARG_1, f_byteidx},
357 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
358 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200360 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200361#endif
362#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200363 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
364 {"ch_close", 1, 1, FEARG_1, f_ch_close},
365 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
366 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
367 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
368 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
369 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
370 {"ch_info", 1, 1, FEARG_1, f_ch_info},
371 {"ch_log", 1, 2, FEARG_1, f_ch_log},
372 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
373 {"ch_open", 1, 2, FEARG_1, f_ch_open},
374 {"ch_read", 1, 2, FEARG_1, f_ch_read},
375 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
376 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
377 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
378 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
379 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
380 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200382 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200383 {"char2nr", 1, 2, FEARG_1, f_char2nr},
384 {"chdir", 1, 1, FEARG_1, f_chdir},
385 {"cindent", 1, 1, FEARG_1, f_cindent},
386 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
387 {"col", 1, 1, FEARG_1, f_col},
388 {"complete", 2, 2, FEARG_2, f_complete},
389 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200390 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200391 {"complete_info", 0, 1, FEARG_1, f_complete_info},
392 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200393 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200394#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200395 {"cos", 1, 1, FEARG_1, f_cos},
396 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200397#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200398 {"count", 2, 4, FEARG_1, f_count},
399 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200400 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100401#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200402 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200403#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200404 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
405 {"delete", 1, 2, FEARG_1, f_delete},
406 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200407 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200408 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
409 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200410 {"empty", 1, 1, FEARG_1, f_empty},
411 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200412 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200413 {"eval", 1, 1, FEARG_1, f_eval},
414 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200415 {"executable", 1, 1, FEARG_1, f_executable},
416 {"execute", 1, 2, FEARG_1, f_execute},
417 {"exepath", 1, 1, FEARG_1, f_exepath},
418 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200420 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200422 {"expand", 1, 3, FEARG_1, f_expand},
423 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200424 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200425 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
426 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
427 {"filereadable", 1, 1, FEARG_1, f_filereadable},
428 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200429 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200430 {"finddir", 1, 3, FEARG_1, f_finddir},
431 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200432#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200433 {"float2nr", 1, 1, FEARG_1, f_float2nr},
434 {"floor", 1, 1, FEARG_1, f_floor},
435 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200437 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
438 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
439 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
440 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
441 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200442 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200443 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200444 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200445 {"funcref", 1, 3, FEARG_1, f_funcref},
446 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200447 {"garbagecollect", 0, 1, 0, f_garbagecollect},
448 {"get", 2, 3, FEARG_1, f_get},
449 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200450 {"getbufline", 2, 3, FEARG_1, f_getbufline},
451 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
452 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200453 {"getchar", 0, 1, 0, f_getchar},
454 {"getcharmod", 0, 0, 0, f_getcharmod},
455 {"getcharsearch", 0, 0, 0, f_getcharsearch},
456 {"getcmdline", 0, 0, 0, f_getcmdline},
457 {"getcmdpos", 0, 0, 0, f_getcmdpos},
458 {"getcmdtype", 0, 0, 0, f_getcmdtype},
459 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200460 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200461 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200462 {"getcwd", 0, 2, FEARG_1, f_getcwd},
463 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200464 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200465 {"getfperm", 1, 1, FEARG_1, f_getfperm},
466 {"getfsize", 1, 1, FEARG_1, f_getfsize},
467 {"getftime", 1, 1, FEARG_1, f_getftime},
468 {"getftype", 1, 1, FEARG_1, f_getftype},
Bram Moolenaara3a12462019-09-07 15:08:38 +0200469 {"getimstatus", 0, 0, 0, f_getimstatus},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200470 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
471 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200472 {"getloclist", 1, 2, 0, f_getloclist},
473 {"getmatches", 0, 1, 0, f_getmatches},
474 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200475 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200476 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200477 {"getreg", 0, 3, FEARG_1, f_getreg},
478 {"getregtype", 0, 1, FEARG_1, f_getregtype},
479 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
480 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
481 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200482 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
483 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
484 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200485 {"getwinposx", 0, 0, 0, f_getwinposx},
486 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200487 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
488 {"glob", 1, 4, FEARG_1, f_glob},
489 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
490 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200491 {"has", 1, 1, 0, f_has},
492 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200493 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
494 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
495 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
496 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
497 {"histadd", 2, 2, FEARG_2, f_histadd},
498 {"histdel", 1, 2, FEARG_1, f_histdel},
499 {"histget", 1, 2, FEARG_1, f_histget},
500 {"histnr", 1, 1, FEARG_1, f_histnr},
501 {"hlID", 1, 1, FEARG_1, f_hlID},
502 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200503 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200504 {"iconv", 3, 3, FEARG_1, f_iconv},
505 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200506 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200507 {"input", 1, 3, FEARG_1, f_input},
508 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
509 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200510 {"inputrestore", 0, 0, 0, f_inputrestore},
511 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200512 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200513 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200514 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200515 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200516#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200517 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200518#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200519 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200521 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200522#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200523 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200524#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200525 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
526 {"job_info", 0, 1, FEARG_1, f_job_info},
527 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
528 {"job_start", 1, 2, FEARG_1, f_job_start},
529 {"job_status", 1, 1, FEARG_1, f_job_status},
530 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200531#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200532 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200533 {"js_decode", 1, 1, FEARG_1, f_js_decode},
534 {"js_encode", 1, 1, FEARG_1, f_js_encode},
535 {"json_decode", 1, 1, FEARG_1, f_json_decode},
536 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200537 {"keys", 1, 1, FEARG_1, f_keys},
538 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
539 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200540 {"libcall", 3, 3, FEARG_3, f_libcall},
541 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200542 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200543 {"line2byte", 1, 1, FEARG_1, f_line2byte},
544 {"lispindent", 1, 1, FEARG_1, f_lispindent},
545 {"list2str", 1, 2, FEARG_1, f_list2str},
546 {"listener_add", 1, 2, FEARG_2, f_listener_add},
547 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
548 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200549 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200551 {"log", 1, 1, FEARG_1, f_log},
552 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200553#endif
554#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200555 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200556#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200557 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200558 {"maparg", 1, 4, FEARG_1, f_maparg},
559 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
560 {"match", 2, 4, FEARG_1, f_match},
561 {"matchadd", 2, 5, FEARG_1, f_matchadd},
562 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
563 {"matcharg", 1, 1, FEARG_1, f_matcharg},
564 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
565 {"matchend", 2, 4, FEARG_1, f_matchend},
566 {"matchlist", 2, 4, FEARG_1, f_matchlist},
567 {"matchstr", 2, 4, FEARG_1, f_matchstr},
568 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200569 {"max", 1, 1, FEARG_1, f_max},
570 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200571 {"mkdir", 1, 3, FEARG_1, f_mkdir},
572 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200573#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200574 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200576 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
577 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200578 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200579 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200580#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200581 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200582#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200583#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200584 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
585 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200586 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200587 {"popup_close", 1, 2, FEARG_1, f_popup_close},
588 {"popup_create", 2, 2, FEARG_1, f_popup_create},
589 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200590 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
591 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200592 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
593 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200594 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
595 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
596 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200597 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200598 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
599 {"popup_move", 2, 2, FEARG_1, f_popup_move},
600 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
601 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
602 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
603 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200604#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200605#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200606 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200607#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200608 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200609 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200610#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200611 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
612 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
613 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200614#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100615#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200616 {"prop_add", 3, 3, FEARG_1, f_prop_add},
617 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
618 {"prop_list", 1, 2, FEARG_1, f_prop_list},
619 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
620 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
621 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
622 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
623 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
624 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100625#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200626 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200627 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200628#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200629 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200630#endif
631#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200632 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100634#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200635 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100636#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200637 {"range", 1, 3, FEARG_1, f_range},
638 {"readdir", 1, 2, FEARG_1, f_readdir},
639 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200640 {"reg_executing", 0, 0, 0, f_reg_executing},
641 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200642 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200644 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200645#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200646 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
647 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
648 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
649 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
650 {"remote_read", 1, 2, FEARG_1, f_remote_read},
651 {"remote_send", 2, 3, FEARG_1, f_remote_send},
652 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200653 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200654 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200655 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200656 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200657 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200659 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200660#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100661#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200662 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100663#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200664 {"screenattr", 2, 2, FEARG_1, f_screenattr},
665 {"screenchar", 2, 2, FEARG_1, f_screenchar},
666 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200667 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200668 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200669 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200670 {"screenstring", 2, 2, FEARG_1, f_screenstring},
671 {"search", 1, 4, FEARG_1, f_search},
672 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200673 {"searchpair", 3, 7, 0, f_searchpair},
674 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200675 {"searchpos", 1, 4, FEARG_1, f_searchpos},
676 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200677 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200678 {"setbufline", 3, 3, FEARG_3, f_setbufline},
679 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
680 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
681 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
682 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200683 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200684 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200685 {"setloclist", 2, 4, FEARG_2, f_setloclist},
686 {"setmatches", 1, 2, FEARG_1, f_setmatches},
687 {"setpos", 2, 2, FEARG_2, f_setpos},
688 {"setqflist", 1, 3, FEARG_1, f_setqflist},
689 {"setreg", 2, 3, FEARG_2, f_setreg},
690 {"settabvar", 3, 3, FEARG_3, f_settabvar},
691 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
692 {"settagstack", 2, 3, FEARG_2, f_settagstack},
693 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200694#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200695 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200696#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200697 {"shellescape", 1, 2, FEARG_1, f_shellescape},
698 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100699#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200700 {"sign_define", 1, 2, FEARG_1, f_sign_define},
701 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
702 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
703 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
704 {"sign_place", 4, 5, FEARG_1, f_sign_place},
705 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
706 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
707 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
708 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100709#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200710 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200711#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200712 {"sin", 1, 1, FEARG_1, f_sin},
713 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200714#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200715 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200716#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200717 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200718 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
719 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
720 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200721#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200722 {"soundfold", 1, 1, FEARG_1, f_soundfold},
723 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
724 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200725 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200726#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200727 {"sqrt", 1, 1, FEARG_1, f_sqrt},
728 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200729#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200730 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200731 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200732 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
733 {"strchars", 1, 2, FEARG_1, f_strchars},
734 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200735#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200736 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200737#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200738 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
739 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200740 {"string", 1, 1, FEARG_1, f_string},
741 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200742 {"strpart", 2, 3, FEARG_1, f_strpart},
743 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200744 {"strtrans", 1, 1, FEARG_1, f_strtrans},
745 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200746 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200748 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
749 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200750 {"synID", 3, 3, 0, f_synID},
751 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
752 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
753 {"synconcealed", 2, 2, 0, f_synconcealed},
754 {"synstack", 2, 2, 0, f_synstack},
755 {"system", 1, 2, FEARG_1, f_system},
756 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200757 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200758 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200759 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200760 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200761 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200763 {"tan", 1, 1, FEARG_1, f_tan},
764 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200765#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200766 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200767#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200768 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
769 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
770 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
771 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200772# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200773 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200774# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200775 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
776 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
777 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
778 {"term_getline", 2, 2, FEARG_1, f_term_getline},
779 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
780 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
781 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
782 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
783 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200784 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200785 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
786 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200787# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200788 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200789# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200790 {"term_setkill", 2, 2, FEARG_1, f_term_setkill},
791 {"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
792 {"term_setsize", 3, 3, FEARG_1, f_term_setsize},
793 {"term_start", 1, 2, FEARG_1, f_term_start},
794 {"term_wait", 1, 2, FEARG_1, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200795#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200796 {"test_alloc_fail", 3, 3, FEARG_1, f_test_alloc_fail},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200797 {"test_autochdir", 0, 0, 0, f_test_autochdir},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200798 {"test_feedinput", 1, 1, FEARG_1, f_test_feedinput},
799 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
800 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
801 {"test_getvalue", 1, 1, FEARG_1, f_test_getvalue},
802 {"test_ignore_error", 1, 1, FEARG_1, f_test_ignore_error},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200803 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200805 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200806#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200807 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200809 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200810#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200811 {"test_null_list", 0, 0, 0, f_test_null_list},
812 {"test_null_partial", 0, 0, 0, f_test_null_partial},
813 {"test_null_string", 0, 0, 0, f_test_null_string},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200814 {"test_option_not_set", 1, 1, FEARG_1, f_test_option_not_set},
815 {"test_override", 2, 2, FEARG_2, f_test_override},
816 {"test_refcount", 1, 1, FEARG_1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200817#ifdef FEAT_GUI
Bram Moolenaarce90e362019-09-08 18:58:44 +0200818 {"test_scrollbar", 3, 3, FEARG_2, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200819#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200820#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200821 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200822#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200823 {"test_settime", 1, 1, FEARG_1, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824#ifdef FEAT_TIMERS
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200825 {"timer_info", 0, 1, FEARG_1, f_timer_info},
826 {"timer_pause", 2, 2, FEARG_1, f_timer_pause},
827 {"timer_start", 2, 3, FEARG_1, f_timer_start},
828 {"timer_stop", 1, 1, FEARG_1, f_timer_stop},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200829 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830#endif
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200831 {"tolower", 1, 1, FEARG_1, f_tolower},
832 {"toupper", 1, 1, FEARG_1, f_toupper},
833 {"tr", 3, 3, FEARG_1, f_tr},
834 {"trim", 1, 2, FEARG_1, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200835#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200836 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200837#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200838 {"type", 1, 1, FEARG_1, f_type},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200839 {"undofile", 1, 1, FEARG_1, f_undofile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200840 {"undotree", 0, 0, 0, f_undotree},
841 {"uniq", 1, 3, FEARG_1, f_uniq},
842 {"values", 1, 1, FEARG_1, f_values},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200843 {"virtcol", 1, 1, FEARG_1, f_virtcol},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200844 {"visualmode", 0, 1, 0, f_visualmode},
845 {"wildmenumode", 0, 0, 0, f_wildmenumode},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200846 {"win_execute", 2, 3, FEARG_2, f_win_execute},
847 {"win_findbuf", 1, 1, FEARG_1, f_win_findbuf},
848 {"win_getid", 0, 2, FEARG_1, f_win_getid},
849 {"win_gotoid", 1, 1, FEARG_1, f_win_gotoid},
850 {"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
851 {"win_id2win", 1, 1, FEARG_1, f_win_id2win},
852 {"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200853 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200854 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200855 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200856 {"winheight", 1, 1, FEARG_1, f_winheight},
857 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200858 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200859 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200860 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200861 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200862 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200863 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200864 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200865 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200866 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200867};
868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200869/*
870 * Function given to ExpandGeneric() to obtain the list of internal
871 * or user defined function names.
872 */
873 char_u *
874get_function_name(expand_T *xp, int idx)
875{
876 static int intidx = -1;
877 char_u *name;
878
879 if (idx == 0)
880 intidx = -1;
881 if (intidx < 0)
882 {
883 name = get_user_func_name(xp, idx);
884 if (name != NULL)
885 return name;
886 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200887 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200889 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200891 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200892 STRCAT(IObuff, ")");
893 return IObuff;
894 }
895
896 return NULL;
897}
898
899/*
900 * Function given to ExpandGeneric() to obtain the list of internal or
901 * user defined variable or function names.
902 */
903 char_u *
904get_expr_name(expand_T *xp, int idx)
905{
906 static int intidx = -1;
907 char_u *name;
908
909 if (idx == 0)
910 intidx = -1;
911 if (intidx < 0)
912 {
913 name = get_function_name(xp, idx);
914 if (name != NULL)
915 return name;
916 }
917 return get_user_var_name(xp, ++intidx);
918}
919
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200921 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922 * Return index, or -1 if not found
923 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200924 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200925find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926{
927 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200928 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929 int cmp;
930 int x;
931
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200932 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200933
934 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935 while (first <= last)
936 {
937 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200938 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939 if (cmp < 0)
940 last = x - 1;
941 else if (cmp > 0)
942 first = x + 1;
943 else
944 return x;
945 }
946 return -1;
947}
948
949 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200950has_internal_func(char_u *name)
951{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200952 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200953}
954
955 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956call_internal_func(
957 char_u *name,
958 int argcount,
959 typval_T *argvars,
960 typval_T *rettv)
961{
962 int i;
963
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200964 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965 if (i < 0)
966 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200967 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200968 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200969 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200970 return ERROR_TOOMANY;
971 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200972 global_functions[i].f_func(argvars, rettv);
973 return ERROR_NONE;
974}
975
976/*
977 * Invoke a method for base->method().
978 */
979 int
980call_internal_method(
981 char_u *name,
982 int argcount,
983 typval_T *argvars,
984 typval_T *rettv,
985 typval_T *basetv)
986{
987 int i;
988 int fi;
989 typval_T argv[MAX_FUNC_ARGS + 1];
990
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200991 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +0200992 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200993 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +0200994 if (global_functions[fi].f_argtype == 0)
995 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200996 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200997 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200998 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200999 return ERROR_TOOMANY;
1000
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001001 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001002 {
1003 // base value goes last
1004 for (i = 0; i < argcount; ++i)
1005 argv[i] = argvars[i];
1006 argv[argcount] = *basetv;
1007 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001008 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001009 {
1010 // base value goes second
1011 argv[0] = argvars[0];
1012 argv[1] = *basetv;
1013 for (i = 1; i < argcount; ++i)
1014 argv[i + 1] = argvars[i];
1015 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001016 else if (global_functions[fi].f_argtype == FEARG_3)
1017 {
1018 // base value goes third
1019 argv[0] = argvars[0];
1020 argv[1] = argvars[1];
1021 argv[2] = *basetv;
1022 for (i = 2; i < argcount; ++i)
1023 argv[i + 1] = argvars[i];
1024 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001025 else if (global_functions[fi].f_argtype == FEARG_4)
1026 {
1027 // base value goes fourth
1028 argv[0] = argvars[0];
1029 argv[1] = argvars[1];
1030 argv[2] = argvars[2];
1031 argv[3] = *basetv;
1032 for (i = 3; i < argcount; ++i)
1033 argv[i + 1] = argvars[i];
1034 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001035 else
1036 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001037 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001038 argv[0] = *basetv;
1039 for (i = 0; i < argcount; ++i)
1040 argv[i + 1] = argvars[i];
1041 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042 argv[argcount + 1].v_type = VAR_UNKNOWN;
1043
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001044 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001045 return ERROR_NONE;
1046}
1047
1048/*
1049 * Return TRUE for a non-zero Number and a non-empty String.
1050 */
1051 static int
1052non_zero_arg(typval_T *argvars)
1053{
1054 return ((argvars[0].v_type == VAR_NUMBER
1055 && argvars[0].vval.v_number != 0)
1056 || (argvars[0].v_type == VAR_SPECIAL
1057 && argvars[0].vval.v_number == VVAL_TRUE)
1058 || (argvars[0].v_type == VAR_STRING
1059 && argvars[0].vval.v_string != NULL
1060 && *argvars[0].vval.v_string != NUL));
1061}
1062
1063/*
1064 * Get the lnum from the first argument.
1065 * Also accepts ".", "$", etc., but that only works for the current buffer.
1066 * Returns -1 on error.
1067 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001068 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001069tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001070{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001071 linenr_T lnum;
1072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001073 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001074 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001075 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001076 int fnum;
1077 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1078
1079 if (fp != NULL)
1080 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001081 }
1082 return lnum;
1083}
1084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001085/*
1086 * Get the lnum from the first argument.
1087 * Also accepts "$", then "buf" is used.
1088 * Returns 0 on error.
1089 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001090 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001091tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1092{
1093 if (argvars[0].v_type == VAR_STRING
1094 && argvars[0].vval.v_string != NULL
1095 && argvars[0].vval.v_string[0] == '$'
1096 && buf != NULL)
1097 return buf->b_ml.ml_line_count;
1098 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1099}
1100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001101#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001102/*
1103 * Get the float value of "argvars[0]" into "f".
1104 * Returns FAIL when the argument is not a Number or Float.
1105 */
1106 static int
1107get_float_arg(typval_T *argvars, float_T *f)
1108{
1109 if (argvars[0].v_type == VAR_FLOAT)
1110 {
1111 *f = argvars[0].vval.v_float;
1112 return OK;
1113 }
1114 if (argvars[0].v_type == VAR_NUMBER)
1115 {
1116 *f = (float_T)argvars[0].vval.v_number;
1117 return OK;
1118 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001119 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001120 return FAIL;
1121}
1122
1123/*
1124 * "abs(expr)" function
1125 */
1126 static void
1127f_abs(typval_T *argvars, typval_T *rettv)
1128{
1129 if (argvars[0].v_type == VAR_FLOAT)
1130 {
1131 rettv->v_type = VAR_FLOAT;
1132 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1133 }
1134 else
1135 {
1136 varnumber_T n;
1137 int error = FALSE;
1138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001139 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001140 if (error)
1141 rettv->vval.v_number = -1;
1142 else if (n > 0)
1143 rettv->vval.v_number = n;
1144 else
1145 rettv->vval.v_number = -n;
1146 }
1147}
1148
1149/*
1150 * "acos()" function
1151 */
1152 static void
1153f_acos(typval_T *argvars, typval_T *rettv)
1154{
1155 float_T f = 0.0;
1156
1157 rettv->v_type = VAR_FLOAT;
1158 if (get_float_arg(argvars, &f) == OK)
1159 rettv->vval.v_float = acos(f);
1160 else
1161 rettv->vval.v_float = 0.0;
1162}
1163#endif
1164
1165/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001166 * "and(expr, expr)" function
1167 */
1168 static void
1169f_and(typval_T *argvars, typval_T *rettv)
1170{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001171 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1172 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001173}
1174
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001175#ifdef FEAT_FLOAT
1176/*
1177 * "asin()" function
1178 */
1179 static void
1180f_asin(typval_T *argvars, typval_T *rettv)
1181{
1182 float_T f = 0.0;
1183
1184 rettv->v_type = VAR_FLOAT;
1185 if (get_float_arg(argvars, &f) == OK)
1186 rettv->vval.v_float = asin(f);
1187 else
1188 rettv->vval.v_float = 0.0;
1189}
1190
1191/*
1192 * "atan()" function
1193 */
1194 static void
1195f_atan(typval_T *argvars, typval_T *rettv)
1196{
1197 float_T f = 0.0;
1198
1199 rettv->v_type = VAR_FLOAT;
1200 if (get_float_arg(argvars, &f) == OK)
1201 rettv->vval.v_float = atan(f);
1202 else
1203 rettv->vval.v_float = 0.0;
1204}
1205
1206/*
1207 * "atan2()" function
1208 */
1209 static void
1210f_atan2(typval_T *argvars, typval_T *rettv)
1211{
1212 float_T fx = 0.0, fy = 0.0;
1213
1214 rettv->v_type = VAR_FLOAT;
1215 if (get_float_arg(argvars, &fx) == OK
1216 && get_float_arg(&argvars[1], &fy) == OK)
1217 rettv->vval.v_float = atan2(fx, fy);
1218 else
1219 rettv->vval.v_float = 0.0;
1220}
1221#endif
1222
1223/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001224 * "balloon_show()" function
1225 */
1226#ifdef FEAT_BEVAL
1227 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001228f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1229{
1230 rettv->v_type = VAR_STRING;
1231 if (balloonEval != NULL)
1232 {
1233 if (balloonEval->msg == NULL)
1234 rettv->vval.v_string = NULL;
1235 else
1236 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1237 }
1238}
1239
1240 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001241f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1242{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001243 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001244 {
1245 if (argvars[0].v_type == VAR_LIST
1246# ifdef FEAT_GUI
1247 && !gui.in_use
1248# endif
1249 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001250 {
1251 list_T *l = argvars[0].vval.v_list;
1252
1253 // empty list removes the balloon
1254 post_balloon(balloonEval, NULL,
1255 l == NULL || l->lv_len == 0 ? NULL : l);
1256 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001257 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001258 {
1259 char_u *mesg = tv_get_string_chk(&argvars[0]);
1260
1261 if (mesg != NULL)
1262 // empty string removes the balloon
1263 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1264 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001265 }
1266}
1267
Bram Moolenaar669a8282017-11-19 20:13:05 +01001268# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001269 static void
1270f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1271{
1272 if (rettv_list_alloc(rettv) == OK)
1273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001274 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001275
1276 if (msg != NULL)
1277 {
1278 pumitem_T *array;
1279 int size = split_message(msg, &array);
1280 int i;
1281
1282 /* Skip the first and last item, they are always empty. */
1283 for (i = 1; i < size - 1; ++i)
1284 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001285 while (size > 0)
1286 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001287 vim_free(array);
1288 }
1289 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001290}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001291# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001292#endif
1293
1294/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 * Get buffer by number or pattern.
1296 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001297 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001298tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001299{
1300 char_u *name = tv->vval.v_string;
1301 buf_T *buf;
1302
1303 if (tv->v_type == VAR_NUMBER)
1304 return buflist_findnr((int)tv->vval.v_number);
1305 if (tv->v_type != VAR_STRING)
1306 return NULL;
1307 if (name == NULL || *name == NUL)
1308 return curbuf;
1309 if (name[0] == '$' && name[1] == NUL)
1310 return lastbuf;
1311
1312 buf = buflist_find_by_name(name, curtab_only);
1313
1314 /* If not found, try expanding the name, like done for bufexists(). */
1315 if (buf == NULL)
1316 buf = find_buffer(tv);
1317
1318 return buf;
1319}
1320
1321/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001322 * Get the buffer from "arg" and give an error and return NULL if it is not
1323 * valid.
1324 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001325 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001326get_buf_arg(typval_T *arg)
1327{
1328 buf_T *buf;
1329
1330 ++emsg_off;
1331 buf = tv_get_buf(arg, FALSE);
1332 --emsg_off;
1333 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001334 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001335 return buf;
1336}
1337
1338/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001339 * "byte2line(byte)" function
1340 */
1341 static void
1342f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1343{
1344#ifndef FEAT_BYTEOFF
1345 rettv->vval.v_number = -1;
1346#else
1347 long boff = 0;
1348
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001349 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 if (boff < 0)
1351 rettv->vval.v_number = -1;
1352 else
1353 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1354 (linenr_T)0, &boff);
1355#endif
1356}
1357
1358 static void
1359byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1360{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 char_u *str;
1363 varnumber_T idx;
1364
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001365 str = tv_get_string_chk(&argvars[0]);
1366 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 rettv->vval.v_number = -1;
1368 if (str == NULL || idx < 0)
1369 return;
1370
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001371 t = str;
1372 for ( ; idx > 0; idx--)
1373 {
1374 if (*t == NUL) /* EOL reached */
1375 return;
1376 if (enc_utf8 && comp)
1377 t += utf_ptr2len(t);
1378 else
1379 t += (*mb_ptr2len)(t);
1380 }
1381 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382}
1383
1384/*
1385 * "byteidx()" function
1386 */
1387 static void
1388f_byteidx(typval_T *argvars, typval_T *rettv)
1389{
1390 byteidx(argvars, rettv, FALSE);
1391}
1392
1393/*
1394 * "byteidxcomp()" function
1395 */
1396 static void
1397f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1398{
1399 byteidx(argvars, rettv, TRUE);
1400}
1401
1402/*
1403 * "call(func, arglist [, dict])" function
1404 */
1405 static void
1406f_call(typval_T *argvars, typval_T *rettv)
1407{
1408 char_u *func;
1409 partial_T *partial = NULL;
1410 dict_T *selfdict = NULL;
1411
1412 if (argvars[1].v_type != VAR_LIST)
1413 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001414 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001415 return;
1416 }
1417 if (argvars[1].vval.v_list == NULL)
1418 return;
1419
1420 if (argvars[0].v_type == VAR_FUNC)
1421 func = argvars[0].vval.v_string;
1422 else if (argvars[0].v_type == VAR_PARTIAL)
1423 {
1424 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001425 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001426 }
1427 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001428 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001429 if (*func == NUL)
1430 return; /* type error or empty name */
1431
1432 if (argvars[2].v_type != VAR_UNKNOWN)
1433 {
1434 if (argvars[2].v_type != VAR_DICT)
1435 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001436 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001437 return;
1438 }
1439 selfdict = argvars[2].vval.v_dict;
1440 }
1441
1442 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1443}
1444
1445#ifdef FEAT_FLOAT
1446/*
1447 * "ceil({float})" function
1448 */
1449 static void
1450f_ceil(typval_T *argvars, typval_T *rettv)
1451{
1452 float_T f = 0.0;
1453
1454 rettv->v_type = VAR_FLOAT;
1455 if (get_float_arg(argvars, &f) == OK)
1456 rettv->vval.v_float = ceil(f);
1457 else
1458 rettv->vval.v_float = 0.0;
1459}
1460#endif
1461
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001462/*
1463 * "changenr()" function
1464 */
1465 static void
1466f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1467{
1468 rettv->vval.v_number = curbuf->b_u_seq_cur;
1469}
1470
1471/*
1472 * "char2nr(string)" function
1473 */
1474 static void
1475f_char2nr(typval_T *argvars, typval_T *rettv)
1476{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001477 if (has_mbyte)
1478 {
1479 int utf8 = 0;
1480
1481 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001482 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483
1484 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001485 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001487 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488 }
1489 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001490 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001491}
1492
1493/*
1494 * "cindent(lnum)" function
1495 */
1496 static void
1497f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1498{
1499#ifdef FEAT_CINDENT
1500 pos_T pos;
1501 linenr_T lnum;
1502
1503 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001504 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001505 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1506 {
1507 curwin->w_cursor.lnum = lnum;
1508 rettv->vval.v_number = get_c_indent();
1509 curwin->w_cursor = pos;
1510 }
1511 else
1512#endif
1513 rettv->vval.v_number = -1;
1514}
1515
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001516 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001517get_optional_window(typval_T *argvars, int idx)
1518{
1519 win_T *win = curwin;
1520
1521 if (argvars[idx].v_type != VAR_UNKNOWN)
1522 {
1523 win = find_win_by_nr_or_id(&argvars[idx]);
1524 if (win == NULL)
1525 {
1526 emsg(_(e_invalwindow));
1527 return NULL;
1528 }
1529 }
1530 return win;
1531}
1532
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001534 * "col(string)" function
1535 */
1536 static void
1537f_col(typval_T *argvars, typval_T *rettv)
1538{
1539 colnr_T col = 0;
1540 pos_T *fp;
1541 int fnum = curbuf->b_fnum;
1542
1543 fp = var2fpos(&argvars[0], FALSE, &fnum);
1544 if (fp != NULL && fnum == curbuf->b_fnum)
1545 {
1546 if (fp->col == MAXCOL)
1547 {
1548 /* '> can be MAXCOL, get the length of the line then */
1549 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1550 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1551 else
1552 col = MAXCOL;
1553 }
1554 else
1555 {
1556 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001557 /* col(".") when the cursor is on the NUL at the end of the line
1558 * because of "coladd" can be seen as an extra column. */
1559 if (virtual_active() && fp == &curwin->w_cursor)
1560 {
1561 char_u *p = ml_get_cursor();
1562
1563 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1564 curwin->w_virtcol - curwin->w_cursor.coladd))
1565 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001566 int l;
1567
1568 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1569 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 }
1571 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572 }
1573 }
1574 rettv->vval.v_number = col;
1575}
1576
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001577/*
1578 * "confirm(message, buttons[, default [, type]])" function
1579 */
1580 static void
1581f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1582{
1583#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1584 char_u *message;
1585 char_u *buttons = NULL;
1586 char_u buf[NUMBUFLEN];
1587 char_u buf2[NUMBUFLEN];
1588 int def = 1;
1589 int type = VIM_GENERIC;
1590 char_u *typestr;
1591 int error = FALSE;
1592
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001593 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001594 if (message == NULL)
1595 error = TRUE;
1596 if (argvars[1].v_type != VAR_UNKNOWN)
1597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001598 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001599 if (buttons == NULL)
1600 error = TRUE;
1601 if (argvars[2].v_type != VAR_UNKNOWN)
1602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001603 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001604 if (argvars[3].v_type != VAR_UNKNOWN)
1605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001606 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607 if (typestr == NULL)
1608 error = TRUE;
1609 else
1610 {
1611 switch (TOUPPER_ASC(*typestr))
1612 {
1613 case 'E': type = VIM_ERROR; break;
1614 case 'Q': type = VIM_QUESTION; break;
1615 case 'I': type = VIM_INFO; break;
1616 case 'W': type = VIM_WARNING; break;
1617 case 'G': type = VIM_GENERIC; break;
1618 }
1619 }
1620 }
1621 }
1622 }
1623
1624 if (buttons == NULL || *buttons == NUL)
1625 buttons = (char_u *)_("&Ok");
1626
1627 if (!error)
1628 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1629 def, NULL, FALSE);
1630#endif
1631}
1632
1633/*
1634 * "copy()" function
1635 */
1636 static void
1637f_copy(typval_T *argvars, typval_T *rettv)
1638{
1639 item_copy(&argvars[0], rettv, FALSE, 0);
1640}
1641
1642#ifdef FEAT_FLOAT
1643/*
1644 * "cos()" function
1645 */
1646 static void
1647f_cos(typval_T *argvars, typval_T *rettv)
1648{
1649 float_T f = 0.0;
1650
1651 rettv->v_type = VAR_FLOAT;
1652 if (get_float_arg(argvars, &f) == OK)
1653 rettv->vval.v_float = cos(f);
1654 else
1655 rettv->vval.v_float = 0.0;
1656}
1657
1658/*
1659 * "cosh()" function
1660 */
1661 static void
1662f_cosh(typval_T *argvars, typval_T *rettv)
1663{
1664 float_T f = 0.0;
1665
1666 rettv->v_type = VAR_FLOAT;
1667 if (get_float_arg(argvars, &f) == OK)
1668 rettv->vval.v_float = cosh(f);
1669 else
1670 rettv->vval.v_float = 0.0;
1671}
1672#endif
1673
1674/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 * "cursor(lnum, col)" function, or
1676 * "cursor(list)"
1677 *
1678 * Moves the cursor to the specified line and column.
1679 * Returns 0 when the position could be set, -1 otherwise.
1680 */
1681 static void
1682f_cursor(typval_T *argvars, typval_T *rettv)
1683{
1684 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 int set_curswant = TRUE;
1687
1688 rettv->vval.v_number = -1;
1689 if (argvars[1].v_type == VAR_UNKNOWN)
1690 {
1691 pos_T pos;
1692 colnr_T curswant = -1;
1693
1694 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1695 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001696 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697 return;
1698 }
1699 line = pos.lnum;
1700 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001701 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702 if (curswant >= 0)
1703 {
1704 curwin->w_curswant = curswant - 1;
1705 set_curswant = FALSE;
1706 }
1707 }
1708 else
1709 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001710 line = tv_get_lnum(argvars);
1711 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001713 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001715 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 return; /* type error; errmsg already given */
1717 if (line > 0)
1718 curwin->w_cursor.lnum = line;
1719 if (col > 0)
1720 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001721 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722
1723 /* Make sure the cursor is in a valid position. */
1724 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 /* Correct cursor for multi-byte character. */
1726 if (has_mbyte)
1727 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728
1729 curwin->w_set_curswant = set_curswant;
1730 rettv->vval.v_number = 0;
1731}
1732
Bram Moolenaar4f974752019-02-17 17:44:42 +01001733#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001734/*
1735 * "debugbreak()" function
1736 */
1737 static void
1738f_debugbreak(typval_T *argvars, typval_T *rettv)
1739{
1740 int pid;
1741
1742 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001743 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001744 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001745 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001746 else
1747 {
1748 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1749
1750 if (hProcess != NULL)
1751 {
1752 DebugBreakProcess(hProcess);
1753 CloseHandle(hProcess);
1754 rettv->vval.v_number = OK;
1755 }
1756 }
1757}
1758#endif
1759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001760/*
1761 * "deepcopy()" function
1762 */
1763 static void
1764f_deepcopy(typval_T *argvars, typval_T *rettv)
1765{
1766 int noref = 0;
1767 int copyID;
1768
1769 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001770 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001771 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001772 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773 else
1774 {
1775 copyID = get_copyID();
1776 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1777 }
1778}
1779
1780/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001781 * "did_filetype()" function
1782 */
1783 static void
1784f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1785{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001786 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001787}
1788
1789/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790 * "empty({expr})" function
1791 */
1792 static void
1793f_empty(typval_T *argvars, typval_T *rettv)
1794{
1795 int n = FALSE;
1796
1797 switch (argvars[0].v_type)
1798 {
1799 case VAR_STRING:
1800 case VAR_FUNC:
1801 n = argvars[0].vval.v_string == NULL
1802 || *argvars[0].vval.v_string == NUL;
1803 break;
1804 case VAR_PARTIAL:
1805 n = FALSE;
1806 break;
1807 case VAR_NUMBER:
1808 n = argvars[0].vval.v_number == 0;
1809 break;
1810 case VAR_FLOAT:
1811#ifdef FEAT_FLOAT
1812 n = argvars[0].vval.v_float == 0.0;
1813 break;
1814#endif
1815 case VAR_LIST:
1816 n = argvars[0].vval.v_list == NULL
1817 || argvars[0].vval.v_list->lv_first == NULL;
1818 break;
1819 case VAR_DICT:
1820 n = argvars[0].vval.v_dict == NULL
1821 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1822 break;
1823 case VAR_SPECIAL:
1824 n = argvars[0].vval.v_number != VVAL_TRUE;
1825 break;
1826
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001827 case VAR_BLOB:
1828 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001829 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1830 break;
1831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 case VAR_JOB:
1833#ifdef FEAT_JOB_CHANNEL
1834 n = argvars[0].vval.v_job == NULL
1835 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1836 break;
1837#endif
1838 case VAR_CHANNEL:
1839#ifdef FEAT_JOB_CHANNEL
1840 n = argvars[0].vval.v_channel == NULL
1841 || !channel_is_open(argvars[0].vval.v_channel);
1842 break;
1843#endif
1844 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001845 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846 n = TRUE;
1847 break;
1848 }
1849
1850 rettv->vval.v_number = n;
1851}
1852
1853/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001854 * "environ()" function
1855 */
1856 static void
1857f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1858{
1859#if !defined(AMIGA)
1860 int i = 0;
1861 char_u *entry, *value;
1862# ifdef MSWIN
1863 extern wchar_t **_wenviron;
1864# else
1865 extern char **environ;
1866# endif
1867
1868 if (rettv_dict_alloc(rettv) != OK)
1869 return;
1870
1871# ifdef MSWIN
1872 if (*_wenviron == NULL)
1873 return;
1874# else
1875 if (*environ == NULL)
1876 return;
1877# endif
1878
1879 for (i = 0; ; ++i)
1880 {
1881# ifdef MSWIN
1882 short_u *p;
1883
1884 if ((p = (short_u *)_wenviron[i]) == NULL)
1885 return;
1886 entry = utf16_to_enc(p, NULL);
1887# else
1888 if ((entry = (char_u *)environ[i]) == NULL)
1889 return;
1890 entry = vim_strsave(entry);
1891# endif
1892 if (entry == NULL) // out of memory
1893 return;
1894 if ((value = vim_strchr(entry, '=')) == NULL)
1895 {
1896 vim_free(entry);
1897 continue;
1898 }
1899 *value++ = NUL;
1900 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1901 vim_free(entry);
1902 }
1903#endif
1904}
1905
1906/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001907 * "escape({string}, {chars})" function
1908 */
1909 static void
1910f_escape(typval_T *argvars, typval_T *rettv)
1911{
1912 char_u buf[NUMBUFLEN];
1913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001914 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1915 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001916 rettv->v_type = VAR_STRING;
1917}
1918
1919/*
1920 * "eval()" function
1921 */
1922 static void
1923f_eval(typval_T *argvars, typval_T *rettv)
1924{
1925 char_u *s, *p;
1926
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001927 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 if (s != NULL)
1929 s = skipwhite(s);
1930
1931 p = s;
1932 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1933 {
1934 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001935 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001936 need_clr_eos = FALSE;
1937 rettv->v_type = VAR_NUMBER;
1938 rettv->vval.v_number = 0;
1939 }
1940 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001941 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942}
1943
1944/*
1945 * "eventhandler()" function
1946 */
1947 static void
1948f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1949{
1950 rettv->vval.v_number = vgetc_busy;
1951}
1952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001953static garray_T redir_execute_ga;
1954
1955/*
1956 * Append "value[value_len]" to the execute() output.
1957 */
1958 void
1959execute_redir_str(char_u *value, int value_len)
1960{
1961 int len;
1962
1963 if (value_len == -1)
1964 len = (int)STRLEN(value); /* Append the entire string */
1965 else
1966 len = value_len; /* Append only "value_len" characters */
1967 if (ga_grow(&redir_execute_ga, len) == OK)
1968 {
1969 mch_memmove((char *)redir_execute_ga.ga_data
1970 + redir_execute_ga.ga_len, value, len);
1971 redir_execute_ga.ga_len += len;
1972 }
1973}
1974
1975/*
1976 * Get next line from a list.
1977 * Called by do_cmdline() to get the next line.
1978 * Returns allocated string, or NULL for end of function.
1979 */
1980
1981 static char_u *
1982get_list_line(
1983 int c UNUSED,
1984 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001985 int indent UNUSED,
1986 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987{
1988 listitem_T **p = (listitem_T **)cookie;
1989 listitem_T *item = *p;
1990 char_u buf[NUMBUFLEN];
1991 char_u *s;
1992
1993 if (item == NULL)
1994 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001995 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996 *p = item->li_next;
1997 return s == NULL ? NULL : vim_strsave(s);
1998}
1999
2000/*
2001 * "execute()" function
2002 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002003 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002004execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002005{
2006 char_u *cmd = NULL;
2007 list_T *list = NULL;
2008 int save_msg_silent = msg_silent;
2009 int save_emsg_silent = emsg_silent;
2010 int save_emsg_noredir = emsg_noredir;
2011 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002012 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002014 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002015 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002016
2017 rettv->vval.v_string = NULL;
2018 rettv->v_type = VAR_STRING;
2019
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002020 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002022 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023 if (list == NULL || list->lv_first == NULL)
2024 /* empty list, no commands, empty output */
2025 return;
2026 ++list->lv_refcount;
2027 }
2028 else
2029 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002030 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002031 if (cmd == NULL)
2032 return;
2033 }
2034
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002035 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002036 {
2037 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002038 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039
2040 if (s == NULL)
2041 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002042 if (*s == NUL)
2043 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002044 if (STRNCMP(s, "silent", 6) == 0)
2045 ++msg_silent;
2046 if (STRCMP(s, "silent!") == 0)
2047 {
2048 emsg_silent = TRUE;
2049 emsg_noredir = TRUE;
2050 }
2051 }
2052 else
2053 ++msg_silent;
2054
2055 if (redir_execute)
2056 save_ga = redir_execute_ga;
2057 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2058 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002059 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002060 if (!echo_output)
2061 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002062
2063 if (cmd != NULL)
2064 do_cmdline_cmd(cmd);
2065 else
2066 {
2067 listitem_T *item = list->lv_first;
2068
2069 do_cmdline(NULL, get_list_line, (void *)&item,
2070 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2071 --list->lv_refcount;
2072 }
2073
Bram Moolenaard297f352017-01-29 20:31:21 +01002074 /* Need to append a NUL to the result. */
2075 if (ga_grow(&redir_execute_ga, 1) == OK)
2076 {
2077 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2078 rettv->vval.v_string = redir_execute_ga.ga_data;
2079 }
2080 else
2081 {
2082 ga_clear(&redir_execute_ga);
2083 rettv->vval.v_string = NULL;
2084 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002085 msg_silent = save_msg_silent;
2086 emsg_silent = save_emsg_silent;
2087 emsg_noredir = save_emsg_noredir;
2088
2089 redir_execute = save_redir_execute;
2090 if (redir_execute)
2091 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002092 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002094 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002095 if (echo_output)
2096 // When not working silently: put it in column zero. A following
2097 // "echon" will overwrite the message, unavoidably.
2098 msg_col = 0;
2099 else
2100 // When working silently: Put it back where it was, since nothing
2101 // should have been written.
2102 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002103}
2104
2105/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002106 * "execute()" function
2107 */
2108 static void
2109f_execute(typval_T *argvars, typval_T *rettv)
2110{
2111 execute_common(argvars, rettv, 0);
2112}
2113
2114/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002115 * "exists()" function
2116 */
2117 static void
2118f_exists(typval_T *argvars, typval_T *rettv)
2119{
2120 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002121 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002123 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002124 if (*p == '$') /* environment variable */
2125 {
2126 /* first try "normal" environment variables (fast) */
2127 if (mch_getenv(p + 1) != NULL)
2128 n = TRUE;
2129 else
2130 {
2131 /* try expanding things like $VIM and ${HOME} */
2132 p = expand_env_save(p);
2133 if (p != NULL && *p != '$')
2134 n = TRUE;
2135 vim_free(p);
2136 }
2137 }
2138 else if (*p == '&' || *p == '+') /* option */
2139 {
2140 n = (get_option_tv(&p, NULL, TRUE) == OK);
2141 if (*skipwhite(p) != NUL)
2142 n = FALSE; /* trailing garbage */
2143 }
2144 else if (*p == '*') /* internal or user defined function */
2145 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002146 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147 }
2148 else if (*p == ':')
2149 {
2150 n = cmd_exists(p + 1);
2151 }
2152 else if (*p == '#')
2153 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 if (p[1] == '#')
2155 n = autocmd_supported(p + 2);
2156 else
2157 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 }
2159 else /* internal variable */
2160 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002161 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162 }
2163
2164 rettv->vval.v_number = n;
2165}
2166
2167#ifdef FEAT_FLOAT
2168/*
2169 * "exp()" function
2170 */
2171 static void
2172f_exp(typval_T *argvars, typval_T *rettv)
2173{
2174 float_T f = 0.0;
2175
2176 rettv->v_type = VAR_FLOAT;
2177 if (get_float_arg(argvars, &f) == OK)
2178 rettv->vval.v_float = exp(f);
2179 else
2180 rettv->vval.v_float = 0.0;
2181}
2182#endif
2183
2184/*
2185 * "expand()" function
2186 */
2187 static void
2188f_expand(typval_T *argvars, typval_T *rettv)
2189{
2190 char_u *s;
2191 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002192 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002193 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2194 expand_T xpc;
2195 int error = FALSE;
2196 char_u *result;
2197
2198 rettv->v_type = VAR_STRING;
2199 if (argvars[1].v_type != VAR_UNKNOWN
2200 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002201 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002202 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002203 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002205 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002206 if (*s == '%' || *s == '#' || *s == '<')
2207 {
2208 ++emsg_off;
2209 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2210 --emsg_off;
2211 if (rettv->v_type == VAR_LIST)
2212 {
2213 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2214 list_append_string(rettv->vval.v_list, result, -1);
2215 else
2216 vim_free(result);
2217 }
2218 else
2219 rettv->vval.v_string = result;
2220 }
2221 else
2222 {
2223 /* When the optional second argument is non-zero, don't remove matches
2224 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2225 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002226 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002227 options |= WILD_KEEP_ALL;
2228 if (!error)
2229 {
2230 ExpandInit(&xpc);
2231 xpc.xp_context = EXPAND_FILES;
2232 if (p_wic)
2233 options += WILD_ICASE;
2234 if (rettv->v_type == VAR_STRING)
2235 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2236 options, WILD_ALL);
2237 else if (rettv_list_alloc(rettv) != FAIL)
2238 {
2239 int i;
2240
2241 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2242 for (i = 0; i < xpc.xp_numfiles; i++)
2243 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2244 ExpandCleanup(&xpc);
2245 }
2246 }
2247 else
2248 rettv->vval.v_string = NULL;
2249 }
2250}
2251
2252/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002253 * "expandcmd()" function
2254 * Expand all the special characters in a command string.
2255 */
2256 static void
2257f_expandcmd(typval_T *argvars, typval_T *rettv)
2258{
2259 exarg_T eap;
2260 char_u *cmdstr;
2261 char *errormsg = NULL;
2262
2263 rettv->v_type = VAR_STRING;
2264 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2265
2266 memset(&eap, 0, sizeof(eap));
2267 eap.cmd = cmdstr;
2268 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002269 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002270 eap.usefilter = FALSE;
2271 eap.nextcmd = NULL;
2272 eap.cmdidx = CMD_USER;
2273
2274 expand_filename(&eap, &cmdstr, &errormsg);
2275 if (errormsg != NULL && *errormsg != NUL)
2276 emsg(errormsg);
2277
2278 rettv->vval.v_string = cmdstr;
2279}
2280
2281/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 * "feedkeys()" function
2283 */
2284 static void
2285f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2286{
2287 int remap = TRUE;
2288 int insert = FALSE;
2289 char_u *keys, *flags;
2290 char_u nbuf[NUMBUFLEN];
2291 int typed = FALSE;
2292 int execute = FALSE;
2293 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002294 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 char_u *keys_esc;
2296
2297 /* This is not allowed in the sandbox. If the commands would still be
2298 * executed in the sandbox it would be OK, but it probably happens later,
2299 * when "sandbox" is no longer set. */
2300 if (check_secure())
2301 return;
2302
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002303 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002304
2305 if (argvars[1].v_type != VAR_UNKNOWN)
2306 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002307 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 for ( ; *flags != NUL; ++flags)
2309 {
2310 switch (*flags)
2311 {
2312 case 'n': remap = FALSE; break;
2313 case 'm': remap = TRUE; break;
2314 case 't': typed = TRUE; break;
2315 case 'i': insert = TRUE; break;
2316 case 'x': execute = TRUE; break;
2317 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002318 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002319 }
2320 }
2321 }
2322
2323 if (*keys != NUL || execute)
2324 {
2325 /* Need to escape K_SPECIAL and CSI before putting the string in the
2326 * typeahead buffer. */
2327 keys_esc = vim_strsave_escape_csi(keys);
2328 if (keys_esc != NULL)
2329 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002330 if (lowlevel)
2331 {
2332#ifdef USE_INPUT_BUF
2333 add_to_input_buf(keys, (int)STRLEN(keys));
2334#else
2335 emsg(_("E980: lowlevel input not supported"));
2336#endif
2337 }
2338 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002339 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002340 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002341 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002342 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002343#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002344 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002345#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002346 )
2347 typebuf_was_filled = TRUE;
2348 }
2349 vim_free(keys_esc);
2350
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002351 if (execute)
2352 {
2353 int save_msg_scroll = msg_scroll;
2354
2355 /* Avoid a 1 second delay when the keys start Insert mode. */
2356 msg_scroll = FALSE;
2357
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002358 if (!dangerous)
2359 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002360 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002361 if (!dangerous)
2362 --ex_normal_busy;
2363
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 msg_scroll |= save_msg_scroll;
2365 }
2366 }
2367 }
2368}
2369
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370#ifdef FEAT_FLOAT
2371/*
2372 * "float2nr({float})" function
2373 */
2374 static void
2375f_float2nr(typval_T *argvars, typval_T *rettv)
2376{
2377 float_T f = 0.0;
2378
2379 if (get_float_arg(argvars, &f) == OK)
2380 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002381 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002382 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002383 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002384 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002385 else
2386 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002387 }
2388}
2389
2390/*
2391 * "floor({float})" function
2392 */
2393 static void
2394f_floor(typval_T *argvars, typval_T *rettv)
2395{
2396 float_T f = 0.0;
2397
2398 rettv->v_type = VAR_FLOAT;
2399 if (get_float_arg(argvars, &f) == OK)
2400 rettv->vval.v_float = floor(f);
2401 else
2402 rettv->vval.v_float = 0.0;
2403}
2404
2405/*
2406 * "fmod()" function
2407 */
2408 static void
2409f_fmod(typval_T *argvars, typval_T *rettv)
2410{
2411 float_T fx = 0.0, fy = 0.0;
2412
2413 rettv->v_type = VAR_FLOAT;
2414 if (get_float_arg(argvars, &fx) == OK
2415 && get_float_arg(&argvars[1], &fy) == OK)
2416 rettv->vval.v_float = fmod(fx, fy);
2417 else
2418 rettv->vval.v_float = 0.0;
2419}
2420#endif
2421
2422/*
2423 * "fnameescape({string})" function
2424 */
2425 static void
2426f_fnameescape(typval_T *argvars, typval_T *rettv)
2427{
2428 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002429 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002430 rettv->v_type = VAR_STRING;
2431}
2432
2433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 * "foreground()" function
2435 */
2436 static void
2437f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2438{
2439#ifdef FEAT_GUI
2440 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002441 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002443 return;
2444 }
2445#endif
2446#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448#endif
2449}
2450
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002452common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002453{
2454 char_u *s;
2455 char_u *name;
2456 int use_string = FALSE;
2457 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002458 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459
2460 if (argvars[0].v_type == VAR_FUNC)
2461 {
2462 /* function(MyFunc, [arg], dict) */
2463 s = argvars[0].vval.v_string;
2464 }
2465 else if (argvars[0].v_type == VAR_PARTIAL
2466 && argvars[0].vval.v_partial != NULL)
2467 {
2468 /* function(dict.MyFunc, [arg]) */
2469 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002470 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002471 }
2472 else
2473 {
2474 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002475 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476 use_string = TRUE;
2477 }
2478
Bram Moolenaar843b8842016-08-21 14:36:15 +02002479 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002480 {
2481 name = s;
2482 trans_name = trans_function_name(&name, FALSE,
2483 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2484 if (*name != NUL)
2485 s = NULL;
2486 }
2487
Bram Moolenaar843b8842016-08-21 14:36:15 +02002488 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2489 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002490 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002491 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002492 else if (trans_name != NULL && (is_funcref
2493 ? find_func(trans_name) == NULL
2494 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002495 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496 else
2497 {
2498 int dict_idx = 0;
2499 int arg_idx = 0;
2500 list_T *list = NULL;
2501
2502 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2503 {
2504 char sid_buf[25];
2505 int off = *s == 's' ? 2 : 5;
2506
2507 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2508 * also be called from another script. Using trans_function_name()
2509 * would also work, but some plugins depend on the name being
2510 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002511 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002512 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002513 if (name != NULL)
2514 {
2515 STRCPY(name, sid_buf);
2516 STRCAT(name, s + off);
2517 }
2518 }
2519 else
2520 name = vim_strsave(s);
2521
2522 if (argvars[1].v_type != VAR_UNKNOWN)
2523 {
2524 if (argvars[2].v_type != VAR_UNKNOWN)
2525 {
2526 /* function(name, [args], dict) */
2527 arg_idx = 1;
2528 dict_idx = 2;
2529 }
2530 else if (argvars[1].v_type == VAR_DICT)
2531 /* function(name, dict) */
2532 dict_idx = 1;
2533 else
2534 /* function(name, [args]) */
2535 arg_idx = 1;
2536 if (dict_idx > 0)
2537 {
2538 if (argvars[dict_idx].v_type != VAR_DICT)
2539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002540 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002542 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 }
2544 if (argvars[dict_idx].vval.v_dict == NULL)
2545 dict_idx = 0;
2546 }
2547 if (arg_idx > 0)
2548 {
2549 if (argvars[arg_idx].v_type != VAR_LIST)
2550 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002551 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002553 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 }
2555 list = argvars[arg_idx].vval.v_list;
2556 if (list == NULL || list->lv_len == 0)
2557 arg_idx = 0;
2558 }
2559 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002560 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002562 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563
2564 /* result is a VAR_PARTIAL */
2565 if (pt == NULL)
2566 vim_free(name);
2567 else
2568 {
2569 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2570 {
2571 listitem_T *li;
2572 int i = 0;
2573 int arg_len = 0;
2574 int lv_len = 0;
2575
2576 if (arg_pt != NULL)
2577 arg_len = arg_pt->pt_argc;
2578 if (list != NULL)
2579 lv_len = list->lv_len;
2580 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002581 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 if (pt->pt_argv == NULL)
2583 {
2584 vim_free(pt);
2585 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002586 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002588 for (i = 0; i < arg_len; i++)
2589 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2590 if (lv_len > 0)
2591 for (li = list->lv_first; li != NULL;
2592 li = li->li_next)
2593 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 }
2595
2596 /* For "function(dict.func, [], dict)" and "func" is a partial
2597 * use "dict". That is backwards compatible. */
2598 if (dict_idx > 0)
2599 {
2600 /* The dict is bound explicitly, pt_auto is FALSE. */
2601 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2602 ++pt->pt_dict->dv_refcount;
2603 }
2604 else if (arg_pt != NULL)
2605 {
2606 /* If the dict was bound automatically the result is also
2607 * bound automatically. */
2608 pt->pt_dict = arg_pt->pt_dict;
2609 pt->pt_auto = arg_pt->pt_auto;
2610 if (pt->pt_dict != NULL)
2611 ++pt->pt_dict->dv_refcount;
2612 }
2613
2614 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002615 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2616 {
2617 pt->pt_func = arg_pt->pt_func;
2618 func_ptr_ref(pt->pt_func);
2619 vim_free(name);
2620 }
2621 else if (is_funcref)
2622 {
2623 pt->pt_func = find_func(trans_name);
2624 func_ptr_ref(pt->pt_func);
2625 vim_free(name);
2626 }
2627 else
2628 {
2629 pt->pt_name = name;
2630 func_ref(name);
2631 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632 }
2633 rettv->v_type = VAR_PARTIAL;
2634 rettv->vval.v_partial = pt;
2635 }
2636 else
2637 {
2638 /* result is a VAR_FUNC */
2639 rettv->v_type = VAR_FUNC;
2640 rettv->vval.v_string = name;
2641 func_ref(name);
2642 }
2643 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644theend:
2645 vim_free(trans_name);
2646}
2647
2648/*
2649 * "funcref()" function
2650 */
2651 static void
2652f_funcref(typval_T *argvars, typval_T *rettv)
2653{
2654 common_function(argvars, rettv, TRUE);
2655}
2656
2657/*
2658 * "function()" function
2659 */
2660 static void
2661f_function(typval_T *argvars, typval_T *rettv)
2662{
2663 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002664}
2665
2666/*
2667 * "garbagecollect()" function
2668 */
2669 static void
2670f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2671{
2672 /* This is postponed until we are back at the toplevel, because we may be
2673 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2674 want_garbage_collect = TRUE;
2675
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002676 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 garbage_collect_at_exit = TRUE;
2678}
2679
2680/*
2681 * "get()" function
2682 */
2683 static void
2684f_get(typval_T *argvars, typval_T *rettv)
2685{
2686 listitem_T *li;
2687 list_T *l;
2688 dictitem_T *di;
2689 dict_T *d;
2690 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002691 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002692
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002693 if (argvars[0].v_type == VAR_BLOB)
2694 {
2695 int error = FALSE;
2696 int idx = tv_get_number_chk(&argvars[1], &error);
2697
2698 if (!error)
2699 {
2700 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002701 if (idx < 0)
2702 idx = blob_len(argvars[0].vval.v_blob) + idx;
2703 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2704 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002705 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002706 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002707 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002708 tv = rettv;
2709 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002710 }
2711 }
2712 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 {
2714 if ((l = argvars[0].vval.v_list) != NULL)
2715 {
2716 int error = FALSE;
2717
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002718 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 if (!error && li != NULL)
2720 tv = &li->li_tv;
2721 }
2722 }
2723 else if (argvars[0].v_type == VAR_DICT)
2724 {
2725 if ((d = argvars[0].vval.v_dict) != NULL)
2726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002727 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 if (di != NULL)
2729 tv = &di->di_tv;
2730 }
2731 }
2732 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2733 {
2734 partial_T *pt;
2735 partial_T fref_pt;
2736
2737 if (argvars[0].v_type == VAR_PARTIAL)
2738 pt = argvars[0].vval.v_partial;
2739 else
2740 {
2741 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2742 fref_pt.pt_name = argvars[0].vval.v_string;
2743 pt = &fref_pt;
2744 }
2745
2746 if (pt != NULL)
2747 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002748 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002749 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002750
2751 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2752 {
2753 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002754 n = partial_name(pt);
2755 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 rettv->vval.v_string = NULL;
2757 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002758 {
2759 rettv->vval.v_string = vim_strsave(n);
2760 if (rettv->v_type == VAR_FUNC)
2761 func_ref(rettv->vval.v_string);
2762 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 }
2764 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002765 {
2766 what_is_dict = TRUE;
2767 if (pt->pt_dict != NULL)
2768 rettv_dict_set(rettv, pt->pt_dict);
2769 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 else if (STRCMP(what, "args") == 0)
2771 {
2772 rettv->v_type = VAR_LIST;
2773 if (rettv_list_alloc(rettv) == OK)
2774 {
2775 int i;
2776
2777 for (i = 0; i < pt->pt_argc; ++i)
2778 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2779 }
2780 }
2781 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002782 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002783
2784 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2785 // third argument
2786 if (!what_is_dict)
2787 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002788 }
2789 }
2790 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002791 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792
2793 if (tv == NULL)
2794 {
2795 if (argvars[2].v_type != VAR_UNKNOWN)
2796 copy_tv(&argvars[2], rettv);
2797 }
2798 else
2799 copy_tv(tv, rettv);
2800}
2801
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002802/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002803 * "getchangelist()" function
2804 */
2805 static void
2806f_getchangelist(typval_T *argvars, typval_T *rettv)
2807{
2808#ifdef FEAT_JUMPLIST
2809 buf_T *buf;
2810 int i;
2811 list_T *l;
2812 dict_T *d;
2813#endif
2814
2815 if (rettv_list_alloc(rettv) != OK)
2816 return;
2817
2818#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002819 if (argvars[0].v_type == VAR_UNKNOWN)
2820 buf = curbuf;
2821 else
2822 {
2823 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2824 ++emsg_off;
2825 buf = tv_get_buf(&argvars[0], FALSE);
2826 --emsg_off;
2827 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002828 if (buf == NULL)
2829 return;
2830
2831 l = list_alloc();
2832 if (l == NULL)
2833 return;
2834
2835 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2836 return;
2837 /*
2838 * The current window change list index tracks only the position in the
2839 * current buffer change list. For other buffers, use the change list
2840 * length as the current index.
2841 */
2842 list_append_number(rettv->vval.v_list,
2843 (varnumber_T)((buf == curwin->w_buffer)
2844 ? curwin->w_changelistidx : buf->b_changelistlen));
2845
2846 for (i = 0; i < buf->b_changelistlen; ++i)
2847 {
2848 if (buf->b_changelist[i].lnum == 0)
2849 continue;
2850 if ((d = dict_alloc()) == NULL)
2851 return;
2852 if (list_append_dict(l, d) == FAIL)
2853 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002854 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2855 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002856 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002857 }
2858#endif
2859}
2860/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002861 * "getchar()" function
2862 */
2863 static void
2864f_getchar(typval_T *argvars, typval_T *rettv)
2865{
2866 varnumber_T n;
2867 int error = FALSE;
2868
Bram Moolenaar84d93902018-09-11 20:10:20 +02002869#ifdef MESSAGE_QUEUE
2870 // vpeekc() used to check for messages, but that caused problems, invoking
2871 // a callback where it was not expected. Some plugins use getchar(1) in a
2872 // loop to await a message, therefore make sure we check for messages here.
2873 parse_queued_messages();
2874#endif
2875
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876 /* Position the cursor. Needed after a message that ends in a space. */
2877 windgoto(msg_row, msg_col);
2878
2879 ++no_mapping;
2880 ++allow_keys;
2881 for (;;)
2882 {
2883 if (argvars[0].v_type == VAR_UNKNOWN)
2884 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01002885 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002886 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002887 /* getchar(1): only check if char avail */
2888 n = vpeekc_any();
2889 else if (error || vpeekc_any() == NUL)
2890 /* illegal argument or getchar(0) and no char avail: return zero */
2891 n = 0;
2892 else
2893 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01002894 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002895
2896 if (n == K_IGNORE)
2897 continue;
2898 break;
2899 }
2900 --no_mapping;
2901 --allow_keys;
2902
2903 set_vim_var_nr(VV_MOUSE_WIN, 0);
2904 set_vim_var_nr(VV_MOUSE_WINID, 0);
2905 set_vim_var_nr(VV_MOUSE_LNUM, 0);
2906 set_vim_var_nr(VV_MOUSE_COL, 0);
2907
2908 rettv->vval.v_number = n;
2909 if (IS_SPECIAL(n) || mod_mask != 0)
2910 {
2911 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
2912 int i = 0;
2913
2914 /* Turn a special key into three bytes, plus modifier. */
2915 if (mod_mask != 0)
2916 {
2917 temp[i++] = K_SPECIAL;
2918 temp[i++] = KS_MODIFIER;
2919 temp[i++] = mod_mask;
2920 }
2921 if (IS_SPECIAL(n))
2922 {
2923 temp[i++] = K_SPECIAL;
2924 temp[i++] = K_SECOND(n);
2925 temp[i++] = K_THIRD(n);
2926 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002927 else if (has_mbyte)
2928 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002929 else
2930 temp[i++] = n;
2931 temp[i++] = NUL;
2932 rettv->v_type = VAR_STRING;
2933 rettv->vval.v_string = vim_strsave(temp);
2934
2935#ifdef FEAT_MOUSE
2936 if (is_mouse_key(n))
2937 {
2938 int row = mouse_row;
2939 int col = mouse_col;
2940 win_T *win;
2941 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002942 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002943 int winnr = 1;
2944
2945 if (row >= 0 && col >= 0)
2946 {
2947 /* Find the window at the mouse coordinates and compute the
2948 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002949 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02002950 if (win == NULL)
2951 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02002952 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002953# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02002954 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002955 winnr = 0;
2956 else
2957# endif
2958 for (wp = firstwin; wp != win && wp != NULL;
2959 wp = wp->w_next)
2960 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002961 set_vim_var_nr(VV_MOUSE_WIN, winnr);
2962 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
2963 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
2964 set_vim_var_nr(VV_MOUSE_COL, col + 1);
2965 }
2966 }
2967#endif
2968 }
2969}
2970
2971/*
2972 * "getcharmod()" function
2973 */
2974 static void
2975f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
2976{
2977 rettv->vval.v_number = mod_mask;
2978}
2979
2980/*
2981 * "getcharsearch()" function
2982 */
2983 static void
2984f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2985{
2986 if (rettv_dict_alloc(rettv) != FAIL)
2987 {
2988 dict_T *dict = rettv->vval.v_dict;
2989
Bram Moolenaare0be1672018-07-08 16:50:37 +02002990 dict_add_string(dict, "char", last_csearch());
2991 dict_add_number(dict, "forward", last_csearch_forward());
2992 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002993 }
2994}
2995
2996/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002997 * "getcmdwintype()" function
2998 */
2999 static void
3000f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
3001{
3002 rettv->v_type = VAR_STRING;
3003 rettv->vval.v_string = NULL;
3004#ifdef FEAT_CMDWIN
3005 rettv->vval.v_string = alloc(2);
3006 if (rettv->vval.v_string != NULL)
3007 {
3008 rettv->vval.v_string[0] = cmdwin_type;
3009 rettv->vval.v_string[1] = NUL;
3010 }
3011#endif
3012}
3013
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003014/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003015 * "getenv()" function
3016 */
3017 static void
3018f_getenv(typval_T *argvars, typval_T *rettv)
3019{
3020 int mustfree = FALSE;
3021 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3022
3023 if (p == NULL)
3024 {
3025 rettv->v_type = VAR_SPECIAL;
3026 rettv->vval.v_number = VVAL_NULL;
3027 return;
3028 }
3029 if (!mustfree)
3030 p = vim_strsave(p);
3031 rettv->vval.v_string = p;
3032 rettv->v_type = VAR_STRING;
3033}
3034
3035/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 * "getfontname()" function
3037 */
3038 static void
3039f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3040{
3041 rettv->v_type = VAR_STRING;
3042 rettv->vval.v_string = NULL;
3043#ifdef FEAT_GUI
3044 if (gui.in_use)
3045 {
3046 GuiFont font;
3047 char_u *name = NULL;
3048
3049 if (argvars[0].v_type == VAR_UNKNOWN)
3050 {
3051 /* Get the "Normal" font. Either the name saved by
3052 * hl_set_font_name() or from the font ID. */
3053 font = gui.norm_font;
3054 name = hl_get_font_name();
3055 }
3056 else
3057 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003058 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059 if (STRCMP(name, "*") == 0) /* don't use font dialog */
3060 return;
3061 font = gui_mch_get_font(name, FALSE);
3062 if (font == NOFONT)
3063 return; /* Invalid font name, return empty string. */
3064 }
3065 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3066 if (argvars[0].v_type != VAR_UNKNOWN)
3067 gui_mch_free_font(font);
3068 }
3069#endif
3070}
3071
3072/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003073 * "getjumplist()" function
3074 */
3075 static void
3076f_getjumplist(typval_T *argvars, typval_T *rettv)
3077{
3078#ifdef FEAT_JUMPLIST
3079 win_T *wp;
3080 int i;
3081 list_T *l;
3082 dict_T *d;
3083#endif
3084
3085 if (rettv_list_alloc(rettv) != OK)
3086 return;
3087
3088#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003089 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003090 if (wp == NULL)
3091 return;
3092
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003093 cleanup_jumplist(wp, TRUE);
3094
Bram Moolenaar4f505882018-02-10 21:06:32 +01003095 l = list_alloc();
3096 if (l == NULL)
3097 return;
3098
3099 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3100 return;
3101 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3102
3103 for (i = 0; i < wp->w_jumplistlen; ++i)
3104 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003105 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3106 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003107 if ((d = dict_alloc()) == NULL)
3108 return;
3109 if (list_append_dict(l, d) == FAIL)
3110 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003111 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3112 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003113 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003114 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003115 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003116 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003117 }
3118#endif
3119}
3120
3121/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003122 * "getpid()" function
3123 */
3124 static void
3125f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3126{
3127 rettv->vval.v_number = mch_get_pid();
3128}
3129
3130 static void
3131getpos_both(
3132 typval_T *argvars,
3133 typval_T *rettv,
3134 int getcurpos)
3135{
3136 pos_T *fp;
3137 list_T *l;
3138 int fnum = -1;
3139
3140 if (rettv_list_alloc(rettv) == OK)
3141 {
3142 l = rettv->vval.v_list;
3143 if (getcurpos)
3144 fp = &curwin->w_cursor;
3145 else
3146 fp = var2fpos(&argvars[0], TRUE, &fnum);
3147 if (fnum != -1)
3148 list_append_number(l, (varnumber_T)fnum);
3149 else
3150 list_append_number(l, (varnumber_T)0);
3151 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3152 : (varnumber_T)0);
3153 list_append_number(l, (fp != NULL)
3154 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3155 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003156 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003157 (varnumber_T)0);
3158 if (getcurpos)
3159 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003160 int save_set_curswant = curwin->w_set_curswant;
3161 colnr_T save_curswant = curwin->w_curswant;
3162 colnr_T save_virtcol = curwin->w_virtcol;
3163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003164 update_curswant();
3165 list_append_number(l, curwin->w_curswant == MAXCOL ?
3166 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003167
3168 // Do not change "curswant", as it is unexpected that a get
3169 // function has a side effect.
3170 if (save_set_curswant)
3171 {
3172 curwin->w_set_curswant = save_set_curswant;
3173 curwin->w_curswant = save_curswant;
3174 curwin->w_virtcol = save_virtcol;
3175 curwin->w_valid &= ~VALID_VIRTCOL;
3176 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003177 }
3178 }
3179 else
3180 rettv->vval.v_number = FALSE;
3181}
3182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003183/*
3184 * "getcurpos()" function
3185 */
3186 static void
3187f_getcurpos(typval_T *argvars, typval_T *rettv)
3188{
3189 getpos_both(argvars, rettv, TRUE);
3190}
3191
3192/*
3193 * "getpos(string)" function
3194 */
3195 static void
3196f_getpos(typval_T *argvars, typval_T *rettv)
3197{
3198 getpos_both(argvars, rettv, FALSE);
3199}
3200
3201/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003202 * "getreg()" function
3203 */
3204 static void
3205f_getreg(typval_T *argvars, typval_T *rettv)
3206{
3207 char_u *strregname;
3208 int regname;
3209 int arg2 = FALSE;
3210 int return_list = FALSE;
3211 int error = FALSE;
3212
3213 if (argvars[0].v_type != VAR_UNKNOWN)
3214 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003215 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216 error = strregname == NULL;
3217 if (argvars[1].v_type != VAR_UNKNOWN)
3218 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003219 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003220 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003221 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003222 }
3223 }
3224 else
3225 strregname = get_vim_var_str(VV_REG);
3226
3227 if (error)
3228 return;
3229
3230 regname = (strregname == NULL ? '"' : *strregname);
3231 if (regname == 0)
3232 regname = '"';
3233
3234 if (return_list)
3235 {
3236 rettv->v_type = VAR_LIST;
3237 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3238 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3239 if (rettv->vval.v_list == NULL)
3240 (void)rettv_list_alloc(rettv);
3241 else
3242 ++rettv->vval.v_list->lv_refcount;
3243 }
3244 else
3245 {
3246 rettv->v_type = VAR_STRING;
3247 rettv->vval.v_string = get_reg_contents(regname,
3248 arg2 ? GREG_EXPR_SRC : 0);
3249 }
3250}
3251
3252/*
3253 * "getregtype()" function
3254 */
3255 static void
3256f_getregtype(typval_T *argvars, typval_T *rettv)
3257{
3258 char_u *strregname;
3259 int regname;
3260 char_u buf[NUMBUFLEN + 2];
3261 long reglen = 0;
3262
3263 if (argvars[0].v_type != VAR_UNKNOWN)
3264 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003265 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003266 if (strregname == NULL) /* type error; errmsg already given */
3267 {
3268 rettv->v_type = VAR_STRING;
3269 rettv->vval.v_string = NULL;
3270 return;
3271 }
3272 }
3273 else
3274 /* Default to v:register */
3275 strregname = get_vim_var_str(VV_REG);
3276
3277 regname = (strregname == NULL ? '"' : *strregname);
3278 if (regname == 0)
3279 regname = '"';
3280
3281 buf[0] = NUL;
3282 buf[1] = NUL;
3283 switch (get_reg_type(regname, &reglen))
3284 {
3285 case MLINE: buf[0] = 'V'; break;
3286 case MCHAR: buf[0] = 'v'; break;
3287 case MBLOCK:
3288 buf[0] = Ctrl_V;
3289 sprintf((char *)buf + 1, "%ld", reglen + 1);
3290 break;
3291 }
3292 rettv->v_type = VAR_STRING;
3293 rettv->vval.v_string = vim_strsave(buf);
3294}
3295
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003296/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003297 * "gettagstack()" function
3298 */
3299 static void
3300f_gettagstack(typval_T *argvars, typval_T *rettv)
3301{
3302 win_T *wp = curwin; // default is current window
3303
3304 if (rettv_dict_alloc(rettv) != OK)
3305 return;
3306
3307 if (argvars[0].v_type != VAR_UNKNOWN)
3308 {
3309 wp = find_win_by_nr_or_id(&argvars[0]);
3310 if (wp == NULL)
3311 return;
3312 }
3313
3314 get_tagstack(wp, rettv->vval.v_dict);
3315}
3316
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317/* for VIM_VERSION_ defines */
3318#include "version.h"
3319
3320/*
3321 * "has()" function
3322 */
3323 static void
3324f_has(typval_T *argvars, typval_T *rettv)
3325{
3326 int i;
3327 char_u *name;
3328 int n = FALSE;
3329 static char *(has_list[]) =
3330 {
3331#ifdef AMIGA
3332 "amiga",
3333# ifdef FEAT_ARP
3334 "arp",
3335# endif
3336#endif
3337#ifdef __BEOS__
3338 "beos",
3339#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003340#if defined(BSD) && !defined(MACOS_X)
3341 "bsd",
3342#endif
3343#ifdef hpux
3344 "hpux",
3345#endif
3346#ifdef __linux__
3347 "linux",
3348#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003349#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003350 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3351 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003352# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003353 "macunix", /* Mac OS X, with the darwin feature */
3354 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003355# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003356#endif
3357#ifdef __QNX__
3358 "qnx",
3359#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003360#ifdef SUN_SYSTEM
3361 "sun",
3362#else
3363 "moon",
3364#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003365#ifdef UNIX
3366 "unix",
3367#endif
3368#ifdef VMS
3369 "vms",
3370#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003371#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003372 "win32",
3373#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003374#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003375 "win32unix",
3376#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003377#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378 "win64",
3379#endif
3380#ifdef EBCDIC
3381 "ebcdic",
3382#endif
3383#ifndef CASE_INSENSITIVE_FILENAME
3384 "fname_case",
3385#endif
3386#ifdef HAVE_ACL
3387 "acl",
3388#endif
3389#ifdef FEAT_ARABIC
3390 "arabic",
3391#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003393#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003394 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003395#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003396#ifdef FEAT_AUTOSERVERNAME
3397 "autoservername",
3398#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003399#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003401# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003402 "balloon_multiline",
3403# endif
3404#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003405#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003406 "balloon_eval_term",
3407#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003408#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3409 "builtin_terms",
3410# ifdef ALL_BUILTIN_TCAPS
3411 "all_builtin_terms",
3412# endif
3413#endif
3414#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003415 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003416 || defined(FEAT_GUI_MOTIF))
3417 "browsefilter",
3418#endif
3419#ifdef FEAT_BYTEOFF
3420 "byte_offset",
3421#endif
3422#ifdef FEAT_JOB_CHANNEL
3423 "channel",
3424#endif
3425#ifdef FEAT_CINDENT
3426 "cindent",
3427#endif
3428#ifdef FEAT_CLIENTSERVER
3429 "clientserver",
3430#endif
3431#ifdef FEAT_CLIPBOARD
3432 "clipboard",
3433#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436#ifdef FEAT_COMMENTS
3437 "comments",
3438#endif
3439#ifdef FEAT_CONCEAL
3440 "conceal",
3441#endif
3442#ifdef FEAT_CRYPT
3443 "cryptv",
3444 "crypt-blowfish",
3445 "crypt-blowfish2",
3446#endif
3447#ifdef FEAT_CSCOPE
3448 "cscope",
3449#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003450 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003451#ifdef CURSOR_SHAPE
3452 "cursorshape",
3453#endif
3454#ifdef DEBUG
3455 "debug",
3456#endif
3457#ifdef FEAT_CON_DIALOG
3458 "dialog_con",
3459#endif
3460#ifdef FEAT_GUI_DIALOG
3461 "dialog_gui",
3462#endif
3463#ifdef FEAT_DIFF
3464 "diff",
3465#endif
3466#ifdef FEAT_DIGRAPHS
3467 "digraphs",
3468#endif
3469#ifdef FEAT_DIRECTX
3470 "directx",
3471#endif
3472#ifdef FEAT_DND
3473 "dnd",
3474#endif
3475#ifdef FEAT_EMACS_TAGS
3476 "emacs_tags",
3477#endif
3478 "eval", /* always present, of course! */
3479 "ex_extra", /* graduated feature */
3480#ifdef FEAT_SEARCH_EXTRA
3481 "extra_search",
3482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483#ifdef FEAT_SEARCHPATH
3484 "file_in_path",
3485#endif
3486#ifdef FEAT_FILTERPIPE
3487 "filterpipe",
3488#endif
3489#ifdef FEAT_FIND_ID
3490 "find_in_path",
3491#endif
3492#ifdef FEAT_FLOAT
3493 "float",
3494#endif
3495#ifdef FEAT_FOLDING
3496 "folding",
3497#endif
3498#ifdef FEAT_FOOTER
3499 "footer",
3500#endif
3501#if !defined(USE_SYSTEM) && defined(UNIX)
3502 "fork",
3503#endif
3504#ifdef FEAT_GETTEXT
3505 "gettext",
3506#endif
3507#ifdef FEAT_GUI
3508 "gui",
3509#endif
3510#ifdef FEAT_GUI_ATHENA
3511# ifdef FEAT_GUI_NEXTAW
3512 "gui_neXtaw",
3513# else
3514 "gui_athena",
3515# endif
3516#endif
3517#ifdef FEAT_GUI_GTK
3518 "gui_gtk",
3519# ifdef USE_GTK3
3520 "gui_gtk3",
3521# else
3522 "gui_gtk2",
3523# endif
3524#endif
3525#ifdef FEAT_GUI_GNOME
3526 "gui_gnome",
3527#endif
3528#ifdef FEAT_GUI_MAC
3529 "gui_mac",
3530#endif
3531#ifdef FEAT_GUI_MOTIF
3532 "gui_motif",
3533#endif
3534#ifdef FEAT_GUI_PHOTON
3535 "gui_photon",
3536#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003537#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003538 "gui_win32",
3539#endif
3540#ifdef FEAT_HANGULIN
3541 "hangul_input",
3542#endif
3543#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3544 "iconv",
3545#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003547#ifdef FEAT_JOB_CHANNEL
3548 "job",
3549#endif
3550#ifdef FEAT_JUMPLIST
3551 "jumplist",
3552#endif
3553#ifdef FEAT_KEYMAP
3554 "keymap",
3555#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003556 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003557#ifdef FEAT_LANGMAP
3558 "langmap",
3559#endif
3560#ifdef FEAT_LIBCALL
3561 "libcall",
3562#endif
3563#ifdef FEAT_LINEBREAK
3564 "linebreak",
3565#endif
3566#ifdef FEAT_LISP
3567 "lispindent",
3568#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003571#ifdef FEAT_LUA
3572# ifndef DYNAMIC_LUA
3573 "lua",
3574# endif
3575#endif
3576#ifdef FEAT_MENU
3577 "menu",
3578#endif
3579#ifdef FEAT_SESSION
3580 "mksession",
3581#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003583#ifdef FEAT_MOUSE
3584 "mouse",
3585#endif
3586#ifdef FEAT_MOUSESHAPE
3587 "mouseshape",
3588#endif
3589#if defined(UNIX) || defined(VMS)
3590# ifdef FEAT_MOUSE_DEC
3591 "mouse_dec",
3592# endif
3593# ifdef FEAT_MOUSE_GPM
3594 "mouse_gpm",
3595# endif
3596# ifdef FEAT_MOUSE_JSB
3597 "mouse_jsbterm",
3598# endif
3599# ifdef FEAT_MOUSE_NET
3600 "mouse_netterm",
3601# endif
3602# ifdef FEAT_MOUSE_PTERM
3603 "mouse_pterm",
3604# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003605# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003606 "mouse_sgr",
3607# endif
3608# ifdef FEAT_SYSMOUSE
3609 "mouse_sysmouse",
3610# endif
3611# ifdef FEAT_MOUSE_URXVT
3612 "mouse_urxvt",
3613# endif
3614# ifdef FEAT_MOUSE_XTERM
3615 "mouse_xterm",
3616# endif
3617#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003618 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003619#ifdef FEAT_MBYTE_IME
3620 "multi_byte_ime",
3621#endif
3622#ifdef FEAT_MULTI_LANG
3623 "multi_lang",
3624#endif
3625#ifdef FEAT_MZSCHEME
3626#ifndef DYNAMIC_MZSCHEME
3627 "mzscheme",
3628#endif
3629#endif
3630#ifdef FEAT_NUM64
3631 "num64",
3632#endif
3633#ifdef FEAT_OLE
3634 "ole",
3635#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003636#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003638#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003639#ifdef FEAT_PATH_EXTRA
3640 "path_extra",
3641#endif
3642#ifdef FEAT_PERL
3643#ifndef DYNAMIC_PERL
3644 "perl",
3645#endif
3646#endif
3647#ifdef FEAT_PERSISTENT_UNDO
3648 "persistent_undo",
3649#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003650#if defined(FEAT_PYTHON)
3651 "python_compiled",
3652# if defined(DYNAMIC_PYTHON)
3653 "python_dynamic",
3654# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003655 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003656 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003657# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003658#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003659#if defined(FEAT_PYTHON3)
3660 "python3_compiled",
3661# if defined(DYNAMIC_PYTHON3)
3662 "python3_dynamic",
3663# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003664 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003665 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003666# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003667#endif
3668#ifdef FEAT_POSTSCRIPT
3669 "postscript",
3670#endif
3671#ifdef FEAT_PRINTER
3672 "printer",
3673#endif
3674#ifdef FEAT_PROFILE
3675 "profile",
3676#endif
3677#ifdef FEAT_RELTIME
3678 "reltime",
3679#endif
3680#ifdef FEAT_QUICKFIX
3681 "quickfix",
3682#endif
3683#ifdef FEAT_RIGHTLEFT
3684 "rightleft",
3685#endif
3686#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3687 "ruby",
3688#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003689 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003690#ifdef FEAT_CMDL_INFO
3691 "showcmd",
3692 "cmdline_info",
3693#endif
3694#ifdef FEAT_SIGNS
3695 "signs",
3696#endif
3697#ifdef FEAT_SMARTINDENT
3698 "smartindent",
3699#endif
3700#ifdef STARTUPTIME
3701 "startuptime",
3702#endif
3703#ifdef FEAT_STL_OPT
3704 "statusline",
3705#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003706#ifdef FEAT_NETBEANS_INTG
3707 "netbeans_intg",
3708#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003709#ifdef FEAT_SOUND
3710 "sound",
3711#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003712#ifdef FEAT_SPELL
3713 "spell",
3714#endif
3715#ifdef FEAT_SYN_HL
3716 "syntax",
3717#endif
3718#if defined(USE_SYSTEM) || !defined(UNIX)
3719 "system",
3720#endif
3721#ifdef FEAT_TAG_BINS
3722 "tag_binary",
3723#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003724#ifdef FEAT_TCL
3725# ifndef DYNAMIC_TCL
3726 "tcl",
3727# endif
3728#endif
3729#ifdef FEAT_TERMGUICOLORS
3730 "termguicolors",
3731#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003732#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003733 "terminal",
3734#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735#ifdef TERMINFO
3736 "terminfo",
3737#endif
3738#ifdef FEAT_TERMRESPONSE
3739 "termresponse",
3740#endif
3741#ifdef FEAT_TEXTOBJ
3742 "textobjects",
3743#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003744#ifdef FEAT_TEXT_PROP
3745 "textprop",
3746#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747#ifdef HAVE_TGETENT
3748 "tgetent",
3749#endif
3750#ifdef FEAT_TIMERS
3751 "timers",
3752#endif
3753#ifdef FEAT_TITLE
3754 "title",
3755#endif
3756#ifdef FEAT_TOOLBAR
3757 "toolbar",
3758#endif
3759#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3760 "unnamedplus",
3761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003762 "user-commands", /* was accidentally included in 5.4 */
3763 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003764#ifdef FEAT_VARTABS
3765 "vartabs",
3766#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003767 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003768#ifdef FEAT_VIMINFO
3769 "viminfo",
3770#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003771 "vimscript-1",
3772 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003773 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003774 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003776 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003778 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003779#ifdef FEAT_VTP
3780 "vtp",
3781#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003782#ifdef FEAT_WILDIGN
3783 "wildignore",
3784#endif
3785#ifdef FEAT_WILDMENU
3786 "wildmenu",
3787#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003788 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003789#ifdef FEAT_WAK
3790 "winaltkeys",
3791#endif
3792#ifdef FEAT_WRITEBACKUP
3793 "writebackup",
3794#endif
3795#ifdef FEAT_XIM
3796 "xim",
3797#endif
3798#ifdef FEAT_XFONTSET
3799 "xfontset",
3800#endif
3801#ifdef FEAT_XPM_W32
3802 "xpm",
3803 "xpm_w32", /* for backward compatibility */
3804#else
3805# if defined(HAVE_XPM)
3806 "xpm",
3807# endif
3808#endif
3809#ifdef USE_XSMP
3810 "xsmp",
3811#endif
3812#ifdef USE_XSMP_INTERACT
3813 "xsmp_interact",
3814#endif
3815#ifdef FEAT_XCLIPBOARD
3816 "xterm_clipboard",
3817#endif
3818#ifdef FEAT_XTERM_SAVE
3819 "xterm_save",
3820#endif
3821#if defined(UNIX) && defined(FEAT_X11)
3822 "X11",
3823#endif
3824 NULL
3825 };
3826
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003827 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003828 for (i = 0; has_list[i] != NULL; ++i)
3829 if (STRICMP(name, has_list[i]) == 0)
3830 {
3831 n = TRUE;
3832 break;
3833 }
3834
3835 if (n == FALSE)
3836 {
3837 if (STRNICMP(name, "patch", 5) == 0)
3838 {
3839 if (name[5] == '-'
3840 && STRLEN(name) >= 11
3841 && vim_isdigit(name[6])
3842 && vim_isdigit(name[8])
3843 && vim_isdigit(name[10]))
3844 {
3845 int major = atoi((char *)name + 6);
3846 int minor = atoi((char *)name + 8);
3847
3848 /* Expect "patch-9.9.01234". */
3849 n = (major < VIM_VERSION_MAJOR
3850 || (major == VIM_VERSION_MAJOR
3851 && (minor < VIM_VERSION_MINOR
3852 || (minor == VIM_VERSION_MINOR
3853 && has_patch(atoi((char *)name + 10))))));
3854 }
3855 else
3856 n = has_patch(atoi((char *)name + 5));
3857 }
3858 else if (STRICMP(name, "vim_starting") == 0)
3859 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003860 else if (STRICMP(name, "ttyin") == 0)
3861 n = mch_input_isatty();
3862 else if (STRICMP(name, "ttyout") == 0)
3863 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 else if (STRICMP(name, "multi_byte_encoding") == 0)
3865 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003866#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003867 else if (STRICMP(name, "balloon_multiline") == 0)
3868 n = multiline_balloon_available();
3869#endif
3870#ifdef DYNAMIC_TCL
3871 else if (STRICMP(name, "tcl") == 0)
3872 n = tcl_enabled(FALSE);
3873#endif
3874#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3875 else if (STRICMP(name, "iconv") == 0)
3876 n = iconv_enabled(FALSE);
3877#endif
3878#ifdef DYNAMIC_LUA
3879 else if (STRICMP(name, "lua") == 0)
3880 n = lua_enabled(FALSE);
3881#endif
3882#ifdef DYNAMIC_MZSCHEME
3883 else if (STRICMP(name, "mzscheme") == 0)
3884 n = mzscheme_enabled(FALSE);
3885#endif
3886#ifdef DYNAMIC_RUBY
3887 else if (STRICMP(name, "ruby") == 0)
3888 n = ruby_enabled(FALSE);
3889#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003890#ifdef DYNAMIC_PYTHON
3891 else if (STRICMP(name, "python") == 0)
3892 n = python_enabled(FALSE);
3893#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003894#ifdef DYNAMIC_PYTHON3
3895 else if (STRICMP(name, "python3") == 0)
3896 n = python3_enabled(FALSE);
3897#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003898#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3899 else if (STRICMP(name, "pythonx") == 0)
3900 {
3901# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3902 if (p_pyx == 0)
3903 n = python3_enabled(FALSE) || python_enabled(FALSE);
3904 else if (p_pyx == 3)
3905 n = python3_enabled(FALSE);
3906 else if (p_pyx == 2)
3907 n = python_enabled(FALSE);
3908# elif defined(DYNAMIC_PYTHON)
3909 n = python_enabled(FALSE);
3910# elif defined(DYNAMIC_PYTHON3)
3911 n = python3_enabled(FALSE);
3912# endif
3913 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003914#endif
3915#ifdef DYNAMIC_PERL
3916 else if (STRICMP(name, "perl") == 0)
3917 n = perl_enabled(FALSE);
3918#endif
3919#ifdef FEAT_GUI
3920 else if (STRICMP(name, "gui_running") == 0)
3921 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003922# ifdef FEAT_BROWSE
3923 else if (STRICMP(name, "browse") == 0)
3924 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3925# endif
3926#endif
3927#ifdef FEAT_SYN_HL
3928 else if (STRICMP(name, "syntax_items") == 0)
3929 n = syntax_present(curwin);
3930#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003931#ifdef FEAT_VTP
3932 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003933 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934#endif
3935#ifdef FEAT_NETBEANS_INTG
3936 else if (STRICMP(name, "netbeans_enabled") == 0)
3937 n = netbeans_active();
3938#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003939#ifdef FEAT_MOUSE_GPM
3940 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3941 n = gpm_enabled();
3942#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003943#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003944 else if (STRICMP(name, "terminal") == 0)
3945 n = terminal_enabled();
3946#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003947#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003948 else if (STRICMP(name, "conpty") == 0)
3949 n = use_conpty();
3950#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003951#ifdef FEAT_CLIPBOARD
3952 else if (STRICMP(name, "clipboard_working") == 0)
3953 n = clip_star.available;
3954#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003955 }
3956
3957 rettv->vval.v_number = n;
3958}
3959
3960/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003961 * "haslocaldir()" function
3962 */
3963 static void
3964f_haslocaldir(typval_T *argvars, typval_T *rettv)
3965{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003966 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003967 win_T *wp = NULL;
3968
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003969 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3970
3971 // Check for window-local and tab-local directories
3972 if (wp != NULL && wp->w_localdir != NULL)
3973 rettv->vval.v_number = 1;
3974 else if (tp != NULL && tp->tp_localdir != NULL)
3975 rettv->vval.v_number = 2;
3976 else
3977 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003978}
3979
3980/*
3981 * "hasmapto()" function
3982 */
3983 static void
3984f_hasmapto(typval_T *argvars, typval_T *rettv)
3985{
3986 char_u *name;
3987 char_u *mode;
3988 char_u buf[NUMBUFLEN];
3989 int abbr = FALSE;
3990
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003991 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003992 if (argvars[1].v_type == VAR_UNKNOWN)
3993 mode = (char_u *)"nvo";
3994 else
3995 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003996 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003997 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003998 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003999 }
4000
4001 if (map_to_exists(name, mode, abbr))
4002 rettv->vval.v_number = TRUE;
4003 else
4004 rettv->vval.v_number = FALSE;
4005}
4006
4007/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004008 * "highlightID(name)" function
4009 */
4010 static void
4011f_hlID(typval_T *argvars, typval_T *rettv)
4012{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004013 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004014}
4015
4016/*
4017 * "highlight_exists()" function
4018 */
4019 static void
4020f_hlexists(typval_T *argvars, typval_T *rettv)
4021{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004022 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023}
4024
4025/*
4026 * "hostname()" function
4027 */
4028 static void
4029f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4030{
4031 char_u hostname[256];
4032
4033 mch_get_host_name(hostname, 256);
4034 rettv->v_type = VAR_STRING;
4035 rettv->vval.v_string = vim_strsave(hostname);
4036}
4037
4038/*
4039 * iconv() function
4040 */
4041 static void
4042f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4043{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044 char_u buf1[NUMBUFLEN];
4045 char_u buf2[NUMBUFLEN];
4046 char_u *from, *to, *str;
4047 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004048
4049 rettv->v_type = VAR_STRING;
4050 rettv->vval.v_string = NULL;
4051
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004052 str = tv_get_string(&argvars[0]);
4053 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4054 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004055 vimconv.vc_type = CONV_NONE;
4056 convert_setup(&vimconv, from, to);
4057
4058 /* If the encodings are equal, no conversion needed. */
4059 if (vimconv.vc_type == CONV_NONE)
4060 rettv->vval.v_string = vim_strsave(str);
4061 else
4062 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4063
4064 convert_setup(&vimconv, NULL, NULL);
4065 vim_free(from);
4066 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004067}
4068
4069/*
4070 * "indent()" function
4071 */
4072 static void
4073f_indent(typval_T *argvars, typval_T *rettv)
4074{
4075 linenr_T lnum;
4076
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004077 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4079 rettv->vval.v_number = get_indent_lnum(lnum);
4080 else
4081 rettv->vval.v_number = -1;
4082}
4083
4084/*
4085 * "index()" function
4086 */
4087 static void
4088f_index(typval_T *argvars, typval_T *rettv)
4089{
4090 list_T *l;
4091 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004092 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004093 long idx = 0;
4094 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004095 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004096
4097 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004098 if (argvars[0].v_type == VAR_BLOB)
4099 {
4100 typval_T tv;
4101 int start = 0;
4102
4103 if (argvars[2].v_type != VAR_UNKNOWN)
4104 {
4105 start = tv_get_number_chk(&argvars[2], &error);
4106 if (error)
4107 return;
4108 }
4109 b = argvars[0].vval.v_blob;
4110 if (b == NULL)
4111 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004112 if (start < 0)
4113 {
4114 start = blob_len(b) + start;
4115 if (start < 0)
4116 start = 0;
4117 }
4118
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004119 for (idx = start; idx < blob_len(b); ++idx)
4120 {
4121 tv.v_type = VAR_NUMBER;
4122 tv.vval.v_number = blob_get(b, idx);
4123 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4124 {
4125 rettv->vval.v_number = idx;
4126 return;
4127 }
4128 }
4129 return;
4130 }
4131 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004132 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004133 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134 return;
4135 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004136
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004137 l = argvars[0].vval.v_list;
4138 if (l != NULL)
4139 {
4140 item = l->lv_first;
4141 if (argvars[2].v_type != VAR_UNKNOWN)
4142 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004143 /* Start at specified item. Use the cached index that list_find()
4144 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004145 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004146 idx = l->lv_idx;
4147 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004148 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004149 if (error)
4150 item = NULL;
4151 }
4152
4153 for ( ; item != NULL; item = item->li_next, ++idx)
4154 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4155 {
4156 rettv->vval.v_number = idx;
4157 break;
4158 }
4159 }
4160}
4161
4162static int inputsecret_flag = 0;
4163
4164/*
4165 * "input()" function
4166 * Also handles inputsecret() when inputsecret is set.
4167 */
4168 static void
4169f_input(typval_T *argvars, typval_T *rettv)
4170{
4171 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4172}
4173
4174/*
4175 * "inputdialog()" function
4176 */
4177 static void
4178f_inputdialog(typval_T *argvars, typval_T *rettv)
4179{
4180#if defined(FEAT_GUI_TEXTDIALOG)
4181 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4182 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4183 {
4184 char_u *message;
4185 char_u buf[NUMBUFLEN];
4186 char_u *defstr = (char_u *)"";
4187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004188 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004189 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004190 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004191 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4192 else
4193 IObuff[0] = NUL;
4194 if (message != NULL && defstr != NULL
4195 && do_dialog(VIM_QUESTION, NULL, message,
4196 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4197 rettv->vval.v_string = vim_strsave(IObuff);
4198 else
4199 {
4200 if (message != NULL && defstr != NULL
4201 && argvars[1].v_type != VAR_UNKNOWN
4202 && argvars[2].v_type != VAR_UNKNOWN)
4203 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004204 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004205 else
4206 rettv->vval.v_string = NULL;
4207 }
4208 rettv->v_type = VAR_STRING;
4209 }
4210 else
4211#endif
4212 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4213}
4214
4215/*
4216 * "inputlist()" function
4217 */
4218 static void
4219f_inputlist(typval_T *argvars, typval_T *rettv)
4220{
4221 listitem_T *li;
4222 int selected;
4223 int mouse_used;
4224
4225#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004226 /* While starting up, there is no place to enter text. When running tests
4227 * with --not-a-term we assume feedkeys() will be used. */
4228 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004229 return;
4230#endif
4231 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4232 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004233 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004234 return;
4235 }
4236
4237 msg_start();
4238 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4239 lines_left = Rows; /* avoid more prompt */
4240 msg_scroll = TRUE;
4241 msg_clr_eos();
4242
4243 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4244 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004245 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004246 msg_putchar('\n');
4247 }
4248
4249 /* Ask for choice. */
4250 selected = prompt_for_number(&mouse_used);
4251 if (mouse_used)
4252 selected -= lines_left;
4253
4254 rettv->vval.v_number = selected;
4255}
4256
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004257static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4258
4259/*
4260 * "inputrestore()" function
4261 */
4262 static void
4263f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4264{
4265 if (ga_userinput.ga_len > 0)
4266 {
4267 --ga_userinput.ga_len;
4268 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4269 + ga_userinput.ga_len);
4270 /* default return is zero == OK */
4271 }
4272 else if (p_verbose > 1)
4273 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004274 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004275 rettv->vval.v_number = 1; /* Failed */
4276 }
4277}
4278
4279/*
4280 * "inputsave()" function
4281 */
4282 static void
4283f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4284{
4285 /* Add an entry to the stack of typeahead storage. */
4286 if (ga_grow(&ga_userinput, 1) == OK)
4287 {
4288 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4289 + ga_userinput.ga_len);
4290 ++ga_userinput.ga_len;
4291 /* default return is zero == OK */
4292 }
4293 else
4294 rettv->vval.v_number = 1; /* Failed */
4295}
4296
4297/*
4298 * "inputsecret()" function
4299 */
4300 static void
4301f_inputsecret(typval_T *argvars, typval_T *rettv)
4302{
4303 ++cmdline_star;
4304 ++inputsecret_flag;
4305 f_input(argvars, rettv);
4306 --cmdline_star;
4307 --inputsecret_flag;
4308}
4309
4310/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004311 * "invert(expr)" function
4312 */
4313 static void
4314f_invert(typval_T *argvars, typval_T *rettv)
4315{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004316 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004317}
4318
4319/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004320 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4321 * or it refers to a List or Dictionary that is locked.
4322 */
4323 static int
4324tv_islocked(typval_T *tv)
4325{
4326 return (tv->v_lock & VAR_LOCKED)
4327 || (tv->v_type == VAR_LIST
4328 && tv->vval.v_list != NULL
4329 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4330 || (tv->v_type == VAR_DICT
4331 && tv->vval.v_dict != NULL
4332 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4333}
4334
4335/*
4336 * "islocked()" function
4337 */
4338 static void
4339f_islocked(typval_T *argvars, typval_T *rettv)
4340{
4341 lval_T lv;
4342 char_u *end;
4343 dictitem_T *di;
4344
4345 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004346 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004347 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004348 if (end != NULL && lv.ll_name != NULL)
4349 {
4350 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004351 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004352 else
4353 {
4354 if (lv.ll_tv == NULL)
4355 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004356 di = find_var(lv.ll_name, NULL, TRUE);
4357 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004358 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004359 /* Consider a variable locked when:
4360 * 1. the variable itself is locked
4361 * 2. the value of the variable is locked.
4362 * 3. the List or Dict value is locked.
4363 */
4364 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4365 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004366 }
4367 }
4368 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004369 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004370 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004371 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004372 else if (lv.ll_list != NULL)
4373 /* List item. */
4374 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4375 else
4376 /* Dictionary item. */
4377 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4378 }
4379 }
4380
4381 clear_lval(&lv);
4382}
4383
4384#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4385/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004386 * "isinf()" function
4387 */
4388 static void
4389f_isinf(typval_T *argvars, typval_T *rettv)
4390{
4391 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4392 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4393}
4394
4395/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004396 * "isnan()" function
4397 */
4398 static void
4399f_isnan(typval_T *argvars, typval_T *rettv)
4400{
4401 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4402 && isnan(argvars[0].vval.v_float);
4403}
4404#endif
4405
4406/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004407 * "last_buffer_nr()" function.
4408 */
4409 static void
4410f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4411{
4412 int n = 0;
4413 buf_T *buf;
4414
Bram Moolenaar29323592016-07-24 22:04:11 +02004415 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416 if (n < buf->b_fnum)
4417 n = buf->b_fnum;
4418
4419 rettv->vval.v_number = n;
4420}
4421
4422/*
4423 * "len()" function
4424 */
4425 static void
4426f_len(typval_T *argvars, typval_T *rettv)
4427{
4428 switch (argvars[0].v_type)
4429 {
4430 case VAR_STRING:
4431 case VAR_NUMBER:
4432 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004433 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004434 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004435 case VAR_BLOB:
4436 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4437 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004438 case VAR_LIST:
4439 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4440 break;
4441 case VAR_DICT:
4442 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4443 break;
4444 case VAR_UNKNOWN:
4445 case VAR_SPECIAL:
4446 case VAR_FLOAT:
4447 case VAR_FUNC:
4448 case VAR_PARTIAL:
4449 case VAR_JOB:
4450 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004451 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004452 break;
4453 }
4454}
4455
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004456 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004457libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004458{
4459#ifdef FEAT_LIBCALL
4460 char_u *string_in;
4461 char_u **string_result;
4462 int nr_result;
4463#endif
4464
4465 rettv->v_type = type;
4466 if (type != VAR_NUMBER)
4467 rettv->vval.v_string = NULL;
4468
4469 if (check_restricted() || check_secure())
4470 return;
4471
4472#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004473 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4475 {
4476 string_in = NULL;
4477 if (argvars[2].v_type == VAR_STRING)
4478 string_in = argvars[2].vval.v_string;
4479 if (type == VAR_NUMBER)
4480 string_result = NULL;
4481 else
4482 string_result = &rettv->vval.v_string;
4483 if (mch_libcall(argvars[0].vval.v_string,
4484 argvars[1].vval.v_string,
4485 string_in,
4486 argvars[2].vval.v_number,
4487 string_result,
4488 &nr_result) == OK
4489 && type == VAR_NUMBER)
4490 rettv->vval.v_number = nr_result;
4491 }
4492#endif
4493}
4494
4495/*
4496 * "libcall()" function
4497 */
4498 static void
4499f_libcall(typval_T *argvars, typval_T *rettv)
4500{
4501 libcall_common(argvars, rettv, VAR_STRING);
4502}
4503
4504/*
4505 * "libcallnr()" function
4506 */
4507 static void
4508f_libcallnr(typval_T *argvars, typval_T *rettv)
4509{
4510 libcall_common(argvars, rettv, VAR_NUMBER);
4511}
4512
4513/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004514 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004515 */
4516 static void
4517f_line(typval_T *argvars, typval_T *rettv)
4518{
4519 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004520 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004521 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004522 int id;
4523 tabpage_T *tp;
4524 win_T *wp;
4525 win_T *save_curwin;
4526 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004527
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004528 if (argvars[1].v_type != VAR_UNKNOWN)
4529 {
4530 // use window specified in the second argument
4531 id = (int)tv_get_number(&argvars[1]);
4532 wp = win_id2wp_tp(id, &tp);
4533 if (wp != NULL && tp != NULL)
4534 {
4535 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4536 == OK)
4537 {
4538 check_cursor();
4539 fp = var2fpos(&argvars[0], TRUE, &fnum);
4540 }
4541 restore_win_noblock(save_curwin, save_curtab, TRUE);
4542 }
4543 }
4544 else
4545 // use current window
4546 fp = var2fpos(&argvars[0], TRUE, &fnum);
4547
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004548 if (fp != NULL)
4549 lnum = fp->lnum;
4550 rettv->vval.v_number = lnum;
4551}
4552
4553/*
4554 * "line2byte(lnum)" function
4555 */
4556 static void
4557f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4558{
4559#ifndef FEAT_BYTEOFF
4560 rettv->vval.v_number = -1;
4561#else
4562 linenr_T lnum;
4563
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004564 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004565 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4566 rettv->vval.v_number = -1;
4567 else
4568 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4569 if (rettv->vval.v_number >= 0)
4570 ++rettv->vval.v_number;
4571#endif
4572}
4573
4574/*
4575 * "lispindent(lnum)" function
4576 */
4577 static void
4578f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
4579{
4580#ifdef FEAT_LISP
4581 pos_T pos;
4582 linenr_T lnum;
4583
4584 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004585 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004586 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4587 {
4588 curwin->w_cursor.lnum = lnum;
4589 rettv->vval.v_number = get_lisp_indent();
4590 curwin->w_cursor = pos;
4591 }
4592 else
4593#endif
4594 rettv->vval.v_number = -1;
4595}
4596
4597/*
4598 * "localtime()" function
4599 */
4600 static void
4601f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4602{
4603 rettv->vval.v_number = (varnumber_T)time(NULL);
4604}
4605
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004606#ifdef FEAT_FLOAT
4607/*
4608 * "log()" function
4609 */
4610 static void
4611f_log(typval_T *argvars, typval_T *rettv)
4612{
4613 float_T f = 0.0;
4614
4615 rettv->v_type = VAR_FLOAT;
4616 if (get_float_arg(argvars, &f) == OK)
4617 rettv->vval.v_float = log(f);
4618 else
4619 rettv->vval.v_float = 0.0;
4620}
4621
4622/*
4623 * "log10()" function
4624 */
4625 static void
4626f_log10(typval_T *argvars, typval_T *rettv)
4627{
4628 float_T f = 0.0;
4629
4630 rettv->v_type = VAR_FLOAT;
4631 if (get_float_arg(argvars, &f) == OK)
4632 rettv->vval.v_float = log10(f);
4633 else
4634 rettv->vval.v_float = 0.0;
4635}
4636#endif
4637
4638#ifdef FEAT_LUA
4639/*
4640 * "luaeval()" function
4641 */
4642 static void
4643f_luaeval(typval_T *argvars, typval_T *rettv)
4644{
4645 char_u *str;
4646 char_u buf[NUMBUFLEN];
4647
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004648 if (check_restricted() || check_secure())
4649 return;
4650
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004651 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004652 do_luaeval(str, argvars + 1, rettv);
4653}
4654#endif
4655
4656/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004657 * "maparg()" function
4658 */
4659 static void
4660f_maparg(typval_T *argvars, typval_T *rettv)
4661{
4662 get_maparg(argvars, rettv, TRUE);
4663}
4664
4665/*
4666 * "mapcheck()" function
4667 */
4668 static void
4669f_mapcheck(typval_T *argvars, typval_T *rettv)
4670{
4671 get_maparg(argvars, rettv, FALSE);
4672}
4673
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004674typedef enum
4675{
4676 MATCH_END, /* matchend() */
4677 MATCH_MATCH, /* match() */
4678 MATCH_STR, /* matchstr() */
4679 MATCH_LIST, /* matchlist() */
4680 MATCH_POS /* matchstrpos() */
4681} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004682
4683 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004684find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004685{
4686 char_u *str = NULL;
4687 long len = 0;
4688 char_u *expr = NULL;
4689 char_u *pat;
4690 regmatch_T regmatch;
4691 char_u patbuf[NUMBUFLEN];
4692 char_u strbuf[NUMBUFLEN];
4693 char_u *save_cpo;
4694 long start = 0;
4695 long nth = 1;
4696 colnr_T startcol = 0;
4697 int match = 0;
4698 list_T *l = NULL;
4699 listitem_T *li = NULL;
4700 long idx = 0;
4701 char_u *tofree = NULL;
4702
4703 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4704 save_cpo = p_cpo;
4705 p_cpo = (char_u *)"";
4706
4707 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004708 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004709 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004710 /* type MATCH_LIST: return empty list when there are no matches.
4711 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004712 if (rettv_list_alloc(rettv) == FAIL)
4713 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004714 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004715 && (list_append_string(rettv->vval.v_list,
4716 (char_u *)"", 0) == FAIL
4717 || list_append_number(rettv->vval.v_list,
4718 (varnumber_T)-1) == FAIL
4719 || list_append_number(rettv->vval.v_list,
4720 (varnumber_T)-1) == FAIL
4721 || list_append_number(rettv->vval.v_list,
4722 (varnumber_T)-1) == FAIL))
4723 {
4724 list_free(rettv->vval.v_list);
4725 rettv->vval.v_list = NULL;
4726 goto theend;
4727 }
4728 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004729 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004730 {
4731 rettv->v_type = VAR_STRING;
4732 rettv->vval.v_string = NULL;
4733 }
4734
4735 if (argvars[0].v_type == VAR_LIST)
4736 {
4737 if ((l = argvars[0].vval.v_list) == NULL)
4738 goto theend;
4739 li = l->lv_first;
4740 }
4741 else
4742 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004743 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004744 len = (long)STRLEN(str);
4745 }
4746
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004747 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748 if (pat == NULL)
4749 goto theend;
4750
4751 if (argvars[2].v_type != VAR_UNKNOWN)
4752 {
4753 int error = FALSE;
4754
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004755 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004756 if (error)
4757 goto theend;
4758 if (l != NULL)
4759 {
4760 li = list_find(l, start);
4761 if (li == NULL)
4762 goto theend;
4763 idx = l->lv_idx; /* use the cached index */
4764 }
4765 else
4766 {
4767 if (start < 0)
4768 start = 0;
4769 if (start > len)
4770 goto theend;
4771 /* When "count" argument is there ignore matches before "start",
4772 * otherwise skip part of the string. Differs when pattern is "^"
4773 * or "\<". */
4774 if (argvars[3].v_type != VAR_UNKNOWN)
4775 startcol = start;
4776 else
4777 {
4778 str += start;
4779 len -= start;
4780 }
4781 }
4782
4783 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004784 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004785 if (error)
4786 goto theend;
4787 }
4788
4789 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4790 if (regmatch.regprog != NULL)
4791 {
4792 regmatch.rm_ic = p_ic;
4793
4794 for (;;)
4795 {
4796 if (l != NULL)
4797 {
4798 if (li == NULL)
4799 {
4800 match = FALSE;
4801 break;
4802 }
4803 vim_free(tofree);
4804 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4805 if (str == NULL)
4806 break;
4807 }
4808
4809 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4810
4811 if (match && --nth <= 0)
4812 break;
4813 if (l == NULL && !match)
4814 break;
4815
4816 /* Advance to just after the match. */
4817 if (l != NULL)
4818 {
4819 li = li->li_next;
4820 ++idx;
4821 }
4822 else
4823 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004824 startcol = (colnr_T)(regmatch.startp[0]
4825 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004826 if (startcol > (colnr_T)len
4827 || str + startcol <= regmatch.startp[0])
4828 {
4829 match = FALSE;
4830 break;
4831 }
4832 }
4833 }
4834
4835 if (match)
4836 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004837 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004838 {
4839 listitem_T *li1 = rettv->vval.v_list->lv_first;
4840 listitem_T *li2 = li1->li_next;
4841 listitem_T *li3 = li2->li_next;
4842 listitem_T *li4 = li3->li_next;
4843
4844 vim_free(li1->li_tv.vval.v_string);
4845 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4846 (int)(regmatch.endp[0] - regmatch.startp[0]));
4847 li3->li_tv.vval.v_number =
4848 (varnumber_T)(regmatch.startp[0] - expr);
4849 li4->li_tv.vval.v_number =
4850 (varnumber_T)(regmatch.endp[0] - expr);
4851 if (l != NULL)
4852 li2->li_tv.vval.v_number = (varnumber_T)idx;
4853 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004854 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004855 {
4856 int i;
4857
4858 /* return list with matched string and submatches */
4859 for (i = 0; i < NSUBEXP; ++i)
4860 {
4861 if (regmatch.endp[i] == NULL)
4862 {
4863 if (list_append_string(rettv->vval.v_list,
4864 (char_u *)"", 0) == FAIL)
4865 break;
4866 }
4867 else if (list_append_string(rettv->vval.v_list,
4868 regmatch.startp[i],
4869 (int)(regmatch.endp[i] - regmatch.startp[i]))
4870 == FAIL)
4871 break;
4872 }
4873 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004874 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004875 {
4876 /* return matched string */
4877 if (l != NULL)
4878 copy_tv(&li->li_tv, rettv);
4879 else
4880 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4881 (int)(regmatch.endp[0] - regmatch.startp[0]));
4882 }
4883 else if (l != NULL)
4884 rettv->vval.v_number = idx;
4885 else
4886 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004887 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004888 rettv->vval.v_number =
4889 (varnumber_T)(regmatch.startp[0] - str);
4890 else
4891 rettv->vval.v_number =
4892 (varnumber_T)(regmatch.endp[0] - str);
4893 rettv->vval.v_number += (varnumber_T)(str - expr);
4894 }
4895 }
4896 vim_regfree(regmatch.regprog);
4897 }
4898
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004899theend:
4900 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004901 /* matchstrpos() without a list: drop the second item. */
4902 listitem_remove(rettv->vval.v_list,
4903 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004904 vim_free(tofree);
4905 p_cpo = save_cpo;
4906}
4907
4908/*
4909 * "match()" function
4910 */
4911 static void
4912f_match(typval_T *argvars, typval_T *rettv)
4913{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004914 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915}
4916
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917/*
4918 * "matchend()" function
4919 */
4920 static void
4921f_matchend(typval_T *argvars, typval_T *rettv)
4922{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004923 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004924}
4925
4926/*
4927 * "matchlist()" function
4928 */
4929 static void
4930f_matchlist(typval_T *argvars, typval_T *rettv)
4931{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004932 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933}
4934
4935/*
4936 * "matchstr()" function
4937 */
4938 static void
4939f_matchstr(typval_T *argvars, typval_T *rettv)
4940{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004941 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942}
4943
4944/*
4945 * "matchstrpos()" function
4946 */
4947 static void
4948f_matchstrpos(typval_T *argvars, typval_T *rettv)
4949{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004950 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004951}
4952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004953 static void
4954max_min(typval_T *argvars, typval_T *rettv, int domax)
4955{
4956 varnumber_T n = 0;
4957 varnumber_T i;
4958 int error = FALSE;
4959
4960 if (argvars[0].v_type == VAR_LIST)
4961 {
4962 list_T *l;
4963 listitem_T *li;
4964
4965 l = argvars[0].vval.v_list;
4966 if (l != NULL)
4967 {
4968 li = l->lv_first;
4969 if (li != NULL)
4970 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004971 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972 for (;;)
4973 {
4974 li = li->li_next;
4975 if (li == NULL)
4976 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004977 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004978 if (domax ? i > n : i < n)
4979 n = i;
4980 }
4981 }
4982 }
4983 }
4984 else if (argvars[0].v_type == VAR_DICT)
4985 {
4986 dict_T *d;
4987 int first = TRUE;
4988 hashitem_T *hi;
4989 int todo;
4990
4991 d = argvars[0].vval.v_dict;
4992 if (d != NULL)
4993 {
4994 todo = (int)d->dv_hashtab.ht_used;
4995 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4996 {
4997 if (!HASHITEM_EMPTY(hi))
4998 {
4999 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005000 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005001 if (first)
5002 {
5003 n = i;
5004 first = FALSE;
5005 }
5006 else if (domax ? i > n : i < n)
5007 n = i;
5008 }
5009 }
5010 }
5011 }
5012 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005013 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005014 rettv->vval.v_number = error ? 0 : n;
5015}
5016
5017/*
5018 * "max()" function
5019 */
5020 static void
5021f_max(typval_T *argvars, typval_T *rettv)
5022{
5023 max_min(argvars, rettv, TRUE);
5024}
5025
5026/*
5027 * "min()" function
5028 */
5029 static void
5030f_min(typval_T *argvars, typval_T *rettv)
5031{
5032 max_min(argvars, rettv, FALSE);
5033}
5034
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005036 * "mode()" function
5037 */
5038 static void
5039f_mode(typval_T *argvars, typval_T *rettv)
5040{
Bram Moolenaar612cc382018-07-29 15:34:26 +02005041 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042
Bram Moolenaar612cc382018-07-29 15:34:26 +02005043 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044
5045 if (time_for_testing == 93784)
5046 {
5047 /* Testing the two-character code. */
5048 buf[0] = 'x';
5049 buf[1] = '!';
5050 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02005051#ifdef FEAT_TERMINAL
5052 else if (term_use_loop())
5053 buf[0] = 't';
5054#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005055 else if (VIsual_active)
5056 {
5057 if (VIsual_select)
5058 buf[0] = VIsual_mode + 's' - 'v';
5059 else
5060 buf[0] = VIsual_mode;
5061 }
5062 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
5063 || State == CONFIRM)
5064 {
5065 buf[0] = 'r';
5066 if (State == ASKMORE)
5067 buf[1] = 'm';
5068 else if (State == CONFIRM)
5069 buf[1] = '?';
5070 }
5071 else if (State == EXTERNCMD)
5072 buf[0] = '!';
5073 else if (State & INSERT)
5074 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075 if (State & VREPLACE_FLAG)
5076 {
5077 buf[0] = 'R';
5078 buf[1] = 'v';
5079 }
5080 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01005081 {
5082 if (State & REPLACE_FLAG)
5083 buf[0] = 'R';
5084 else
5085 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005086 if (ins_compl_active())
5087 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01005088 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01005089 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005090 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005091 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01005092 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005093 {
5094 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005095 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005097 else if (exmode_active == EXMODE_NORMAL)
5098 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 }
5100 else
5101 {
5102 buf[0] = 'n';
5103 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01005104 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01005106 // to be able to detect force-linewise/blockwise/characterwise operations
5107 buf[2] = motion_force;
5108 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02005109 else if (restart_edit == 'I' || restart_edit == 'R'
5110 || restart_edit == 'V')
5111 {
5112 buf[1] = 'i';
5113 buf[2] = restart_edit;
5114 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115 }
5116
5117 /* Clear out the minor mode when the argument is not a non-zero number or
5118 * non-empty string. */
5119 if (!non_zero_arg(&argvars[0]))
5120 buf[1] = NUL;
5121
5122 rettv->vval.v_string = vim_strsave(buf);
5123 rettv->v_type = VAR_STRING;
5124}
5125
5126#if defined(FEAT_MZSCHEME) || defined(PROTO)
5127/*
5128 * "mzeval()" function
5129 */
5130 static void
5131f_mzeval(typval_T *argvars, typval_T *rettv)
5132{
5133 char_u *str;
5134 char_u buf[NUMBUFLEN];
5135
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005136 if (check_restricted() || check_secure())
5137 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005138 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005139 do_mzeval(str, rettv);
5140}
5141
5142 void
5143mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5144{
5145 typval_T argvars[3];
5146
5147 argvars[0].v_type = VAR_STRING;
5148 argvars[0].vval.v_string = name;
5149 copy_tv(args, &argvars[1]);
5150 argvars[2].v_type = VAR_UNKNOWN;
5151 f_call(argvars, rettv);
5152 clear_tv(&argvars[1]);
5153}
5154#endif
5155
5156/*
5157 * "nextnonblank()" function
5158 */
5159 static void
5160f_nextnonblank(typval_T *argvars, typval_T *rettv)
5161{
5162 linenr_T lnum;
5163
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005164 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005165 {
5166 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5167 {
5168 lnum = 0;
5169 break;
5170 }
5171 if (*skipwhite(ml_get(lnum)) != NUL)
5172 break;
5173 }
5174 rettv->vval.v_number = lnum;
5175}
5176
5177/*
5178 * "nr2char()" function
5179 */
5180 static void
5181f_nr2char(typval_T *argvars, typval_T *rettv)
5182{
5183 char_u buf[NUMBUFLEN];
5184
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005185 if (has_mbyte)
5186 {
5187 int utf8 = 0;
5188
5189 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005190 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005191 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005192 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005194 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005195 }
5196 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005197 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005198 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 buf[1] = NUL;
5200 }
5201 rettv->v_type = VAR_STRING;
5202 rettv->vval.v_string = vim_strsave(buf);
5203}
5204
5205/*
5206 * "or(expr, expr)" function
5207 */
5208 static void
5209f_or(typval_T *argvars, typval_T *rettv)
5210{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005211 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5212 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005213}
5214
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005215#ifdef FEAT_PERL
5216/*
5217 * "perleval()" function
5218 */
5219 static void
5220f_perleval(typval_T *argvars, typval_T *rettv)
5221{
5222 char_u *str;
5223 char_u buf[NUMBUFLEN];
5224
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005225 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005226 do_perleval(str, rettv);
5227}
5228#endif
5229
5230#ifdef FEAT_FLOAT
5231/*
5232 * "pow()" function
5233 */
5234 static void
5235f_pow(typval_T *argvars, typval_T *rettv)
5236{
5237 float_T fx = 0.0, fy = 0.0;
5238
5239 rettv->v_type = VAR_FLOAT;
5240 if (get_float_arg(argvars, &fx) == OK
5241 && get_float_arg(&argvars[1], &fy) == OK)
5242 rettv->vval.v_float = pow(fx, fy);
5243 else
5244 rettv->vval.v_float = 0.0;
5245}
5246#endif
5247
5248/*
5249 * "prevnonblank()" function
5250 */
5251 static void
5252f_prevnonblank(typval_T *argvars, typval_T *rettv)
5253{
5254 linenr_T lnum;
5255
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005256 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005257 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5258 lnum = 0;
5259 else
5260 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5261 --lnum;
5262 rettv->vval.v_number = lnum;
5263}
5264
5265/* This dummy va_list is here because:
5266 * - passing a NULL pointer doesn't work when va_list isn't a pointer
5267 * - locally in the function results in a "used before set" warning
5268 * - using va_start() to initialize it gives "function with fixed args" error */
5269static va_list ap;
5270
5271/*
5272 * "printf()" function
5273 */
5274 static void
5275f_printf(typval_T *argvars, typval_T *rettv)
5276{
5277 char_u buf[NUMBUFLEN];
5278 int len;
5279 char_u *s;
5280 int saved_did_emsg = did_emsg;
5281 char *fmt;
5282
5283 rettv->v_type = VAR_STRING;
5284 rettv->vval.v_string = NULL;
5285
5286 /* Get the required length, allocate the buffer and do it for real. */
5287 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005288 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005289 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005290 if (!did_emsg)
5291 {
5292 s = alloc(len + 1);
5293 if (s != NULL)
5294 {
5295 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005296 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5297 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 }
5299 }
5300 did_emsg |= saved_did_emsg;
5301}
5302
5303/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005304 * "pum_getpos()" function
5305 */
5306 static void
5307f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5308{
5309 if (rettv_dict_alloc(rettv) != OK)
5310 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005311 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005312}
5313
5314/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005315 * "pumvisible()" function
5316 */
5317 static void
5318f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5319{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005320 if (pum_visible())
5321 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005322}
5323
5324#ifdef FEAT_PYTHON3
5325/*
5326 * "py3eval()" function
5327 */
5328 static void
5329f_py3eval(typval_T *argvars, typval_T *rettv)
5330{
5331 char_u *str;
5332 char_u buf[NUMBUFLEN];
5333
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005334 if (check_restricted() || check_secure())
5335 return;
5336
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005337 if (p_pyx == 0)
5338 p_pyx = 3;
5339
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005340 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005341 do_py3eval(str, rettv);
5342}
5343#endif
5344
5345#ifdef FEAT_PYTHON
5346/*
5347 * "pyeval()" function
5348 */
5349 static void
5350f_pyeval(typval_T *argvars, typval_T *rettv)
5351{
5352 char_u *str;
5353 char_u buf[NUMBUFLEN];
5354
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005355 if (check_restricted() || check_secure())
5356 return;
5357
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005358 if (p_pyx == 0)
5359 p_pyx = 2;
5360
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005361 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005362 do_pyeval(str, rettv);
5363}
5364#endif
5365
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005366#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5367/*
5368 * "pyxeval()" function
5369 */
5370 static void
5371f_pyxeval(typval_T *argvars, typval_T *rettv)
5372{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005373 if (check_restricted() || check_secure())
5374 return;
5375
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005376# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5377 init_pyxversion();
5378 if (p_pyx == 2)
5379 f_pyeval(argvars, rettv);
5380 else
5381 f_py3eval(argvars, rettv);
5382# elif defined(FEAT_PYTHON)
5383 f_pyeval(argvars, rettv);
5384# elif defined(FEAT_PYTHON3)
5385 f_py3eval(argvars, rettv);
5386# endif
5387}
5388#endif
5389
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005390/*
5391 * "range()" function
5392 */
5393 static void
5394f_range(typval_T *argvars, typval_T *rettv)
5395{
5396 varnumber_T start;
5397 varnumber_T end;
5398 varnumber_T stride = 1;
5399 varnumber_T i;
5400 int error = FALSE;
5401
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005402 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005403 if (argvars[1].v_type == VAR_UNKNOWN)
5404 {
5405 end = start - 1;
5406 start = 0;
5407 }
5408 else
5409 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005410 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005411 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005412 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005413 }
5414
5415 if (error)
5416 return; /* type error; errmsg already given */
5417 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005418 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005419 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005420 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005421 else
5422 {
5423 if (rettv_list_alloc(rettv) == OK)
5424 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5425 if (list_append_number(rettv->vval.v_list,
5426 (varnumber_T)i) == FAIL)
5427 break;
5428 }
5429}
5430
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005431 static void
5432return_register(int regname, typval_T *rettv)
5433{
5434 char_u buf[2] = {0, 0};
5435
5436 buf[0] = (char_u)regname;
5437 rettv->v_type = VAR_STRING;
5438 rettv->vval.v_string = vim_strsave(buf);
5439}
5440
5441/*
5442 * "reg_executing()" function
5443 */
5444 static void
5445f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5446{
5447 return_register(reg_executing, rettv);
5448}
5449
5450/*
5451 * "reg_recording()" function
5452 */
5453 static void
5454f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5455{
5456 return_register(reg_recording, rettv);
5457}
5458
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005459#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005460/*
5461 * Convert a List to proftime_T.
5462 * Return FAIL when there is something wrong.
5463 */
5464 static int
5465list2proftime(typval_T *arg, proftime_T *tm)
5466{
5467 long n1, n2;
5468 int error = FALSE;
5469
5470 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5471 || arg->vval.v_list->lv_len != 2)
5472 return FAIL;
5473 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5474 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005475# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005476 tm->HighPart = n1;
5477 tm->LowPart = n2;
5478# else
5479 tm->tv_sec = n1;
5480 tm->tv_usec = n2;
5481# endif
5482 return error ? FAIL : OK;
5483}
5484#endif /* FEAT_RELTIME */
5485
5486/*
5487 * "reltime()" function
5488 */
5489 static void
5490f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5491{
5492#ifdef FEAT_RELTIME
5493 proftime_T res;
5494 proftime_T start;
5495
5496 if (argvars[0].v_type == VAR_UNKNOWN)
5497 {
5498 /* No arguments: get current time. */
5499 profile_start(&res);
5500 }
5501 else if (argvars[1].v_type == VAR_UNKNOWN)
5502 {
5503 if (list2proftime(&argvars[0], &res) == FAIL)
5504 return;
5505 profile_end(&res);
5506 }
5507 else
5508 {
5509 /* Two arguments: compute the difference. */
5510 if (list2proftime(&argvars[0], &start) == FAIL
5511 || list2proftime(&argvars[1], &res) == FAIL)
5512 return;
5513 profile_sub(&res, &start);
5514 }
5515
5516 if (rettv_list_alloc(rettv) == OK)
5517 {
5518 long n1, n2;
5519
Bram Moolenaar4f974752019-02-17 17:44:42 +01005520# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 n1 = res.HighPart;
5522 n2 = res.LowPart;
5523# else
5524 n1 = res.tv_sec;
5525 n2 = res.tv_usec;
5526# endif
5527 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5528 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5529 }
5530#endif
5531}
5532
5533#ifdef FEAT_FLOAT
5534/*
5535 * "reltimefloat()" function
5536 */
5537 static void
5538f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5539{
5540# ifdef FEAT_RELTIME
5541 proftime_T tm;
5542# endif
5543
5544 rettv->v_type = VAR_FLOAT;
5545 rettv->vval.v_float = 0;
5546# ifdef FEAT_RELTIME
5547 if (list2proftime(&argvars[0], &tm) == OK)
5548 rettv->vval.v_float = profile_float(&tm);
5549# endif
5550}
5551#endif
5552
5553/*
5554 * "reltimestr()" function
5555 */
5556 static void
5557f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5558{
5559#ifdef FEAT_RELTIME
5560 proftime_T tm;
5561#endif
5562
5563 rettv->v_type = VAR_STRING;
5564 rettv->vval.v_string = NULL;
5565#ifdef FEAT_RELTIME
5566 if (list2proftime(&argvars[0], &tm) == OK)
5567 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5568#endif
5569}
5570
5571#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005572 static void
5573make_connection(void)
5574{
5575 if (X_DISPLAY == NULL
5576# ifdef FEAT_GUI
5577 && !gui.in_use
5578# endif
5579 )
5580 {
5581 x_force_connect = TRUE;
5582 setup_term_clip();
5583 x_force_connect = FALSE;
5584 }
5585}
5586
5587 static int
5588check_connection(void)
5589{
5590 make_connection();
5591 if (X_DISPLAY == NULL)
5592 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005593 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005594 return FAIL;
5595 }
5596 return OK;
5597}
5598#endif
5599
5600#ifdef FEAT_CLIENTSERVER
5601 static void
5602remote_common(typval_T *argvars, typval_T *rettv, int expr)
5603{
5604 char_u *server_name;
5605 char_u *keys;
5606 char_u *r = NULL;
5607 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005608 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005609# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005610 HWND w;
5611# else
5612 Window w;
5613# endif
5614
5615 if (check_restricted() || check_secure())
5616 return;
5617
5618# ifdef FEAT_X11
5619 if (check_connection() == FAIL)
5620 return;
5621# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005622 if (argvars[2].v_type != VAR_UNKNOWN
5623 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005624 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005626 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005627 if (server_name == NULL)
5628 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005629 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005630# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005631 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005632# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005633 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5634 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005635# endif
5636 {
5637 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005638 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005639 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005640 vim_free(r);
5641 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005643 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005644 return;
5645 }
5646
5647 rettv->vval.v_string = r;
5648
5649 if (argvars[2].v_type != VAR_UNKNOWN)
5650 {
5651 dictitem_T v;
5652 char_u str[30];
5653 char_u *idvar;
5654
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005655 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005656 if (idvar != NULL && *idvar != NUL)
5657 {
5658 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5659 v.di_tv.v_type = VAR_STRING;
5660 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005661 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005662 vim_free(v.di_tv.vval.v_string);
5663 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005664 }
5665}
5666#endif
5667
5668/*
5669 * "remote_expr()" function
5670 */
5671 static void
5672f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5673{
5674 rettv->v_type = VAR_STRING;
5675 rettv->vval.v_string = NULL;
5676#ifdef FEAT_CLIENTSERVER
5677 remote_common(argvars, rettv, TRUE);
5678#endif
5679}
5680
5681/*
5682 * "remote_foreground()" function
5683 */
5684 static void
5685f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5686{
5687#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005688# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005689 /* On Win32 it's done in this application. */
5690 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005691 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005692
5693 if (server_name != NULL)
5694 serverForeground(server_name);
5695 }
5696# else
5697 /* Send a foreground() expression to the server. */
5698 argvars[1].v_type = VAR_STRING;
5699 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5700 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005701 rettv->v_type = VAR_STRING;
5702 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005703 remote_common(argvars, rettv, TRUE);
5704 vim_free(argvars[1].vval.v_string);
5705# endif
5706#endif
5707}
5708
5709 static void
5710f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5711{
5712#ifdef FEAT_CLIENTSERVER
5713 dictitem_T v;
5714 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005715# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005716 long_u n = 0;
5717# endif
5718 char_u *serverid;
5719
5720 if (check_restricted() || check_secure())
5721 {
5722 rettv->vval.v_number = -1;
5723 return;
5724 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005725 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005726 if (serverid == NULL)
5727 {
5728 rettv->vval.v_number = -1;
5729 return; /* type error; errmsg already given */
5730 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005731# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005732 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5733 if (n == 0)
5734 rettv->vval.v_number = -1;
5735 else
5736 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005737 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005738 rettv->vval.v_number = (s != NULL);
5739 }
5740# else
5741 if (check_connection() == FAIL)
5742 return;
5743
5744 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5745 serverStrToWin(serverid), &s);
5746# endif
5747
5748 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5749 {
5750 char_u *retvar;
5751
5752 v.di_tv.v_type = VAR_STRING;
5753 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005754 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005755 if (retvar != NULL)
5756 set_var(retvar, &v.di_tv, FALSE);
5757 vim_free(v.di_tv.vval.v_string);
5758 }
5759#else
5760 rettv->vval.v_number = -1;
5761#endif
5762}
5763
5764 static void
5765f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5766{
5767 char_u *r = NULL;
5768
5769#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005770 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005771
5772 if (serverid != NULL && !check_restricted() && !check_secure())
5773 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005774 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005775# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005776 /* The server's HWND is encoded in the 'id' parameter */
5777 long_u n = 0;
5778# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005779
5780 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005781 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005782
Bram Moolenaar4f974752019-02-17 17:44:42 +01005783# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005784 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5785 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005786 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005787 if (r == NULL)
5788# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005789 if (check_connection() == FAIL
5790 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5791 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005793 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794 }
5795#endif
5796 rettv->v_type = VAR_STRING;
5797 rettv->vval.v_string = r;
5798}
5799
5800/*
5801 * "remote_send()" function
5802 */
5803 static void
5804f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5805{
5806 rettv->v_type = VAR_STRING;
5807 rettv->vval.v_string = NULL;
5808#ifdef FEAT_CLIENTSERVER
5809 remote_common(argvars, rettv, FALSE);
5810#endif
5811}
5812
5813/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005814 * "remote_startserver()" function
5815 */
5816 static void
5817f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5818{
5819#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005820 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005821
5822 if (server == NULL)
5823 return; /* type error; errmsg already given */
5824 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005825 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005826 else
5827 {
5828# ifdef FEAT_X11
5829 if (check_connection() == OK)
5830 serverRegisterName(X_DISPLAY, server);
5831# else
5832 serverSetName(server);
5833# endif
5834 }
5835#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005836 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005837#endif
5838}
5839
5840/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005841 * "rename({from}, {to})" function
5842 */
5843 static void
5844f_rename(typval_T *argvars, typval_T *rettv)
5845{
5846 char_u buf[NUMBUFLEN];
5847
5848 if (check_restricted() || check_secure())
5849 rettv->vval.v_number = -1;
5850 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005851 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5852 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005853}
5854
5855/*
5856 * "repeat()" function
5857 */
5858 static void
5859f_repeat(typval_T *argvars, typval_T *rettv)
5860{
5861 char_u *p;
5862 int n;
5863 int slen;
5864 int len;
5865 char_u *r;
5866 int i;
5867
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005868 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005869 if (argvars[0].v_type == VAR_LIST)
5870 {
5871 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5872 while (n-- > 0)
5873 if (list_extend(rettv->vval.v_list,
5874 argvars[0].vval.v_list, NULL) == FAIL)
5875 break;
5876 }
5877 else
5878 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005879 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005880 rettv->v_type = VAR_STRING;
5881 rettv->vval.v_string = NULL;
5882
5883 slen = (int)STRLEN(p);
5884 len = slen * n;
5885 if (len <= 0)
5886 return;
5887
5888 r = alloc(len + 1);
5889 if (r != NULL)
5890 {
5891 for (i = 0; i < n; i++)
5892 mch_memmove(r + i * slen, p, (size_t)slen);
5893 r[len] = NUL;
5894 }
5895
5896 rettv->vval.v_string = r;
5897 }
5898}
5899
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900#define SP_NOMOVE 0x01 /* don't move cursor */
5901#define SP_REPEAT 0x02 /* repeat to find outer pair */
5902#define SP_RETCOUNT 0x04 /* return matchcount */
5903#define SP_SETPCMARK 0x08 /* set previous context mark */
5904#define SP_START 0x10 /* accept match at start position */
5905#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5906#define SP_END 0x40 /* leave cursor at end of match */
5907#define SP_COLUMN 0x80 /* start at cursor column */
5908
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005909/*
5910 * Get flags for a search function.
5911 * Possibly sets "p_ws".
5912 * Returns BACKWARD, FORWARD or zero (for an error).
5913 */
5914 static int
5915get_search_arg(typval_T *varp, int *flagsp)
5916{
5917 int dir = FORWARD;
5918 char_u *flags;
5919 char_u nbuf[NUMBUFLEN];
5920 int mask;
5921
5922 if (varp->v_type != VAR_UNKNOWN)
5923 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005924 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005925 if (flags == NULL)
5926 return 0; /* type error; errmsg already given */
5927 while (*flags != NUL)
5928 {
5929 switch (*flags)
5930 {
5931 case 'b': dir = BACKWARD; break;
5932 case 'w': p_ws = TRUE; break;
5933 case 'W': p_ws = FALSE; break;
5934 default: mask = 0;
5935 if (flagsp != NULL)
5936 switch (*flags)
5937 {
5938 case 'c': mask = SP_START; break;
5939 case 'e': mask = SP_END; break;
5940 case 'm': mask = SP_RETCOUNT; break;
5941 case 'n': mask = SP_NOMOVE; break;
5942 case 'p': mask = SP_SUBPAT; break;
5943 case 'r': mask = SP_REPEAT; break;
5944 case 's': mask = SP_SETPCMARK; break;
5945 case 'z': mask = SP_COLUMN; break;
5946 }
5947 if (mask == 0)
5948 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005949 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005950 dir = 0;
5951 }
5952 else
5953 *flagsp |= mask;
5954 }
5955 if (dir == 0)
5956 break;
5957 ++flags;
5958 }
5959 }
5960 return dir;
5961}
5962
5963/*
5964 * Shared by search() and searchpos() functions.
5965 */
5966 static int
5967search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5968{
5969 int flags;
5970 char_u *pat;
5971 pos_T pos;
5972 pos_T save_cursor;
5973 int save_p_ws = p_ws;
5974 int dir;
5975 int retval = 0; /* default: FAIL */
5976 long lnum_stop = 0;
5977 proftime_T tm;
5978#ifdef FEAT_RELTIME
5979 long time_limit = 0;
5980#endif
5981 int options = SEARCH_KEEP;
5982 int subpatnum;
5983
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005984 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005985 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5986 if (dir == 0)
5987 goto theend;
5988 flags = *flagsp;
5989 if (flags & SP_START)
5990 options |= SEARCH_START;
5991 if (flags & SP_END)
5992 options |= SEARCH_END;
5993 if (flags & SP_COLUMN)
5994 options |= SEARCH_COL;
5995
5996 /* Optional arguments: line number to stop searching and timeout. */
5997 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5998 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005999 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006000 if (lnum_stop < 0)
6001 goto theend;
6002#ifdef FEAT_RELTIME
6003 if (argvars[3].v_type != VAR_UNKNOWN)
6004 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006005 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006 if (time_limit < 0)
6007 goto theend;
6008 }
6009#endif
6010 }
6011
6012#ifdef FEAT_RELTIME
6013 /* Set the time limit, if there is one. */
6014 profile_setlimit(time_limit, &tm);
6015#endif
6016
6017 /*
6018 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6019 * Check to make sure only those flags are set.
6020 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6021 * flags cannot be set. Check for that condition also.
6022 */
6023 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6024 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6025 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006026 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006027 goto theend;
6028 }
6029
6030 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006031 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006032 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006033 if (subpatnum != FAIL)
6034 {
6035 if (flags & SP_SUBPAT)
6036 retval = subpatnum;
6037 else
6038 retval = pos.lnum;
6039 if (flags & SP_SETPCMARK)
6040 setpcmark();
6041 curwin->w_cursor = pos;
6042 if (match_pos != NULL)
6043 {
6044 /* Store the match cursor position */
6045 match_pos->lnum = pos.lnum;
6046 match_pos->col = pos.col + 1;
6047 }
6048 /* "/$" will put the cursor after the end of the line, may need to
6049 * correct that here */
6050 check_cursor();
6051 }
6052
6053 /* If 'n' flag is used: restore cursor position. */
6054 if (flags & SP_NOMOVE)
6055 curwin->w_cursor = save_cursor;
6056 else
6057 curwin->w_set_curswant = TRUE;
6058theend:
6059 p_ws = save_p_ws;
6060
6061 return retval;
6062}
6063
6064#ifdef FEAT_FLOAT
6065
6066/*
6067 * round() is not in C90, use ceil() or floor() instead.
6068 */
6069 float_T
6070vim_round(float_T f)
6071{
6072 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6073}
6074
6075/*
6076 * "round({float})" function
6077 */
6078 static void
6079f_round(typval_T *argvars, typval_T *rettv)
6080{
6081 float_T f = 0.0;
6082
6083 rettv->v_type = VAR_FLOAT;
6084 if (get_float_arg(argvars, &f) == OK)
6085 rettv->vval.v_float = vim_round(f);
6086 else
6087 rettv->vval.v_float = 0.0;
6088}
6089#endif
6090
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006091#ifdef FEAT_RUBY
6092/*
6093 * "rubyeval()" function
6094 */
6095 static void
6096f_rubyeval(typval_T *argvars, typval_T *rettv)
6097{
6098 char_u *str;
6099 char_u buf[NUMBUFLEN];
6100
6101 str = tv_get_string_buf(&argvars[0], buf);
6102 do_rubyeval(str, rettv);
6103}
6104#endif
6105
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006106/*
6107 * "screenattr()" function
6108 */
6109 static void
6110f_screenattr(typval_T *argvars, typval_T *rettv)
6111{
6112 int row;
6113 int col;
6114 int c;
6115
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006116 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6117 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006118 if (row < 0 || row >= screen_Rows
6119 || col < 0 || col >= screen_Columns)
6120 c = -1;
6121 else
6122 c = ScreenAttrs[LineOffset[row] + col];
6123 rettv->vval.v_number = c;
6124}
6125
6126/*
6127 * "screenchar()" function
6128 */
6129 static void
6130f_screenchar(typval_T *argvars, typval_T *rettv)
6131{
6132 int row;
6133 int col;
6134 int off;
6135 int c;
6136
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006137 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6138 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006139 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006140 c = -1;
6141 else
6142 {
6143 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006144 if (enc_utf8 && ScreenLinesUC[off] != 0)
6145 c = ScreenLinesUC[off];
6146 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006147 c = ScreenLines[off];
6148 }
6149 rettv->vval.v_number = c;
6150}
6151
6152/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006153 * "screenchars()" function
6154 */
6155 static void
6156f_screenchars(typval_T *argvars, typval_T *rettv)
6157{
6158 int row;
6159 int col;
6160 int off;
6161 int c;
6162 int i;
6163
6164 if (rettv_list_alloc(rettv) == FAIL)
6165 return;
6166 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6167 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6168 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6169 return;
6170
6171 off = LineOffset[row] + col;
6172 if (enc_utf8 && ScreenLinesUC[off] != 0)
6173 c = ScreenLinesUC[off];
6174 else
6175 c = ScreenLines[off];
6176 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6177
6178 if (enc_utf8)
6179
6180 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6181 list_append_number(rettv->vval.v_list,
6182 (varnumber_T)ScreenLinesC[i][off]);
6183}
6184
6185/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186 * "screencol()" function
6187 *
6188 * First column is 1 to be consistent with virtcol().
6189 */
6190 static void
6191f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6192{
6193 rettv->vval.v_number = screen_screencol() + 1;
6194}
6195
6196/*
6197 * "screenrow()" function
6198 */
6199 static void
6200f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6201{
6202 rettv->vval.v_number = screen_screenrow() + 1;
6203}
6204
6205/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006206 * "screenstring()" function
6207 */
6208 static void
6209f_screenstring(typval_T *argvars, typval_T *rettv)
6210{
6211 int row;
6212 int col;
6213 int off;
6214 int c;
6215 int i;
6216 char_u buf[MB_MAXBYTES + 1];
6217 int buflen = 0;
6218
6219 rettv->vval.v_string = NULL;
6220 rettv->v_type = VAR_STRING;
6221
6222 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6223 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6224 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6225 return;
6226
6227 off = LineOffset[row] + col;
6228 if (enc_utf8 && ScreenLinesUC[off] != 0)
6229 c = ScreenLinesUC[off];
6230 else
6231 c = ScreenLines[off];
6232 buflen += mb_char2bytes(c, buf);
6233
6234 if (enc_utf8)
6235 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6236 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6237
6238 buf[buflen] = NUL;
6239 rettv->vval.v_string = vim_strsave(buf);
6240}
6241
6242/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006243 * "search()" function
6244 */
6245 static void
6246f_search(typval_T *argvars, typval_T *rettv)
6247{
6248 int flags = 0;
6249
6250 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6251}
6252
6253/*
6254 * "searchdecl()" function
6255 */
6256 static void
6257f_searchdecl(typval_T *argvars, typval_T *rettv)
6258{
6259 int locally = 1;
6260 int thisblock = 0;
6261 int error = FALSE;
6262 char_u *name;
6263
6264 rettv->vval.v_number = 1; /* default: FAIL */
6265
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006266 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006267 if (argvars[1].v_type != VAR_UNKNOWN)
6268 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006269 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006271 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 }
6273 if (!error && name != NULL)
6274 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6275 locally, thisblock, SEARCH_KEEP) == FAIL;
6276}
6277
6278/*
6279 * Used by searchpair() and searchpairpos()
6280 */
6281 static int
6282searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6283{
6284 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006285 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006286 int save_p_ws = p_ws;
6287 int dir;
6288 int flags = 0;
6289 char_u nbuf1[NUMBUFLEN];
6290 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291 int retval = 0; /* default: FAIL */
6292 long lnum_stop = 0;
6293 long time_limit = 0;
6294
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006295 /* Get the three pattern arguments: start, middle, end. Will result in an
6296 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006297 spat = tv_get_string_chk(&argvars[0]);
6298 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6299 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300 if (spat == NULL || mpat == NULL || epat == NULL)
6301 goto theend; /* type error */
6302
6303 /* Handle the optional fourth argument: flags */
6304 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6305 if (dir == 0)
6306 goto theend;
6307
6308 /* Don't accept SP_END or SP_SUBPAT.
6309 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6310 */
6311 if ((flags & (SP_END | SP_SUBPAT)) != 0
6312 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6313 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006314 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315 goto theend;
6316 }
6317
6318 /* Using 'r' implies 'W', otherwise it doesn't work. */
6319 if (flags & SP_REPEAT)
6320 p_ws = FALSE;
6321
6322 /* Optional fifth argument: skip expression */
6323 if (argvars[3].v_type == VAR_UNKNOWN
6324 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006325 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006326 else
6327 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006328 skip = &argvars[4];
6329 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6330 && skip->v_type != VAR_STRING)
6331 {
6332 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006333 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006334 goto theend;
6335 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006336 if (argvars[5].v_type != VAR_UNKNOWN)
6337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006338 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006339 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006340 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006341 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006342 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006343 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006344#ifdef FEAT_RELTIME
6345 if (argvars[6].v_type != VAR_UNKNOWN)
6346 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006347 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006348 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006349 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006350 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006352 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353 }
6354#endif
6355 }
6356 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006357
6358 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6359 match_pos, lnum_stop, time_limit);
6360
6361theend:
6362 p_ws = save_p_ws;
6363
6364 return retval;
6365}
6366
6367/*
6368 * "searchpair()" function
6369 */
6370 static void
6371f_searchpair(typval_T *argvars, typval_T *rettv)
6372{
6373 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6374}
6375
6376/*
6377 * "searchpairpos()" function
6378 */
6379 static void
6380f_searchpairpos(typval_T *argvars, typval_T *rettv)
6381{
6382 pos_T match_pos;
6383 int lnum = 0;
6384 int col = 0;
6385
6386 if (rettv_list_alloc(rettv) == FAIL)
6387 return;
6388
6389 if (searchpair_cmn(argvars, &match_pos) > 0)
6390 {
6391 lnum = match_pos.lnum;
6392 col = match_pos.col;
6393 }
6394
6395 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6396 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6397}
6398
6399/*
6400 * Search for a start/middle/end thing.
6401 * Used by searchpair(), see its documentation for the details.
6402 * Returns 0 or -1 for no match,
6403 */
6404 long
6405do_searchpair(
6406 char_u *spat, /* start pattern */
6407 char_u *mpat, /* middle pattern */
6408 char_u *epat, /* end pattern */
6409 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006410 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006411 int flags, /* SP_SETPCMARK and other SP_ values */
6412 pos_T *match_pos,
6413 linenr_T lnum_stop, /* stop at this line if not zero */
6414 long time_limit UNUSED) /* stop after this many msec */
6415{
6416 char_u *save_cpo;
6417 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6418 long retval = 0;
6419 pos_T pos;
6420 pos_T firstpos;
6421 pos_T foundpos;
6422 pos_T save_cursor;
6423 pos_T save_pos;
6424 int n;
6425 int r;
6426 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006427 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006428 int err;
6429 int options = SEARCH_KEEP;
6430 proftime_T tm;
6431
6432 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6433 save_cpo = p_cpo;
6434 p_cpo = empty_option;
6435
6436#ifdef FEAT_RELTIME
6437 /* Set the time limit, if there is one. */
6438 profile_setlimit(time_limit, &tm);
6439#endif
6440
6441 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6442 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006443 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6444 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445 if (pat2 == NULL || pat3 == NULL)
6446 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006447 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006448 if (*mpat == NUL)
6449 STRCPY(pat3, pat2);
6450 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006451 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006452 spat, epat, mpat);
6453 if (flags & SP_START)
6454 options |= SEARCH_START;
6455
Bram Moolenaar48570482017-10-30 21:48:41 +01006456 if (skip != NULL)
6457 {
6458 /* Empty string means to not use the skip expression. */
6459 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6460 use_skip = skip->vval.v_string != NULL
6461 && *skip->vval.v_string != NUL;
6462 }
6463
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006464 save_cursor = curwin->w_cursor;
6465 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006466 CLEAR_POS(&firstpos);
6467 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006468 pat = pat3;
6469 for (;;)
6470 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006471 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006472 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006473 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 /* didn't find it or found the first match again: FAIL */
6475 break;
6476
6477 if (firstpos.lnum == 0)
6478 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006479 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006480 {
6481 /* Found the same position again. Can happen with a pattern that
6482 * has "\zs" at the end and searching backwards. Advance one
6483 * character and try again. */
6484 if (dir == BACKWARD)
6485 decl(&pos);
6486 else
6487 incl(&pos);
6488 }
6489 foundpos = pos;
6490
6491 /* clear the start flag to avoid getting stuck here */
6492 options &= ~SEARCH_START;
6493
6494 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006495 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 {
6497 save_pos = curwin->w_cursor;
6498 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006499 err = FALSE;
6500 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 curwin->w_cursor = save_pos;
6502 if (err)
6503 {
6504 /* Evaluating {skip} caused an error, break here. */
6505 curwin->w_cursor = save_cursor;
6506 retval = -1;
6507 break;
6508 }
6509 if (r)
6510 continue;
6511 }
6512
6513 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6514 {
6515 /* Found end when searching backwards or start when searching
6516 * forward: nested pair. */
6517 ++nest;
6518 pat = pat2; /* nested, don't search for middle */
6519 }
6520 else
6521 {
6522 /* Found end when searching forward or start when searching
6523 * backward: end of (nested) pair; or found middle in outer pair. */
6524 if (--nest == 1)
6525 pat = pat3; /* outer level, search for middle */
6526 }
6527
6528 if (nest == 0)
6529 {
6530 /* Found the match: return matchcount or line number. */
6531 if (flags & SP_RETCOUNT)
6532 ++retval;
6533 else
6534 retval = pos.lnum;
6535 if (flags & SP_SETPCMARK)
6536 setpcmark();
6537 curwin->w_cursor = pos;
6538 if (!(flags & SP_REPEAT))
6539 break;
6540 nest = 1; /* search for next unmatched */
6541 }
6542 }
6543
6544 if (match_pos != NULL)
6545 {
6546 /* Store the match cursor position */
6547 match_pos->lnum = curwin->w_cursor.lnum;
6548 match_pos->col = curwin->w_cursor.col + 1;
6549 }
6550
6551 /* If 'n' flag is used or search failed: restore cursor position. */
6552 if ((flags & SP_NOMOVE) || retval == 0)
6553 curwin->w_cursor = save_cursor;
6554
6555theend:
6556 vim_free(pat2);
6557 vim_free(pat3);
6558 if (p_cpo == empty_option)
6559 p_cpo = save_cpo;
6560 else
6561 /* Darn, evaluating the {skip} expression changed the value. */
6562 free_string_option(save_cpo);
6563
6564 return retval;
6565}
6566
6567/*
6568 * "searchpos()" function
6569 */
6570 static void
6571f_searchpos(typval_T *argvars, typval_T *rettv)
6572{
6573 pos_T match_pos;
6574 int lnum = 0;
6575 int col = 0;
6576 int n;
6577 int flags = 0;
6578
6579 if (rettv_list_alloc(rettv) == FAIL)
6580 return;
6581
6582 n = search_cmn(argvars, &match_pos, &flags);
6583 if (n > 0)
6584 {
6585 lnum = match_pos.lnum;
6586 col = match_pos.col;
6587 }
6588
6589 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6590 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6591 if (flags & SP_SUBPAT)
6592 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6593}
6594
6595 static void
6596f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6597{
6598#ifdef FEAT_CLIENTSERVER
6599 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006600 char_u *server = tv_get_string_chk(&argvars[0]);
6601 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602
6603 rettv->vval.v_number = -1;
6604 if (server == NULL || reply == NULL)
6605 return;
6606 if (check_restricted() || check_secure())
6607 return;
6608# ifdef FEAT_X11
6609 if (check_connection() == FAIL)
6610 return;
6611# endif
6612
6613 if (serverSendReply(server, reply) < 0)
6614 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006615 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616 return;
6617 }
6618 rettv->vval.v_number = 0;
6619#else
6620 rettv->vval.v_number = -1;
6621#endif
6622}
6623
6624 static void
6625f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6626{
6627 char_u *r = NULL;
6628
6629#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006630# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006631 r = serverGetVimNames();
6632# else
6633 make_connection();
6634 if (X_DISPLAY != NULL)
6635 r = serverGetVimNames(X_DISPLAY);
6636# endif
6637#endif
6638 rettv->v_type = VAR_STRING;
6639 rettv->vval.v_string = r;
6640}
6641
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 static void
6643f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6644{
6645 dict_T *d;
6646 dictitem_T *di;
6647 char_u *csearch;
6648
6649 if (argvars[0].v_type != VAR_DICT)
6650 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006651 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652 return;
6653 }
6654
6655 if ((d = argvars[0].vval.v_dict) != NULL)
6656 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006657 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006658 if (csearch != NULL)
6659 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006660 if (enc_utf8)
6661 {
6662 int pcc[MAX_MCO];
6663 int c = utfc_ptr2char(csearch, pcc);
6664
6665 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6666 }
6667 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006668 set_last_csearch(PTR2CHAR(csearch),
6669 csearch, MB_PTR2LEN(csearch));
6670 }
6671
6672 di = dict_find(d, (char_u *)"forward", -1);
6673 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006674 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675 ? FORWARD : BACKWARD);
6676
6677 di = dict_find(d, (char_u *)"until", -1);
6678 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006679 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006680 }
6681}
6682
6683/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006684 * "setenv()" function
6685 */
6686 static void
6687f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6688{
6689 char_u namebuf[NUMBUFLEN];
6690 char_u valbuf[NUMBUFLEN];
6691 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6692
6693 if (argvars[1].v_type == VAR_SPECIAL
6694 && argvars[1].vval.v_number == VVAL_NULL)
6695 vim_unsetenv(name);
6696 else
6697 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6698}
6699
6700/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 * "setfperm({fname}, {mode})" function
6702 */
6703 static void
6704f_setfperm(typval_T *argvars, typval_T *rettv)
6705{
6706 char_u *fname;
6707 char_u modebuf[NUMBUFLEN];
6708 char_u *mode_str;
6709 int i;
6710 int mask;
6711 int mode = 0;
6712
6713 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006714 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006715 if (fname == NULL)
6716 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006717 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 if (mode_str == NULL)
6719 return;
6720 if (STRLEN(mode_str) != 9)
6721 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006722 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006723 return;
6724 }
6725
6726 mask = 1;
6727 for (i = 8; i >= 0; --i)
6728 {
6729 if (mode_str[i] != '-')
6730 mode |= mask;
6731 mask = mask << 1;
6732 }
6733 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6734}
6735
6736/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 * "setpos()" function
6738 */
6739 static void
6740f_setpos(typval_T *argvars, typval_T *rettv)
6741{
6742 pos_T pos;
6743 int fnum;
6744 char_u *name;
6745 colnr_T curswant = -1;
6746
6747 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006748 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006749 if (name != NULL)
6750 {
6751 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6752 {
6753 if (--pos.col < 0)
6754 pos.col = 0;
6755 if (name[0] == '.' && name[1] == NUL)
6756 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006757 /* set cursor; "fnum" is ignored */
6758 curwin->w_cursor = pos;
6759 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006760 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006761 curwin->w_curswant = curswant - 1;
6762 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006763 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006764 check_cursor();
6765 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006766 }
6767 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6768 {
6769 /* set mark */
6770 if (setmark_pos(name[1], &pos, fnum) == OK)
6771 rettv->vval.v_number = 0;
6772 }
6773 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006774 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006775 }
6776 }
6777}
6778
6779/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006780 * "setreg()" function
6781 */
6782 static void
6783f_setreg(typval_T *argvars, typval_T *rettv)
6784{
6785 int regname;
6786 char_u *strregname;
6787 char_u *stropt;
6788 char_u *strval;
6789 int append;
6790 char_u yank_type;
6791 long block_len;
6792
6793 block_len = -1;
6794 yank_type = MAUTO;
6795 append = FALSE;
6796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006797 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006798 rettv->vval.v_number = 1; /* FAIL is default */
6799
6800 if (strregname == NULL)
6801 return; /* type error; errmsg already given */
6802 regname = *strregname;
6803 if (regname == 0 || regname == '@')
6804 regname = '"';
6805
6806 if (argvars[2].v_type != VAR_UNKNOWN)
6807 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006808 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006809 if (stropt == NULL)
6810 return; /* type error */
6811 for (; *stropt != NUL; ++stropt)
6812 switch (*stropt)
6813 {
6814 case 'a': case 'A': /* append */
6815 append = TRUE;
6816 break;
6817 case 'v': case 'c': /* character-wise selection */
6818 yank_type = MCHAR;
6819 break;
6820 case 'V': case 'l': /* line-wise selection */
6821 yank_type = MLINE;
6822 break;
6823 case 'b': case Ctrl_V: /* block-wise selection */
6824 yank_type = MBLOCK;
6825 if (VIM_ISDIGIT(stropt[1]))
6826 {
6827 ++stropt;
6828 block_len = getdigits(&stropt) - 1;
6829 --stropt;
6830 }
6831 break;
6832 }
6833 }
6834
6835 if (argvars[1].v_type == VAR_LIST)
6836 {
6837 char_u **lstval;
6838 char_u **allocval;
6839 char_u buf[NUMBUFLEN];
6840 char_u **curval;
6841 char_u **curallocval;
6842 list_T *ll = argvars[1].vval.v_list;
6843 listitem_T *li;
6844 int len;
6845
6846 /* If the list is NULL handle like an empty list. */
6847 len = ll == NULL ? 0 : ll->lv_len;
6848
6849 /* First half: use for pointers to result lines; second half: use for
6850 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006851 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006852 if (lstval == NULL)
6853 return;
6854 curval = lstval;
6855 allocval = lstval + len + 2;
6856 curallocval = allocval;
6857
6858 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6859 li = li->li_next)
6860 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006861 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 if (strval == NULL)
6863 goto free_lstval;
6864 if (strval == buf)
6865 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006866 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006867 * overwrite the string. */
6868 strval = vim_strsave(buf);
6869 if (strval == NULL)
6870 goto free_lstval;
6871 *curallocval++ = strval;
6872 }
6873 *curval++ = strval;
6874 }
6875 *curval++ = NULL;
6876
6877 write_reg_contents_lst(regname, lstval, -1,
6878 append, yank_type, block_len);
6879free_lstval:
6880 while (curallocval > allocval)
6881 vim_free(*--curallocval);
6882 vim_free(lstval);
6883 }
6884 else
6885 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006886 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006887 if (strval == NULL)
6888 return;
6889 write_reg_contents_ex(regname, strval, -1,
6890 append, yank_type, block_len);
6891 }
6892 rettv->vval.v_number = 0;
6893}
6894
6895/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006896 * "settagstack()" function
6897 */
6898 static void
6899f_settagstack(typval_T *argvars, typval_T *rettv)
6900{
6901 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6902 win_T *wp;
6903 dict_T *d;
6904 int action = 'r';
6905
6906 rettv->vval.v_number = -1;
6907
6908 // first argument: window number or id
6909 wp = find_win_by_nr_or_id(&argvars[0]);
6910 if (wp == NULL)
6911 return;
6912
6913 // second argument: dict with items to set in the tag stack
6914 if (argvars[1].v_type != VAR_DICT)
6915 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006916 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006917 return;
6918 }
6919 d = argvars[1].vval.v_dict;
6920 if (d == NULL)
6921 return;
6922
6923 // third argument: action - 'a' for append and 'r' for replace.
6924 // default is to replace the stack.
6925 if (argvars[2].v_type == VAR_UNKNOWN)
6926 action = 'r';
6927 else if (argvars[2].v_type == VAR_STRING)
6928 {
6929 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006930 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006931 if (actstr == NULL)
6932 return;
6933 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6934 action = *actstr;
6935 else
6936 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006937 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006938 return;
6939 }
6940 }
6941 else
6942 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006943 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006944 return;
6945 }
6946
6947 if (set_tagstack(wp, d, action) == OK)
6948 rettv->vval.v_number = 0;
6949}
6950
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006951#ifdef FEAT_CRYPT
6952/*
6953 * "sha256({string})" function
6954 */
6955 static void
6956f_sha256(typval_T *argvars, typval_T *rettv)
6957{
6958 char_u *p;
6959
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006960 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961 rettv->vval.v_string = vim_strsave(
6962 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6963 rettv->v_type = VAR_STRING;
6964}
6965#endif /* FEAT_CRYPT */
6966
6967/*
6968 * "shellescape({string})" function
6969 */
6970 static void
6971f_shellescape(typval_T *argvars, typval_T *rettv)
6972{
Bram Moolenaar20615522017-06-05 18:46:26 +02006973 int do_special = non_zero_arg(&argvars[1]);
6974
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006976 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006977 rettv->v_type = VAR_STRING;
6978}
6979
6980/*
6981 * shiftwidth() function
6982 */
6983 static void
6984f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6985{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006986 rettv->vval.v_number = 0;
6987
6988 if (argvars[0].v_type != VAR_UNKNOWN)
6989 {
6990 long col;
6991
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006992 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006993 if (col < 0)
6994 return; // type error; errmsg already given
6995#ifdef FEAT_VARTABS
6996 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6997 return;
6998#endif
6999 }
7000
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007001 rettv->vval.v_number = get_sw_value(curbuf);
7002}
7003
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007004#ifdef FEAT_FLOAT
7005/*
7006 * "sin()" function
7007 */
7008 static void
7009f_sin(typval_T *argvars, typval_T *rettv)
7010{
7011 float_T f = 0.0;
7012
7013 rettv->v_type = VAR_FLOAT;
7014 if (get_float_arg(argvars, &f) == OK)
7015 rettv->vval.v_float = sin(f);
7016 else
7017 rettv->vval.v_float = 0.0;
7018}
7019
7020/*
7021 * "sinh()" function
7022 */
7023 static void
7024f_sinh(typval_T *argvars, typval_T *rettv)
7025{
7026 float_T f = 0.0;
7027
7028 rettv->v_type = VAR_FLOAT;
7029 if (get_float_arg(argvars, &f) == OK)
7030 rettv->vval.v_float = sinh(f);
7031 else
7032 rettv->vval.v_float = 0.0;
7033}
7034#endif
7035
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036/*
7037 * "soundfold({word})" function
7038 */
7039 static void
7040f_soundfold(typval_T *argvars, typval_T *rettv)
7041{
7042 char_u *s;
7043
7044 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007045 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007046#ifdef FEAT_SPELL
7047 rettv->vval.v_string = eval_soundfold(s);
7048#else
7049 rettv->vval.v_string = vim_strsave(s);
7050#endif
7051}
7052
7053/*
7054 * "spellbadword()" function
7055 */
7056 static void
7057f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7058{
7059 char_u *word = (char_u *)"";
7060 hlf_T attr = HLF_COUNT;
7061 int len = 0;
7062
7063 if (rettv_list_alloc(rettv) == FAIL)
7064 return;
7065
7066#ifdef FEAT_SPELL
7067 if (argvars[0].v_type == VAR_UNKNOWN)
7068 {
7069 /* Find the start and length of the badly spelled word. */
7070 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7071 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007072 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007073 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007074 curwin->w_set_curswant = TRUE;
7075 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007076 }
7077 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7078 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007079 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 int capcol = -1;
7081
7082 if (str != NULL)
7083 {
7084 /* Check the argument for spelling. */
7085 while (*str != NUL)
7086 {
7087 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7088 if (attr != HLF_COUNT)
7089 {
7090 word = str;
7091 break;
7092 }
7093 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007094 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007095 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007096 }
7097 }
7098 }
7099#endif
7100
7101 list_append_string(rettv->vval.v_list, word, len);
7102 list_append_string(rettv->vval.v_list, (char_u *)(
7103 attr == HLF_SPB ? "bad" :
7104 attr == HLF_SPR ? "rare" :
7105 attr == HLF_SPL ? "local" :
7106 attr == HLF_SPC ? "caps" :
7107 ""), -1);
7108}
7109
7110/*
7111 * "spellsuggest()" function
7112 */
7113 static void
7114f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7115{
7116#ifdef FEAT_SPELL
7117 char_u *str;
7118 int typeerr = FALSE;
7119 int maxcount;
7120 garray_T ga;
7121 int i;
7122 listitem_T *li;
7123 int need_capital = FALSE;
7124#endif
7125
7126 if (rettv_list_alloc(rettv) == FAIL)
7127 return;
7128
7129#ifdef FEAT_SPELL
7130 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7131 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007132 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007133 if (argvars[1].v_type != VAR_UNKNOWN)
7134 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007135 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 if (maxcount <= 0)
7137 return;
7138 if (argvars[2].v_type != VAR_UNKNOWN)
7139 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007140 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007141 if (typeerr)
7142 return;
7143 }
7144 }
7145 else
7146 maxcount = 25;
7147
7148 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7149
7150 for (i = 0; i < ga.ga_len; ++i)
7151 {
7152 str = ((char_u **)ga.ga_data)[i];
7153
7154 li = listitem_alloc();
7155 if (li == NULL)
7156 vim_free(str);
7157 else
7158 {
7159 li->li_tv.v_type = VAR_STRING;
7160 li->li_tv.v_lock = 0;
7161 li->li_tv.vval.v_string = str;
7162 list_append(rettv->vval.v_list, li);
7163 }
7164 }
7165 ga_clear(&ga);
7166 }
7167#endif
7168}
7169
7170 static void
7171f_split(typval_T *argvars, typval_T *rettv)
7172{
7173 char_u *str;
7174 char_u *end;
7175 char_u *pat = NULL;
7176 regmatch_T regmatch;
7177 char_u patbuf[NUMBUFLEN];
7178 char_u *save_cpo;
7179 int match;
7180 colnr_T col = 0;
7181 int keepempty = FALSE;
7182 int typeerr = FALSE;
7183
7184 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7185 save_cpo = p_cpo;
7186 p_cpo = (char_u *)"";
7187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007188 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007189 if (argvars[1].v_type != VAR_UNKNOWN)
7190 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007191 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007192 if (pat == NULL)
7193 typeerr = TRUE;
7194 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007195 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007196 }
7197 if (pat == NULL || *pat == NUL)
7198 pat = (char_u *)"[\\x01- ]\\+";
7199
7200 if (rettv_list_alloc(rettv) == FAIL)
7201 return;
7202 if (typeerr)
7203 return;
7204
7205 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7206 if (regmatch.regprog != NULL)
7207 {
7208 regmatch.rm_ic = FALSE;
7209 while (*str != NUL || keepempty)
7210 {
7211 if (*str == NUL)
7212 match = FALSE; /* empty item at the end */
7213 else
7214 match = vim_regexec_nl(&regmatch, str, col);
7215 if (match)
7216 end = regmatch.startp[0];
7217 else
7218 end = str + STRLEN(str);
7219 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7220 && *str != NUL && match && end < regmatch.endp[0]))
7221 {
7222 if (list_append_string(rettv->vval.v_list, str,
7223 (int)(end - str)) == FAIL)
7224 break;
7225 }
7226 if (!match)
7227 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007228 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229 if (regmatch.endp[0] > str)
7230 col = 0;
7231 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007232 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007234 str = regmatch.endp[0];
7235 }
7236
7237 vim_regfree(regmatch.regprog);
7238 }
7239
7240 p_cpo = save_cpo;
7241}
7242
7243#ifdef FEAT_FLOAT
7244/*
7245 * "sqrt()" function
7246 */
7247 static void
7248f_sqrt(typval_T *argvars, typval_T *rettv)
7249{
7250 float_T f = 0.0;
7251
7252 rettv->v_type = VAR_FLOAT;
7253 if (get_float_arg(argvars, &f) == OK)
7254 rettv->vval.v_float = sqrt(f);
7255 else
7256 rettv->vval.v_float = 0.0;
7257}
7258
7259/*
7260 * "str2float()" function
7261 */
7262 static void
7263f_str2float(typval_T *argvars, typval_T *rettv)
7264{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007265 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007266 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267
Bram Moolenaar08243d22017-01-10 16:12:29 +01007268 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007269 p = skipwhite(p + 1);
7270 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007271 if (isneg)
7272 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007273 rettv->v_type = VAR_FLOAT;
7274}
7275#endif
7276
7277/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007278 * "str2list()" function
7279 */
7280 static void
7281f_str2list(typval_T *argvars, typval_T *rettv)
7282{
7283 char_u *p;
7284 int utf8 = FALSE;
7285
7286 if (rettv_list_alloc(rettv) == FAIL)
7287 return;
7288
7289 if (argvars[1].v_type != VAR_UNKNOWN)
7290 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7291
7292 p = tv_get_string(&argvars[0]);
7293
7294 if (has_mbyte || utf8)
7295 {
7296 int (*ptr2len)(char_u *);
7297 int (*ptr2char)(char_u *);
7298
7299 if (utf8 || enc_utf8)
7300 {
7301 ptr2len = utf_ptr2len;
7302 ptr2char = utf_ptr2char;
7303 }
7304 else
7305 {
7306 ptr2len = mb_ptr2len;
7307 ptr2char = mb_ptr2char;
7308 }
7309
7310 for ( ; *p != NUL; p += (*ptr2len)(p))
7311 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7312 }
7313 else
7314 for ( ; *p != NUL; ++p)
7315 list_append_number(rettv->vval.v_list, *p);
7316}
7317
7318/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319 * "str2nr()" function
7320 */
7321 static void
7322f_str2nr(typval_T *argvars, typval_T *rettv)
7323{
7324 int base = 10;
7325 char_u *p;
7326 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007327 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007328 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007329
7330 if (argvars[1].v_type != VAR_UNKNOWN)
7331 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007332 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007333 if (base != 2 && base != 8 && base != 10 && base != 16)
7334 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007335 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336 return;
7337 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007338 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7339 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007340 }
7341
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007342 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007343 isneg = (*p == '-');
7344 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 p = skipwhite(p + 1);
7346 switch (base)
7347 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007348 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7349 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7350 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007352 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7353 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007354 if (isneg)
7355 rettv->vval.v_number = -n;
7356 else
7357 rettv->vval.v_number = n;
7358
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007359}
7360
7361#ifdef HAVE_STRFTIME
7362/*
7363 * "strftime({format}[, {time}])" function
7364 */
7365 static void
7366f_strftime(typval_T *argvars, typval_T *rettv)
7367{
7368 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007369 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007370 struct tm *curtime;
7371 time_t seconds;
7372 char_u *p;
7373
7374 rettv->v_type = VAR_STRING;
7375
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007376 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 if (argvars[1].v_type == VAR_UNKNOWN)
7378 seconds = time(NULL);
7379 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007380 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007381 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 /* MSVC returns NULL for an invalid value of seconds. */
7383 if (curtime == NULL)
7384 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7385 else
7386 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 vimconv_T conv;
7388 char_u *enc;
7389
7390 conv.vc_type = CONV_NONE;
7391 enc = enc_locale();
7392 convert_setup(&conv, p_enc, enc);
7393 if (conv.vc_type != CONV_NONE)
7394 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007395 if (p != NULL)
7396 (void)strftime((char *)result_buf, sizeof(result_buf),
7397 (char *)p, curtime);
7398 else
7399 result_buf[0] = NUL;
7400
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007401 if (conv.vc_type != CONV_NONE)
7402 vim_free(p);
7403 convert_setup(&conv, enc, p_enc);
7404 if (conv.vc_type != CONV_NONE)
7405 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7406 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 rettv->vval.v_string = vim_strsave(result_buf);
7408
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409 /* Release conversion descriptors */
7410 convert_setup(&conv, NULL, NULL);
7411 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 }
7413}
7414#endif
7415
7416/*
7417 * "strgetchar()" function
7418 */
7419 static void
7420f_strgetchar(typval_T *argvars, typval_T *rettv)
7421{
7422 char_u *str;
7423 int len;
7424 int error = FALSE;
7425 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007426 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427
7428 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007429 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007430 if (str == NULL)
7431 return;
7432 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007433 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 if (error)
7435 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007436
Bram Moolenaar13505972019-01-24 15:04:48 +01007437 while (charidx >= 0 && byteidx < len)
7438 {
7439 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007441 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7442 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007443 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007444 --charidx;
7445 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007446 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007447}
7448
7449/*
7450 * "stridx()" function
7451 */
7452 static void
7453f_stridx(typval_T *argvars, typval_T *rettv)
7454{
7455 char_u buf[NUMBUFLEN];
7456 char_u *needle;
7457 char_u *haystack;
7458 char_u *save_haystack;
7459 char_u *pos;
7460 int start_idx;
7461
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007462 needle = tv_get_string_chk(&argvars[1]);
7463 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464 rettv->vval.v_number = -1;
7465 if (needle == NULL || haystack == NULL)
7466 return; /* type error; errmsg already given */
7467
7468 if (argvars[2].v_type != VAR_UNKNOWN)
7469 {
7470 int error = FALSE;
7471
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007472 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007473 if (error || start_idx >= (int)STRLEN(haystack))
7474 return;
7475 if (start_idx >= 0)
7476 haystack += start_idx;
7477 }
7478
7479 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7480 if (pos != NULL)
7481 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7482}
7483
7484/*
7485 * "string()" function
7486 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007487 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488f_string(typval_T *argvars, typval_T *rettv)
7489{
7490 char_u *tofree;
7491 char_u numbuf[NUMBUFLEN];
7492
7493 rettv->v_type = VAR_STRING;
7494 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7495 get_copyID());
7496 /* Make a copy if we have a value but it's not in allocated memory. */
7497 if (rettv->vval.v_string != NULL && tofree == NULL)
7498 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7499}
7500
7501/*
7502 * "strlen()" function
7503 */
7504 static void
7505f_strlen(typval_T *argvars, typval_T *rettv)
7506{
7507 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007508 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007509}
7510
7511/*
7512 * "strchars()" function
7513 */
7514 static void
7515f_strchars(typval_T *argvars, typval_T *rettv)
7516{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007517 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519 varnumber_T len = 0;
7520 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521
7522 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007523 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007525 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 else
7527 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007528 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7529 while (*s != NUL)
7530 {
7531 func_mb_ptr2char_adv(&s);
7532 ++len;
7533 }
7534 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007535 }
7536}
7537
7538/*
7539 * "strdisplaywidth()" function
7540 */
7541 static void
7542f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7543{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007544 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007545 int col = 0;
7546
7547 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007548 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007549
7550 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7551}
7552
7553/*
7554 * "strwidth()" function
7555 */
7556 static void
7557f_strwidth(typval_T *argvars, typval_T *rettv)
7558{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007559 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007560
Bram Moolenaar13505972019-01-24 15:04:48 +01007561 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007562}
7563
7564/*
7565 * "strcharpart()" function
7566 */
7567 static void
7568f_strcharpart(typval_T *argvars, typval_T *rettv)
7569{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570 char_u *p;
7571 int nchar;
7572 int nbyte = 0;
7573 int charlen;
7574 int len = 0;
7575 int slen;
7576 int error = FALSE;
7577
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007578 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007579 slen = (int)STRLEN(p);
7580
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007581 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007582 if (!error)
7583 {
7584 if (nchar > 0)
7585 while (nchar > 0 && nbyte < slen)
7586 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007587 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588 --nchar;
7589 }
7590 else
7591 nbyte = nchar;
7592 if (argvars[2].v_type != VAR_UNKNOWN)
7593 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007594 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007595 while (charlen > 0 && nbyte + len < slen)
7596 {
7597 int off = nbyte + len;
7598
7599 if (off < 0)
7600 len += 1;
7601 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007602 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007603 --charlen;
7604 }
7605 }
7606 else
7607 len = slen - nbyte; /* default: all bytes that are available. */
7608 }
7609
7610 /*
7611 * Only return the overlap between the specified part and the actual
7612 * string.
7613 */
7614 if (nbyte < 0)
7615 {
7616 len += nbyte;
7617 nbyte = 0;
7618 }
7619 else if (nbyte > slen)
7620 nbyte = slen;
7621 if (len < 0)
7622 len = 0;
7623 else if (nbyte + len > slen)
7624 len = slen - nbyte;
7625
7626 rettv->v_type = VAR_STRING;
7627 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007628}
7629
7630/*
7631 * "strpart()" function
7632 */
7633 static void
7634f_strpart(typval_T *argvars, typval_T *rettv)
7635{
7636 char_u *p;
7637 int n;
7638 int len;
7639 int slen;
7640 int error = FALSE;
7641
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007642 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007643 slen = (int)STRLEN(p);
7644
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007645 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007646 if (error)
7647 len = 0;
7648 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007649 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650 else
7651 len = slen - n; /* default len: all bytes that are available. */
7652
7653 /*
7654 * Only return the overlap between the specified part and the actual
7655 * string.
7656 */
7657 if (n < 0)
7658 {
7659 len += n;
7660 n = 0;
7661 }
7662 else if (n > slen)
7663 n = slen;
7664 if (len < 0)
7665 len = 0;
7666 else if (n + len > slen)
7667 len = slen - n;
7668
7669 rettv->v_type = VAR_STRING;
7670 rettv->vval.v_string = vim_strnsave(p + n, len);
7671}
7672
7673/*
7674 * "strridx()" function
7675 */
7676 static void
7677f_strridx(typval_T *argvars, typval_T *rettv)
7678{
7679 char_u buf[NUMBUFLEN];
7680 char_u *needle;
7681 char_u *haystack;
7682 char_u *rest;
7683 char_u *lastmatch = NULL;
7684 int haystack_len, end_idx;
7685
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007686 needle = tv_get_string_chk(&argvars[1]);
7687 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007688
7689 rettv->vval.v_number = -1;
7690 if (needle == NULL || haystack == NULL)
7691 return; /* type error; errmsg already given */
7692
7693 haystack_len = (int)STRLEN(haystack);
7694 if (argvars[2].v_type != VAR_UNKNOWN)
7695 {
7696 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007697 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007698 if (end_idx < 0)
7699 return; /* can never find a match */
7700 }
7701 else
7702 end_idx = haystack_len;
7703
7704 if (*needle == NUL)
7705 {
7706 /* Empty string matches past the end. */
7707 lastmatch = haystack + end_idx;
7708 }
7709 else
7710 {
7711 for (rest = haystack; *rest != '\0'; ++rest)
7712 {
7713 rest = (char_u *)strstr((char *)rest, (char *)needle);
7714 if (rest == NULL || rest > haystack + end_idx)
7715 break;
7716 lastmatch = rest;
7717 }
7718 }
7719
7720 if (lastmatch == NULL)
7721 rettv->vval.v_number = -1;
7722 else
7723 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7724}
7725
7726/*
7727 * "strtrans()" function
7728 */
7729 static void
7730f_strtrans(typval_T *argvars, typval_T *rettv)
7731{
7732 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007733 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007734}
7735
7736/*
7737 * "submatch()" function
7738 */
7739 static void
7740f_submatch(typval_T *argvars, typval_T *rettv)
7741{
7742 int error = FALSE;
7743 int no;
7744 int retList = 0;
7745
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007746 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747 if (error)
7748 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007749 if (no < 0 || no >= NSUBEXP)
7750 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007751 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007752 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007753 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007754 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007755 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756 if (error)
7757 return;
7758
7759 if (retList == 0)
7760 {
7761 rettv->v_type = VAR_STRING;
7762 rettv->vval.v_string = reg_submatch(no);
7763 }
7764 else
7765 {
7766 rettv->v_type = VAR_LIST;
7767 rettv->vval.v_list = reg_submatch_list(no);
7768 }
7769}
7770
7771/*
7772 * "substitute()" function
7773 */
7774 static void
7775f_substitute(typval_T *argvars, typval_T *rettv)
7776{
7777 char_u patbuf[NUMBUFLEN];
7778 char_u subbuf[NUMBUFLEN];
7779 char_u flagsbuf[NUMBUFLEN];
7780
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007781 char_u *str = tv_get_string_chk(&argvars[0]);
7782 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007783 char_u *sub = NULL;
7784 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007785 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007786
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007787 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7788 expr = &argvars[2];
7789 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007790 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007791
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007792 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007793 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7794 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795 rettv->vval.v_string = NULL;
7796 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007797 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798}
7799
7800/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007801 * "swapinfo(swap_filename)" function
7802 */
7803 static void
7804f_swapinfo(typval_T *argvars, typval_T *rettv)
7805{
7806 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007807 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007808}
7809
7810/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007811 * "swapname(expr)" function
7812 */
7813 static void
7814f_swapname(typval_T *argvars, typval_T *rettv)
7815{
7816 buf_T *buf;
7817
7818 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007819 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007820 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7821 || buf->b_ml.ml_mfp->mf_fname == NULL)
7822 rettv->vval.v_string = NULL;
7823 else
7824 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7825}
7826
7827/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007828 * "synID(lnum, col, trans)" function
7829 */
7830 static void
7831f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7832{
7833 int id = 0;
7834#ifdef FEAT_SYN_HL
7835 linenr_T lnum;
7836 colnr_T col;
7837 int trans;
7838 int transerr = FALSE;
7839
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007840 lnum = tv_get_lnum(argvars); /* -1 on type error */
7841 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7842 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843
7844 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7845 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7846 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7847#endif
7848
7849 rettv->vval.v_number = id;
7850}
7851
7852/*
7853 * "synIDattr(id, what [, mode])" function
7854 */
7855 static void
7856f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7857{
7858 char_u *p = NULL;
7859#ifdef FEAT_SYN_HL
7860 int id;
7861 char_u *what;
7862 char_u *mode;
7863 char_u modebuf[NUMBUFLEN];
7864 int modec;
7865
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007866 id = (int)tv_get_number(&argvars[0]);
7867 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 if (argvars[2].v_type != VAR_UNKNOWN)
7869 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007870 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871 modec = TOLOWER_ASC(mode[0]);
7872 if (modec != 't' && modec != 'c' && modec != 'g')
7873 modec = 0; /* replace invalid with current */
7874 }
7875 else
7876 {
7877#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7878 if (USE_24BIT)
7879 modec = 'g';
7880 else
7881#endif
7882 if (t_colors > 1)
7883 modec = 'c';
7884 else
7885 modec = 't';
7886 }
7887
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007888 switch (TOLOWER_ASC(what[0]))
7889 {
7890 case 'b':
7891 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7892 p = highlight_color(id, what, modec);
7893 else /* bold */
7894 p = highlight_has_attr(id, HL_BOLD, modec);
7895 break;
7896
7897 case 'f': /* fg[#] or font */
7898 p = highlight_color(id, what, modec);
7899 break;
7900
7901 case 'i':
7902 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7903 p = highlight_has_attr(id, HL_INVERSE, modec);
7904 else /* italic */
7905 p = highlight_has_attr(id, HL_ITALIC, modec);
7906 break;
7907
7908 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007909 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910 break;
7911
7912 case 'r': /* reverse */
7913 p = highlight_has_attr(id, HL_INVERSE, modec);
7914 break;
7915
7916 case 's':
7917 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7918 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007919 /* strikeout */
7920 else if (TOLOWER_ASC(what[1]) == 't' &&
7921 TOLOWER_ASC(what[2]) == 'r')
7922 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007923 else /* standout */
7924 p = highlight_has_attr(id, HL_STANDOUT, modec);
7925 break;
7926
7927 case 'u':
7928 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7929 /* underline */
7930 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7931 else
7932 /* undercurl */
7933 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7934 break;
7935 }
7936
7937 if (p != NULL)
7938 p = vim_strsave(p);
7939#endif
7940 rettv->v_type = VAR_STRING;
7941 rettv->vval.v_string = p;
7942}
7943
7944/*
7945 * "synIDtrans(id)" function
7946 */
7947 static void
7948f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7949{
7950 int id;
7951
7952#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007953 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954
7955 if (id > 0)
7956 id = syn_get_final_id(id);
7957 else
7958#endif
7959 id = 0;
7960
7961 rettv->vval.v_number = id;
7962}
7963
7964/*
7965 * "synconcealed(lnum, col)" function
7966 */
7967 static void
7968f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7969{
7970#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7971 linenr_T lnum;
7972 colnr_T col;
7973 int syntax_flags = 0;
7974 int cchar;
7975 int matchid = 0;
7976 char_u str[NUMBUFLEN];
7977#endif
7978
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007979 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980
7981#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007982 lnum = tv_get_lnum(argvars); /* -1 on type error */
7983 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984
7985 vim_memset(str, NUL, sizeof(str));
7986
7987 if (rettv_list_alloc(rettv) != FAIL)
7988 {
7989 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7990 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7991 && curwin->w_p_cole > 0)
7992 {
7993 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7994 syntax_flags = get_syntax_info(&matchid);
7995
7996 /* get the conceal character */
7997 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7998 {
7999 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008000 if (cchar == NUL && curwin->w_p_cole == 1)
8001 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002 if (cchar != NUL)
8003 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 if (has_mbyte)
8005 (*mb_char2bytes)(cchar, str);
8006 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007 str[0] = cchar;
8008 }
8009 }
8010 }
8011
8012 list_append_number(rettv->vval.v_list,
8013 (syntax_flags & HL_CONCEAL) != 0);
8014 /* -1 to auto-determine strlen */
8015 list_append_string(rettv->vval.v_list, str, -1);
8016 list_append_number(rettv->vval.v_list, matchid);
8017 }
8018#endif
8019}
8020
8021/*
8022 * "synstack(lnum, col)" function
8023 */
8024 static void
8025f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8026{
8027#ifdef FEAT_SYN_HL
8028 linenr_T lnum;
8029 colnr_T col;
8030 int i;
8031 int id;
8032#endif
8033
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008034 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008035
8036#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008037 lnum = tv_get_lnum(argvars); /* -1 on type error */
8038 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039
8040 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8041 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8042 && rettv_list_alloc(rettv) != FAIL)
8043 {
8044 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8045 for (i = 0; ; ++i)
8046 {
8047 id = syn_get_stack_item(i);
8048 if (id < 0)
8049 break;
8050 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8051 break;
8052 }
8053 }
8054#endif
8055}
8056
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008057/*
8058 * "tabpagebuflist()" function
8059 */
8060 static void
8061f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8062{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063 tabpage_T *tp;
8064 win_T *wp = NULL;
8065
8066 if (argvars[0].v_type == VAR_UNKNOWN)
8067 wp = firstwin;
8068 else
8069 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008070 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008071 if (tp != NULL)
8072 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8073 }
8074 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8075 {
8076 for (; wp != NULL; wp = wp->w_next)
8077 if (list_append_number(rettv->vval.v_list,
8078 wp->w_buffer->b_fnum) == FAIL)
8079 break;
8080 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081}
8082
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084 * "tagfiles()" function
8085 */
8086 static void
8087f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8088{
8089 char_u *fname;
8090 tagname_T tn;
8091 int first;
8092
8093 if (rettv_list_alloc(rettv) == FAIL)
8094 return;
8095 fname = alloc(MAXPATHL);
8096 if (fname == NULL)
8097 return;
8098
8099 for (first = TRUE; ; first = FALSE)
8100 if (get_tagfname(&tn, first, fname) == FAIL
8101 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8102 break;
8103 tagname_free(&tn);
8104 vim_free(fname);
8105}
8106
8107/*
8108 * "taglist()" function
8109 */
8110 static void
8111f_taglist(typval_T *argvars, typval_T *rettv)
8112{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008113 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008114 char_u *tag_pattern;
8115
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008116 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008117
8118 rettv->vval.v_number = FALSE;
8119 if (*tag_pattern == NUL)
8120 return;
8121
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008122 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008123 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008124 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008125 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008126}
8127
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128#ifdef FEAT_FLOAT
8129/*
8130 * "tan()" function
8131 */
8132 static void
8133f_tan(typval_T *argvars, typval_T *rettv)
8134{
8135 float_T f = 0.0;
8136
8137 rettv->v_type = VAR_FLOAT;
8138 if (get_float_arg(argvars, &f) == OK)
8139 rettv->vval.v_float = tan(f);
8140 else
8141 rettv->vval.v_float = 0.0;
8142}
8143
8144/*
8145 * "tanh()" function
8146 */
8147 static void
8148f_tanh(typval_T *argvars, typval_T *rettv)
8149{
8150 float_T f = 0.0;
8151
8152 rettv->v_type = VAR_FLOAT;
8153 if (get_float_arg(argvars, &f) == OK)
8154 rettv->vval.v_float = tanh(f);
8155 else
8156 rettv->vval.v_float = 0.0;
8157}
8158#endif
8159
8160/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161 * "tolower(string)" function
8162 */
8163 static void
8164f_tolower(typval_T *argvars, typval_T *rettv)
8165{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008166 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008167 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008168}
8169
8170/*
8171 * "toupper(string)" function
8172 */
8173 static void
8174f_toupper(typval_T *argvars, typval_T *rettv)
8175{
8176 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008177 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008178}
8179
8180/*
8181 * "tr(string, fromstr, tostr)" function
8182 */
8183 static void
8184f_tr(typval_T *argvars, typval_T *rettv)
8185{
8186 char_u *in_str;
8187 char_u *fromstr;
8188 char_u *tostr;
8189 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 int inlen;
8191 int fromlen;
8192 int tolen;
8193 int idx;
8194 char_u *cpstr;
8195 int cplen;
8196 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008197 char_u buf[NUMBUFLEN];
8198 char_u buf2[NUMBUFLEN];
8199 garray_T ga;
8200
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008201 in_str = tv_get_string(&argvars[0]);
8202 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8203 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008204
8205 /* Default return value: empty string. */
8206 rettv->v_type = VAR_STRING;
8207 rettv->vval.v_string = NULL;
8208 if (fromstr == NULL || tostr == NULL)
8209 return; /* type error; errmsg already given */
8210 ga_init2(&ga, (int)sizeof(char), 80);
8211
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008212 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 /* not multi-byte: fromstr and tostr must be the same length */
8214 if (STRLEN(fromstr) != STRLEN(tostr))
8215 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008216error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008217 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008218 ga_clear(&ga);
8219 return;
8220 }
8221
8222 /* fromstr and tostr have to contain the same number of chars */
8223 while (*in_str != NUL)
8224 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225 if (has_mbyte)
8226 {
8227 inlen = (*mb_ptr2len)(in_str);
8228 cpstr = in_str;
8229 cplen = inlen;
8230 idx = 0;
8231 for (p = fromstr; *p != NUL; p += fromlen)
8232 {
8233 fromlen = (*mb_ptr2len)(p);
8234 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8235 {
8236 for (p = tostr; *p != NUL; p += tolen)
8237 {
8238 tolen = (*mb_ptr2len)(p);
8239 if (idx-- == 0)
8240 {
8241 cplen = tolen;
8242 cpstr = p;
8243 break;
8244 }
8245 }
8246 if (*p == NUL) /* tostr is shorter than fromstr */
8247 goto error;
8248 break;
8249 }
8250 ++idx;
8251 }
8252
8253 if (first && cpstr == in_str)
8254 {
8255 /* Check that fromstr and tostr have the same number of
8256 * (multi-byte) characters. Done only once when a character
8257 * of in_str doesn't appear in fromstr. */
8258 first = FALSE;
8259 for (p = tostr; *p != NUL; p += tolen)
8260 {
8261 tolen = (*mb_ptr2len)(p);
8262 --idx;
8263 }
8264 if (idx != 0)
8265 goto error;
8266 }
8267
8268 (void)ga_grow(&ga, cplen);
8269 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8270 ga.ga_len += cplen;
8271
8272 in_str += inlen;
8273 }
8274 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008275 {
8276 /* When not using multi-byte chars we can do it faster. */
8277 p = vim_strchr(fromstr, *in_str);
8278 if (p != NULL)
8279 ga_append(&ga, tostr[p - fromstr]);
8280 else
8281 ga_append(&ga, *in_str);
8282 ++in_str;
8283 }
8284 }
8285
8286 /* add a terminating NUL */
8287 (void)ga_grow(&ga, 1);
8288 ga_append(&ga, NUL);
8289
8290 rettv->vval.v_string = ga.ga_data;
8291}
8292
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008293/*
8294 * "trim({expr})" function
8295 */
8296 static void
8297f_trim(typval_T *argvars, typval_T *rettv)
8298{
8299 char_u buf1[NUMBUFLEN];
8300 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008301 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008302 char_u *mask = NULL;
8303 char_u *tail;
8304 char_u *prev;
8305 char_u *p;
8306 int c1;
8307
8308 rettv->v_type = VAR_STRING;
8309 if (head == NULL)
8310 {
8311 rettv->vval.v_string = NULL;
8312 return;
8313 }
8314
8315 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008316 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008317
8318 while (*head != NUL)
8319 {
8320 c1 = PTR2CHAR(head);
8321 if (mask == NULL)
8322 {
8323 if (c1 > ' ' && c1 != 0xa0)
8324 break;
8325 }
8326 else
8327 {
8328 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8329 if (c1 == PTR2CHAR(p))
8330 break;
8331 if (*p == NUL)
8332 break;
8333 }
8334 MB_PTR_ADV(head);
8335 }
8336
8337 for (tail = head + STRLEN(head); tail > head; tail = prev)
8338 {
8339 prev = tail;
8340 MB_PTR_BACK(head, prev);
8341 c1 = PTR2CHAR(prev);
8342 if (mask == NULL)
8343 {
8344 if (c1 > ' ' && c1 != 0xa0)
8345 break;
8346 }
8347 else
8348 {
8349 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8350 if (c1 == PTR2CHAR(p))
8351 break;
8352 if (*p == NUL)
8353 break;
8354 }
8355 }
8356 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8357}
8358
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008359#ifdef FEAT_FLOAT
8360/*
8361 * "trunc({float})" function
8362 */
8363 static void
8364f_trunc(typval_T *argvars, typval_T *rettv)
8365{
8366 float_T f = 0.0;
8367
8368 rettv->v_type = VAR_FLOAT;
8369 if (get_float_arg(argvars, &f) == OK)
8370 /* trunc() is not in C90, use floor() or ceil() instead. */
8371 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8372 else
8373 rettv->vval.v_float = 0.0;
8374}
8375#endif
8376
8377/*
8378 * "type(expr)" function
8379 */
8380 static void
8381f_type(typval_T *argvars, typval_T *rettv)
8382{
8383 int n = -1;
8384
8385 switch (argvars[0].v_type)
8386 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008387 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8388 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008389 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008390 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8391 case VAR_LIST: n = VAR_TYPE_LIST; break;
8392 case VAR_DICT: n = VAR_TYPE_DICT; break;
8393 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394 case VAR_SPECIAL:
8395 if (argvars[0].vval.v_number == VVAL_FALSE
8396 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008397 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008399 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008400 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008401 case VAR_JOB: n = VAR_TYPE_JOB; break;
8402 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008403 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008405 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008406 n = -1;
8407 break;
8408 }
8409 rettv->vval.v_number = n;
8410}
8411
8412/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008413 * "virtcol(string)" function
8414 */
8415 static void
8416f_virtcol(typval_T *argvars, typval_T *rettv)
8417{
8418 colnr_T vcol = 0;
8419 pos_T *fp;
8420 int fnum = curbuf->b_fnum;
8421
8422 fp = var2fpos(&argvars[0], FALSE, &fnum);
8423 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8424 && fnum == curbuf->b_fnum)
8425 {
8426 getvvcol(curwin, fp, NULL, NULL, &vcol);
8427 ++vcol;
8428 }
8429
8430 rettv->vval.v_number = vcol;
8431}
8432
8433/*
8434 * "visualmode()" function
8435 */
8436 static void
8437f_visualmode(typval_T *argvars, typval_T *rettv)
8438{
8439 char_u str[2];
8440
8441 rettv->v_type = VAR_STRING;
8442 str[0] = curbuf->b_visual_mode_eval;
8443 str[1] = NUL;
8444 rettv->vval.v_string = vim_strsave(str);
8445
8446 /* A non-zero number or non-empty string argument: reset mode. */
8447 if (non_zero_arg(&argvars[0]))
8448 curbuf->b_visual_mode_eval = NUL;
8449}
8450
8451/*
8452 * "wildmenumode()" function
8453 */
8454 static void
8455f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8456{
8457#ifdef FEAT_WILDMENU
8458 if (wild_menu_showing)
8459 rettv->vval.v_number = 1;
8460#endif
8461}
8462
8463/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008464 * "wordcount()" function
8465 */
8466 static void
8467f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8468{
8469 if (rettv_dict_alloc(rettv) == FAIL)
8470 return;
8471 cursor_pos_info(rettv->vval.v_dict);
8472}
8473
8474/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008475 * "xor(expr, expr)" function
8476 */
8477 static void
8478f_xor(typval_T *argvars, typval_T *rettv)
8479{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008480 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8481 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008482}
8483
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008484#endif /* FEAT_EVAL */