blob: dafd3b6af29e96ec29f99fbcee71ef45e35adcb8 [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 Moolenaarf6ed61e2019-09-07 19:05:09 +0200731 {"str2nr", 1, 2, FEARG_1, f_str2nr},
732 {"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 Moolenaare49fbff2019-08-21 22:50:07 +0200853 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200854 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200855 {"winheight", 1, 1, FEARG_1, f_winheight},
856 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200857 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200858 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200859 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200860 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200861 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200862 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200863 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200864 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200865 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200866};
867
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200868/*
869 * Function given to ExpandGeneric() to obtain the list of internal
870 * or user defined function names.
871 */
872 char_u *
873get_function_name(expand_T *xp, int idx)
874{
875 static int intidx = -1;
876 char_u *name;
877
878 if (idx == 0)
879 intidx = -1;
880 if (intidx < 0)
881 {
882 name = get_user_func_name(xp, idx);
883 if (name != NULL)
884 return name;
885 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200886 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200888 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200889 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200890 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200891 STRCAT(IObuff, ")");
892 return IObuff;
893 }
894
895 return NULL;
896}
897
898/*
899 * Function given to ExpandGeneric() to obtain the list of internal or
900 * user defined variable or function names.
901 */
902 char_u *
903get_expr_name(expand_T *xp, int idx)
904{
905 static int intidx = -1;
906 char_u *name;
907
908 if (idx == 0)
909 intidx = -1;
910 if (intidx < 0)
911 {
912 name = get_function_name(xp, idx);
913 if (name != NULL)
914 return name;
915 }
916 return get_user_var_name(xp, ++intidx);
917}
918
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200919/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200920 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200921 * Return index, or -1 if not found
922 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200923 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200924find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925{
926 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200927 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928 int cmp;
929 int x;
930
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200931 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200932
933 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200934 while (first <= last)
935 {
936 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200937 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200938 if (cmp < 0)
939 last = x - 1;
940 else if (cmp > 0)
941 first = x + 1;
942 else
943 return x;
944 }
945 return -1;
946}
947
948 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200949has_internal_func(char_u *name)
950{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200951 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200952}
953
954 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955call_internal_func(
956 char_u *name,
957 int argcount,
958 typval_T *argvars,
959 typval_T *rettv)
960{
961 int i;
962
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200963 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964 if (i < 0)
965 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200966 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200967 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200968 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200969 return ERROR_TOOMANY;
970 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200971 global_functions[i].f_func(argvars, rettv);
972 return ERROR_NONE;
973}
974
975/*
976 * Invoke a method for base->method().
977 */
978 int
979call_internal_method(
980 char_u *name,
981 int argcount,
982 typval_T *argvars,
983 typval_T *rettv,
984 typval_T *basetv)
985{
986 int i;
987 int fi;
988 typval_T argv[MAX_FUNC_ARGS + 1];
989
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200990 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +0200991 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200992 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +0200993 if (global_functions[fi].f_argtype == 0)
994 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200995 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200996 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200997 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200998 return ERROR_TOOMANY;
999
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001000 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001001 {
1002 // base value goes last
1003 for (i = 0; i < argcount; ++i)
1004 argv[i] = argvars[i];
1005 argv[argcount] = *basetv;
1006 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001007 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001008 {
1009 // base value goes second
1010 argv[0] = argvars[0];
1011 argv[1] = *basetv;
1012 for (i = 1; i < argcount; ++i)
1013 argv[i + 1] = argvars[i];
1014 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001015 else if (global_functions[fi].f_argtype == FEARG_3)
1016 {
1017 // base value goes third
1018 argv[0] = argvars[0];
1019 argv[1] = argvars[1];
1020 argv[2] = *basetv;
1021 for (i = 2; i < argcount; ++i)
1022 argv[i + 1] = argvars[i];
1023 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001024 else if (global_functions[fi].f_argtype == FEARG_4)
1025 {
1026 // base value goes fourth
1027 argv[0] = argvars[0];
1028 argv[1] = argvars[1];
1029 argv[2] = argvars[2];
1030 argv[3] = *basetv;
1031 for (i = 3; i < argcount; ++i)
1032 argv[i + 1] = argvars[i];
1033 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001034 else
1035 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001036 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001037 argv[0] = *basetv;
1038 for (i = 0; i < argcount; ++i)
1039 argv[i + 1] = argvars[i];
1040 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001041 argv[argcount + 1].v_type = VAR_UNKNOWN;
1042
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001043 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001044 return ERROR_NONE;
1045}
1046
1047/*
1048 * Return TRUE for a non-zero Number and a non-empty String.
1049 */
1050 static int
1051non_zero_arg(typval_T *argvars)
1052{
1053 return ((argvars[0].v_type == VAR_NUMBER
1054 && argvars[0].vval.v_number != 0)
1055 || (argvars[0].v_type == VAR_SPECIAL
1056 && argvars[0].vval.v_number == VVAL_TRUE)
1057 || (argvars[0].v_type == VAR_STRING
1058 && argvars[0].vval.v_string != NULL
1059 && *argvars[0].vval.v_string != NUL));
1060}
1061
1062/*
1063 * Get the lnum from the first argument.
1064 * Also accepts ".", "$", etc., but that only works for the current buffer.
1065 * Returns -1 on error.
1066 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001067 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001068tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001069{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001070 linenr_T lnum;
1071
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001072 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001073 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001074 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001075 int fnum;
1076 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1077
1078 if (fp != NULL)
1079 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080 }
1081 return lnum;
1082}
1083
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001084/*
1085 * Get the lnum from the first argument.
1086 * Also accepts "$", then "buf" is used.
1087 * Returns 0 on error.
1088 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001089 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001090tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1091{
1092 if (argvars[0].v_type == VAR_STRING
1093 && argvars[0].vval.v_string != NULL
1094 && argvars[0].vval.v_string[0] == '$'
1095 && buf != NULL)
1096 return buf->b_ml.ml_line_count;
1097 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1098}
1099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001100#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001101/*
1102 * Get the float value of "argvars[0]" into "f".
1103 * Returns FAIL when the argument is not a Number or Float.
1104 */
1105 static int
1106get_float_arg(typval_T *argvars, float_T *f)
1107{
1108 if (argvars[0].v_type == VAR_FLOAT)
1109 {
1110 *f = argvars[0].vval.v_float;
1111 return OK;
1112 }
1113 if (argvars[0].v_type == VAR_NUMBER)
1114 {
1115 *f = (float_T)argvars[0].vval.v_number;
1116 return OK;
1117 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001118 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001119 return FAIL;
1120}
1121
1122/*
1123 * "abs(expr)" function
1124 */
1125 static void
1126f_abs(typval_T *argvars, typval_T *rettv)
1127{
1128 if (argvars[0].v_type == VAR_FLOAT)
1129 {
1130 rettv->v_type = VAR_FLOAT;
1131 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1132 }
1133 else
1134 {
1135 varnumber_T n;
1136 int error = FALSE;
1137
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001138 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001139 if (error)
1140 rettv->vval.v_number = -1;
1141 else if (n > 0)
1142 rettv->vval.v_number = n;
1143 else
1144 rettv->vval.v_number = -n;
1145 }
1146}
1147
1148/*
1149 * "acos()" function
1150 */
1151 static void
1152f_acos(typval_T *argvars, typval_T *rettv)
1153{
1154 float_T f = 0.0;
1155
1156 rettv->v_type = VAR_FLOAT;
1157 if (get_float_arg(argvars, &f) == OK)
1158 rettv->vval.v_float = acos(f);
1159 else
1160 rettv->vval.v_float = 0.0;
1161}
1162#endif
1163
1164/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001165 * "and(expr, expr)" function
1166 */
1167 static void
1168f_and(typval_T *argvars, typval_T *rettv)
1169{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001170 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1171 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001172}
1173
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001174#ifdef FEAT_FLOAT
1175/*
1176 * "asin()" function
1177 */
1178 static void
1179f_asin(typval_T *argvars, typval_T *rettv)
1180{
1181 float_T f = 0.0;
1182
1183 rettv->v_type = VAR_FLOAT;
1184 if (get_float_arg(argvars, &f) == OK)
1185 rettv->vval.v_float = asin(f);
1186 else
1187 rettv->vval.v_float = 0.0;
1188}
1189
1190/*
1191 * "atan()" function
1192 */
1193 static void
1194f_atan(typval_T *argvars, typval_T *rettv)
1195{
1196 float_T f = 0.0;
1197
1198 rettv->v_type = VAR_FLOAT;
1199 if (get_float_arg(argvars, &f) == OK)
1200 rettv->vval.v_float = atan(f);
1201 else
1202 rettv->vval.v_float = 0.0;
1203}
1204
1205/*
1206 * "atan2()" function
1207 */
1208 static void
1209f_atan2(typval_T *argvars, typval_T *rettv)
1210{
1211 float_T fx = 0.0, fy = 0.0;
1212
1213 rettv->v_type = VAR_FLOAT;
1214 if (get_float_arg(argvars, &fx) == OK
1215 && get_float_arg(&argvars[1], &fy) == OK)
1216 rettv->vval.v_float = atan2(fx, fy);
1217 else
1218 rettv->vval.v_float = 0.0;
1219}
1220#endif
1221
1222/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001223 * "balloon_show()" function
1224 */
1225#ifdef FEAT_BEVAL
1226 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001227f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1228{
1229 rettv->v_type = VAR_STRING;
1230 if (balloonEval != NULL)
1231 {
1232 if (balloonEval->msg == NULL)
1233 rettv->vval.v_string = NULL;
1234 else
1235 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1236 }
1237}
1238
1239 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001240f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1241{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001242 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001243 {
1244 if (argvars[0].v_type == VAR_LIST
1245# ifdef FEAT_GUI
1246 && !gui.in_use
1247# endif
1248 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001249 {
1250 list_T *l = argvars[0].vval.v_list;
1251
1252 // empty list removes the balloon
1253 post_balloon(balloonEval, NULL,
1254 l == NULL || l->lv_len == 0 ? NULL : l);
1255 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001256 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001257 {
1258 char_u *mesg = tv_get_string_chk(&argvars[0]);
1259
1260 if (mesg != NULL)
1261 // empty string removes the balloon
1262 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1263 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001264 }
1265}
1266
Bram Moolenaar669a8282017-11-19 20:13:05 +01001267# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001268 static void
1269f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1270{
1271 if (rettv_list_alloc(rettv) == OK)
1272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001273 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001274
1275 if (msg != NULL)
1276 {
1277 pumitem_T *array;
1278 int size = split_message(msg, &array);
1279 int i;
1280
1281 /* Skip the first and last item, they are always empty. */
1282 for (i = 1; i < size - 1; ++i)
1283 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001284 while (size > 0)
1285 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001286 vim_free(array);
1287 }
1288 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001289}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001290# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001291#endif
1292
1293/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001294 * Get buffer by number or pattern.
1295 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001296 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001297tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001298{
1299 char_u *name = tv->vval.v_string;
1300 buf_T *buf;
1301
1302 if (tv->v_type == VAR_NUMBER)
1303 return buflist_findnr((int)tv->vval.v_number);
1304 if (tv->v_type != VAR_STRING)
1305 return NULL;
1306 if (name == NULL || *name == NUL)
1307 return curbuf;
1308 if (name[0] == '$' && name[1] == NUL)
1309 return lastbuf;
1310
1311 buf = buflist_find_by_name(name, curtab_only);
1312
1313 /* If not found, try expanding the name, like done for bufexists(). */
1314 if (buf == NULL)
1315 buf = find_buffer(tv);
1316
1317 return buf;
1318}
1319
1320/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001321 * Get the buffer from "arg" and give an error and return NULL if it is not
1322 * valid.
1323 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001324 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001325get_buf_arg(typval_T *arg)
1326{
1327 buf_T *buf;
1328
1329 ++emsg_off;
1330 buf = tv_get_buf(arg, FALSE);
1331 --emsg_off;
1332 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001333 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001334 return buf;
1335}
1336
1337/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001338 * "byte2line(byte)" function
1339 */
1340 static void
1341f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1342{
1343#ifndef FEAT_BYTEOFF
1344 rettv->vval.v_number = -1;
1345#else
1346 long boff = 0;
1347
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001348 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001349 if (boff < 0)
1350 rettv->vval.v_number = -1;
1351 else
1352 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1353 (linenr_T)0, &boff);
1354#endif
1355}
1356
1357 static void
1358byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1359{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 char_u *str;
1362 varnumber_T idx;
1363
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001364 str = tv_get_string_chk(&argvars[0]);
1365 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001366 rettv->vval.v_number = -1;
1367 if (str == NULL || idx < 0)
1368 return;
1369
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001370 t = str;
1371 for ( ; idx > 0; idx--)
1372 {
1373 if (*t == NUL) /* EOL reached */
1374 return;
1375 if (enc_utf8 && comp)
1376 t += utf_ptr2len(t);
1377 else
1378 t += (*mb_ptr2len)(t);
1379 }
1380 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001381}
1382
1383/*
1384 * "byteidx()" function
1385 */
1386 static void
1387f_byteidx(typval_T *argvars, typval_T *rettv)
1388{
1389 byteidx(argvars, rettv, FALSE);
1390}
1391
1392/*
1393 * "byteidxcomp()" function
1394 */
1395 static void
1396f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1397{
1398 byteidx(argvars, rettv, TRUE);
1399}
1400
1401/*
1402 * "call(func, arglist [, dict])" function
1403 */
1404 static void
1405f_call(typval_T *argvars, typval_T *rettv)
1406{
1407 char_u *func;
1408 partial_T *partial = NULL;
1409 dict_T *selfdict = NULL;
1410
1411 if (argvars[1].v_type != VAR_LIST)
1412 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001413 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001414 return;
1415 }
1416 if (argvars[1].vval.v_list == NULL)
1417 return;
1418
1419 if (argvars[0].v_type == VAR_FUNC)
1420 func = argvars[0].vval.v_string;
1421 else if (argvars[0].v_type == VAR_PARTIAL)
1422 {
1423 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001424 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001425 }
1426 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001427 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001428 if (*func == NUL)
1429 return; /* type error or empty name */
1430
1431 if (argvars[2].v_type != VAR_UNKNOWN)
1432 {
1433 if (argvars[2].v_type != VAR_DICT)
1434 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001435 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001436 return;
1437 }
1438 selfdict = argvars[2].vval.v_dict;
1439 }
1440
1441 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1442}
1443
1444#ifdef FEAT_FLOAT
1445/*
1446 * "ceil({float})" function
1447 */
1448 static void
1449f_ceil(typval_T *argvars, typval_T *rettv)
1450{
1451 float_T f = 0.0;
1452
1453 rettv->v_type = VAR_FLOAT;
1454 if (get_float_arg(argvars, &f) == OK)
1455 rettv->vval.v_float = ceil(f);
1456 else
1457 rettv->vval.v_float = 0.0;
1458}
1459#endif
1460
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001461/*
1462 * "changenr()" function
1463 */
1464 static void
1465f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1466{
1467 rettv->vval.v_number = curbuf->b_u_seq_cur;
1468}
1469
1470/*
1471 * "char2nr(string)" function
1472 */
1473 static void
1474f_char2nr(typval_T *argvars, typval_T *rettv)
1475{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001476 if (has_mbyte)
1477 {
1478 int utf8 = 0;
1479
1480 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001481 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001482
1483 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001484 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001485 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001486 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001487 }
1488 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001489 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001490}
1491
1492/*
1493 * "cindent(lnum)" function
1494 */
1495 static void
1496f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1497{
1498#ifdef FEAT_CINDENT
1499 pos_T pos;
1500 linenr_T lnum;
1501
1502 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001503 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001504 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1505 {
1506 curwin->w_cursor.lnum = lnum;
1507 rettv->vval.v_number = get_c_indent();
1508 curwin->w_cursor = pos;
1509 }
1510 else
1511#endif
1512 rettv->vval.v_number = -1;
1513}
1514
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001515 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001516get_optional_window(typval_T *argvars, int idx)
1517{
1518 win_T *win = curwin;
1519
1520 if (argvars[idx].v_type != VAR_UNKNOWN)
1521 {
1522 win = find_win_by_nr_or_id(&argvars[idx]);
1523 if (win == NULL)
1524 {
1525 emsg(_(e_invalwindow));
1526 return NULL;
1527 }
1528 }
1529 return win;
1530}
1531
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001532/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533 * "col(string)" function
1534 */
1535 static void
1536f_col(typval_T *argvars, typval_T *rettv)
1537{
1538 colnr_T col = 0;
1539 pos_T *fp;
1540 int fnum = curbuf->b_fnum;
1541
1542 fp = var2fpos(&argvars[0], FALSE, &fnum);
1543 if (fp != NULL && fnum == curbuf->b_fnum)
1544 {
1545 if (fp->col == MAXCOL)
1546 {
1547 /* '> can be MAXCOL, get the length of the line then */
1548 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1549 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1550 else
1551 col = MAXCOL;
1552 }
1553 else
1554 {
1555 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 /* col(".") when the cursor is on the NUL at the end of the line
1557 * because of "coladd" can be seen as an extra column. */
1558 if (virtual_active() && fp == &curwin->w_cursor)
1559 {
1560 char_u *p = ml_get_cursor();
1561
1562 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1563 curwin->w_virtcol - curwin->w_cursor.coladd))
1564 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001565 int l;
1566
1567 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1568 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001569 }
1570 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001571 }
1572 }
1573 rettv->vval.v_number = col;
1574}
1575
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576/*
1577 * "confirm(message, buttons[, default [, type]])" function
1578 */
1579 static void
1580f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1581{
1582#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1583 char_u *message;
1584 char_u *buttons = NULL;
1585 char_u buf[NUMBUFLEN];
1586 char_u buf2[NUMBUFLEN];
1587 int def = 1;
1588 int type = VIM_GENERIC;
1589 char_u *typestr;
1590 int error = FALSE;
1591
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001592 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001593 if (message == NULL)
1594 error = TRUE;
1595 if (argvars[1].v_type != VAR_UNKNOWN)
1596 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001597 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598 if (buttons == NULL)
1599 error = TRUE;
1600 if (argvars[2].v_type != VAR_UNKNOWN)
1601 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001602 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603 if (argvars[3].v_type != VAR_UNKNOWN)
1604 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001605 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001606 if (typestr == NULL)
1607 error = TRUE;
1608 else
1609 {
1610 switch (TOUPPER_ASC(*typestr))
1611 {
1612 case 'E': type = VIM_ERROR; break;
1613 case 'Q': type = VIM_QUESTION; break;
1614 case 'I': type = VIM_INFO; break;
1615 case 'W': type = VIM_WARNING; break;
1616 case 'G': type = VIM_GENERIC; break;
1617 }
1618 }
1619 }
1620 }
1621 }
1622
1623 if (buttons == NULL || *buttons == NUL)
1624 buttons = (char_u *)_("&Ok");
1625
1626 if (!error)
1627 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1628 def, NULL, FALSE);
1629#endif
1630}
1631
1632/*
1633 * "copy()" function
1634 */
1635 static void
1636f_copy(typval_T *argvars, typval_T *rettv)
1637{
1638 item_copy(&argvars[0], rettv, FALSE, 0);
1639}
1640
1641#ifdef FEAT_FLOAT
1642/*
1643 * "cos()" function
1644 */
1645 static void
1646f_cos(typval_T *argvars, typval_T *rettv)
1647{
1648 float_T f = 0.0;
1649
1650 rettv->v_type = VAR_FLOAT;
1651 if (get_float_arg(argvars, &f) == OK)
1652 rettv->vval.v_float = cos(f);
1653 else
1654 rettv->vval.v_float = 0.0;
1655}
1656
1657/*
1658 * "cosh()" function
1659 */
1660 static void
1661f_cosh(typval_T *argvars, typval_T *rettv)
1662{
1663 float_T f = 0.0;
1664
1665 rettv->v_type = VAR_FLOAT;
1666 if (get_float_arg(argvars, &f) == OK)
1667 rettv->vval.v_float = cosh(f);
1668 else
1669 rettv->vval.v_float = 0.0;
1670}
1671#endif
1672
1673/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001674 * "cursor(lnum, col)" function, or
1675 * "cursor(list)"
1676 *
1677 * Moves the cursor to the specified line and column.
1678 * Returns 0 when the position could be set, -1 otherwise.
1679 */
1680 static void
1681f_cursor(typval_T *argvars, typval_T *rettv)
1682{
1683 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001684 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 int set_curswant = TRUE;
1686
1687 rettv->vval.v_number = -1;
1688 if (argvars[1].v_type == VAR_UNKNOWN)
1689 {
1690 pos_T pos;
1691 colnr_T curswant = -1;
1692
1693 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1694 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001695 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001696 return;
1697 }
1698 line = pos.lnum;
1699 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001700 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001701 if (curswant >= 0)
1702 {
1703 curwin->w_curswant = curswant - 1;
1704 set_curswant = FALSE;
1705 }
1706 }
1707 else
1708 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001709 line = tv_get_lnum(argvars);
1710 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001711 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001712 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001713 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001714 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001715 return; /* type error; errmsg already given */
1716 if (line > 0)
1717 curwin->w_cursor.lnum = line;
1718 if (col > 0)
1719 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001721
1722 /* Make sure the cursor is in a valid position. */
1723 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001724 /* Correct cursor for multi-byte character. */
1725 if (has_mbyte)
1726 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727
1728 curwin->w_set_curswant = set_curswant;
1729 rettv->vval.v_number = 0;
1730}
1731
Bram Moolenaar4f974752019-02-17 17:44:42 +01001732#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001733/*
1734 * "debugbreak()" function
1735 */
1736 static void
1737f_debugbreak(typval_T *argvars, typval_T *rettv)
1738{
1739 int pid;
1740
1741 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001742 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001743 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001744 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001745 else
1746 {
1747 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1748
1749 if (hProcess != NULL)
1750 {
1751 DebugBreakProcess(hProcess);
1752 CloseHandle(hProcess);
1753 rettv->vval.v_number = OK;
1754 }
1755 }
1756}
1757#endif
1758
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001759/*
1760 * "deepcopy()" function
1761 */
1762 static void
1763f_deepcopy(typval_T *argvars, typval_T *rettv)
1764{
1765 int noref = 0;
1766 int copyID;
1767
1768 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001769 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001770 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001771 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001772 else
1773 {
1774 copyID = get_copyID();
1775 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1776 }
1777}
1778
1779/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001780 * "did_filetype()" function
1781 */
1782 static void
1783f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1784{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001785 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001786}
1787
1788/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001789 * "empty({expr})" function
1790 */
1791 static void
1792f_empty(typval_T *argvars, typval_T *rettv)
1793{
1794 int n = FALSE;
1795
1796 switch (argvars[0].v_type)
1797 {
1798 case VAR_STRING:
1799 case VAR_FUNC:
1800 n = argvars[0].vval.v_string == NULL
1801 || *argvars[0].vval.v_string == NUL;
1802 break;
1803 case VAR_PARTIAL:
1804 n = FALSE;
1805 break;
1806 case VAR_NUMBER:
1807 n = argvars[0].vval.v_number == 0;
1808 break;
1809 case VAR_FLOAT:
1810#ifdef FEAT_FLOAT
1811 n = argvars[0].vval.v_float == 0.0;
1812 break;
1813#endif
1814 case VAR_LIST:
1815 n = argvars[0].vval.v_list == NULL
1816 || argvars[0].vval.v_list->lv_first == NULL;
1817 break;
1818 case VAR_DICT:
1819 n = argvars[0].vval.v_dict == NULL
1820 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1821 break;
1822 case VAR_SPECIAL:
1823 n = argvars[0].vval.v_number != VVAL_TRUE;
1824 break;
1825
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001826 case VAR_BLOB:
1827 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001828 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1829 break;
1830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001831 case VAR_JOB:
1832#ifdef FEAT_JOB_CHANNEL
1833 n = argvars[0].vval.v_job == NULL
1834 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1835 break;
1836#endif
1837 case VAR_CHANNEL:
1838#ifdef FEAT_JOB_CHANNEL
1839 n = argvars[0].vval.v_channel == NULL
1840 || !channel_is_open(argvars[0].vval.v_channel);
1841 break;
1842#endif
1843 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001844 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001845 n = TRUE;
1846 break;
1847 }
1848
1849 rettv->vval.v_number = n;
1850}
1851
1852/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001853 * "environ()" function
1854 */
1855 static void
1856f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1857{
1858#if !defined(AMIGA)
1859 int i = 0;
1860 char_u *entry, *value;
1861# ifdef MSWIN
1862 extern wchar_t **_wenviron;
1863# else
1864 extern char **environ;
1865# endif
1866
1867 if (rettv_dict_alloc(rettv) != OK)
1868 return;
1869
1870# ifdef MSWIN
1871 if (*_wenviron == NULL)
1872 return;
1873# else
1874 if (*environ == NULL)
1875 return;
1876# endif
1877
1878 for (i = 0; ; ++i)
1879 {
1880# ifdef MSWIN
1881 short_u *p;
1882
1883 if ((p = (short_u *)_wenviron[i]) == NULL)
1884 return;
1885 entry = utf16_to_enc(p, NULL);
1886# else
1887 if ((entry = (char_u *)environ[i]) == NULL)
1888 return;
1889 entry = vim_strsave(entry);
1890# endif
1891 if (entry == NULL) // out of memory
1892 return;
1893 if ((value = vim_strchr(entry, '=')) == NULL)
1894 {
1895 vim_free(entry);
1896 continue;
1897 }
1898 *value++ = NUL;
1899 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1900 vim_free(entry);
1901 }
1902#endif
1903}
1904
1905/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001906 * "escape({string}, {chars})" function
1907 */
1908 static void
1909f_escape(typval_T *argvars, typval_T *rettv)
1910{
1911 char_u buf[NUMBUFLEN];
1912
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001913 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1914 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001915 rettv->v_type = VAR_STRING;
1916}
1917
1918/*
1919 * "eval()" function
1920 */
1921 static void
1922f_eval(typval_T *argvars, typval_T *rettv)
1923{
1924 char_u *s, *p;
1925
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001926 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927 if (s != NULL)
1928 s = skipwhite(s);
1929
1930 p = s;
1931 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1932 {
1933 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001934 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935 need_clr_eos = FALSE;
1936 rettv->v_type = VAR_NUMBER;
1937 rettv->vval.v_number = 0;
1938 }
1939 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001940 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001941}
1942
1943/*
1944 * "eventhandler()" function
1945 */
1946 static void
1947f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1948{
1949 rettv->vval.v_number = vgetc_busy;
1950}
1951
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001952static garray_T redir_execute_ga;
1953
1954/*
1955 * Append "value[value_len]" to the execute() output.
1956 */
1957 void
1958execute_redir_str(char_u *value, int value_len)
1959{
1960 int len;
1961
1962 if (value_len == -1)
1963 len = (int)STRLEN(value); /* Append the entire string */
1964 else
1965 len = value_len; /* Append only "value_len" characters */
1966 if (ga_grow(&redir_execute_ga, len) == OK)
1967 {
1968 mch_memmove((char *)redir_execute_ga.ga_data
1969 + redir_execute_ga.ga_len, value, len);
1970 redir_execute_ga.ga_len += len;
1971 }
1972}
1973
1974/*
1975 * Get next line from a list.
1976 * Called by do_cmdline() to get the next line.
1977 * Returns allocated string, or NULL for end of function.
1978 */
1979
1980 static char_u *
1981get_list_line(
1982 int c UNUSED,
1983 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001984 int indent UNUSED,
1985 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986{
1987 listitem_T **p = (listitem_T **)cookie;
1988 listitem_T *item = *p;
1989 char_u buf[NUMBUFLEN];
1990 char_u *s;
1991
1992 if (item == NULL)
1993 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001994 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 *p = item->li_next;
1996 return s == NULL ? NULL : vim_strsave(s);
1997}
1998
1999/*
2000 * "execute()" function
2001 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002002 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002003execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004{
2005 char_u *cmd = NULL;
2006 list_T *list = NULL;
2007 int save_msg_silent = msg_silent;
2008 int save_emsg_silent = emsg_silent;
2009 int save_emsg_noredir = emsg_noredir;
2010 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002011 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002013 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002014 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002015
2016 rettv->vval.v_string = NULL;
2017 rettv->v_type = VAR_STRING;
2018
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002019 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002020 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002021 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002022 if (list == NULL || list->lv_first == NULL)
2023 /* empty list, no commands, empty output */
2024 return;
2025 ++list->lv_refcount;
2026 }
2027 else
2028 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002029 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002030 if (cmd == NULL)
2031 return;
2032 }
2033
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002034 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035 {
2036 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002037 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002038
2039 if (s == NULL)
2040 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002041 if (*s == NUL)
2042 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002043 if (STRNCMP(s, "silent", 6) == 0)
2044 ++msg_silent;
2045 if (STRCMP(s, "silent!") == 0)
2046 {
2047 emsg_silent = TRUE;
2048 emsg_noredir = TRUE;
2049 }
2050 }
2051 else
2052 ++msg_silent;
2053
2054 if (redir_execute)
2055 save_ga = redir_execute_ga;
2056 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2057 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002058 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002059 if (!echo_output)
2060 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061
2062 if (cmd != NULL)
2063 do_cmdline_cmd(cmd);
2064 else
2065 {
2066 listitem_T *item = list->lv_first;
2067
2068 do_cmdline(NULL, get_list_line, (void *)&item,
2069 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2070 --list->lv_refcount;
2071 }
2072
Bram Moolenaard297f352017-01-29 20:31:21 +01002073 /* Need to append a NUL to the result. */
2074 if (ga_grow(&redir_execute_ga, 1) == OK)
2075 {
2076 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2077 rettv->vval.v_string = redir_execute_ga.ga_data;
2078 }
2079 else
2080 {
2081 ga_clear(&redir_execute_ga);
2082 rettv->vval.v_string = NULL;
2083 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002084 msg_silent = save_msg_silent;
2085 emsg_silent = save_emsg_silent;
2086 emsg_noredir = save_emsg_noredir;
2087
2088 redir_execute = save_redir_execute;
2089 if (redir_execute)
2090 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002091 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002092
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002093 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002094 if (echo_output)
2095 // When not working silently: put it in column zero. A following
2096 // "echon" will overwrite the message, unavoidably.
2097 msg_col = 0;
2098 else
2099 // When working silently: Put it back where it was, since nothing
2100 // should have been written.
2101 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002102}
2103
2104/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002105 * "execute()" function
2106 */
2107 static void
2108f_execute(typval_T *argvars, typval_T *rettv)
2109{
2110 execute_common(argvars, rettv, 0);
2111}
2112
2113/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002114 * "exists()" function
2115 */
2116 static void
2117f_exists(typval_T *argvars, typval_T *rettv)
2118{
2119 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002121
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002122 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002123 if (*p == '$') /* environment variable */
2124 {
2125 /* first try "normal" environment variables (fast) */
2126 if (mch_getenv(p + 1) != NULL)
2127 n = TRUE;
2128 else
2129 {
2130 /* try expanding things like $VIM and ${HOME} */
2131 p = expand_env_save(p);
2132 if (p != NULL && *p != '$')
2133 n = TRUE;
2134 vim_free(p);
2135 }
2136 }
2137 else if (*p == '&' || *p == '+') /* option */
2138 {
2139 n = (get_option_tv(&p, NULL, TRUE) == OK);
2140 if (*skipwhite(p) != NUL)
2141 n = FALSE; /* trailing garbage */
2142 }
2143 else if (*p == '*') /* internal or user defined function */
2144 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002145 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002146 }
2147 else if (*p == ':')
2148 {
2149 n = cmd_exists(p + 1);
2150 }
2151 else if (*p == '#')
2152 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 if (p[1] == '#')
2154 n = autocmd_supported(p + 2);
2155 else
2156 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002157 }
2158 else /* internal variable */
2159 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002160 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161 }
2162
2163 rettv->vval.v_number = n;
2164}
2165
2166#ifdef FEAT_FLOAT
2167/*
2168 * "exp()" function
2169 */
2170 static void
2171f_exp(typval_T *argvars, typval_T *rettv)
2172{
2173 float_T f = 0.0;
2174
2175 rettv->v_type = VAR_FLOAT;
2176 if (get_float_arg(argvars, &f) == OK)
2177 rettv->vval.v_float = exp(f);
2178 else
2179 rettv->vval.v_float = 0.0;
2180}
2181#endif
2182
2183/*
2184 * "expand()" function
2185 */
2186 static void
2187f_expand(typval_T *argvars, typval_T *rettv)
2188{
2189 char_u *s;
2190 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002191 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2193 expand_T xpc;
2194 int error = FALSE;
2195 char_u *result;
2196
2197 rettv->v_type = VAR_STRING;
2198 if (argvars[1].v_type != VAR_UNKNOWN
2199 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002200 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002201 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002202 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002203
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002204 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002205 if (*s == '%' || *s == '#' || *s == '<')
2206 {
2207 ++emsg_off;
2208 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2209 --emsg_off;
2210 if (rettv->v_type == VAR_LIST)
2211 {
2212 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2213 list_append_string(rettv->vval.v_list, result, -1);
2214 else
2215 vim_free(result);
2216 }
2217 else
2218 rettv->vval.v_string = result;
2219 }
2220 else
2221 {
2222 /* When the optional second argument is non-zero, don't remove matches
2223 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2224 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002225 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002226 options |= WILD_KEEP_ALL;
2227 if (!error)
2228 {
2229 ExpandInit(&xpc);
2230 xpc.xp_context = EXPAND_FILES;
2231 if (p_wic)
2232 options += WILD_ICASE;
2233 if (rettv->v_type == VAR_STRING)
2234 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2235 options, WILD_ALL);
2236 else if (rettv_list_alloc(rettv) != FAIL)
2237 {
2238 int i;
2239
2240 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2241 for (i = 0; i < xpc.xp_numfiles; i++)
2242 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2243 ExpandCleanup(&xpc);
2244 }
2245 }
2246 else
2247 rettv->vval.v_string = NULL;
2248 }
2249}
2250
2251/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002252 * "expandcmd()" function
2253 * Expand all the special characters in a command string.
2254 */
2255 static void
2256f_expandcmd(typval_T *argvars, typval_T *rettv)
2257{
2258 exarg_T eap;
2259 char_u *cmdstr;
2260 char *errormsg = NULL;
2261
2262 rettv->v_type = VAR_STRING;
2263 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2264
2265 memset(&eap, 0, sizeof(eap));
2266 eap.cmd = cmdstr;
2267 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002268 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002269 eap.usefilter = FALSE;
2270 eap.nextcmd = NULL;
2271 eap.cmdidx = CMD_USER;
2272
2273 expand_filename(&eap, &cmdstr, &errormsg);
2274 if (errormsg != NULL && *errormsg != NUL)
2275 emsg(errormsg);
2276
2277 rettv->vval.v_string = cmdstr;
2278}
2279
2280/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002281 * "feedkeys()" function
2282 */
2283 static void
2284f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2285{
2286 int remap = TRUE;
2287 int insert = FALSE;
2288 char_u *keys, *flags;
2289 char_u nbuf[NUMBUFLEN];
2290 int typed = FALSE;
2291 int execute = FALSE;
2292 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002293 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002294 char_u *keys_esc;
2295
2296 /* This is not allowed in the sandbox. If the commands would still be
2297 * executed in the sandbox it would be OK, but it probably happens later,
2298 * when "sandbox" is no longer set. */
2299 if (check_secure())
2300 return;
2301
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002302 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303
2304 if (argvars[1].v_type != VAR_UNKNOWN)
2305 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002306 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002307 for ( ; *flags != NUL; ++flags)
2308 {
2309 switch (*flags)
2310 {
2311 case 'n': remap = FALSE; break;
2312 case 'm': remap = TRUE; break;
2313 case 't': typed = TRUE; break;
2314 case 'i': insert = TRUE; break;
2315 case 'x': execute = TRUE; break;
2316 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002317 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002318 }
2319 }
2320 }
2321
2322 if (*keys != NUL || execute)
2323 {
2324 /* Need to escape K_SPECIAL and CSI before putting the string in the
2325 * typeahead buffer. */
2326 keys_esc = vim_strsave_escape_csi(keys);
2327 if (keys_esc != NULL)
2328 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002329 if (lowlevel)
2330 {
2331#ifdef USE_INPUT_BUF
2332 add_to_input_buf(keys, (int)STRLEN(keys));
2333#else
2334 emsg(_("E980: lowlevel input not supported"));
2335#endif
2336 }
2337 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002338 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002339 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002340 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002341 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002342#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002343 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002344#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002345 )
2346 typebuf_was_filled = TRUE;
2347 }
2348 vim_free(keys_esc);
2349
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002350 if (execute)
2351 {
2352 int save_msg_scroll = msg_scroll;
2353
2354 /* Avoid a 1 second delay when the keys start Insert mode. */
2355 msg_scroll = FALSE;
2356
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002357 if (!dangerous)
2358 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002359 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002360 if (!dangerous)
2361 --ex_normal_busy;
2362
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002363 msg_scroll |= save_msg_scroll;
2364 }
2365 }
2366 }
2367}
2368
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002369#ifdef FEAT_FLOAT
2370/*
2371 * "float2nr({float})" function
2372 */
2373 static void
2374f_float2nr(typval_T *argvars, typval_T *rettv)
2375{
2376 float_T f = 0.0;
2377
2378 if (get_float_arg(argvars, &f) == OK)
2379 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002380 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002381 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002382 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002383 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002384 else
2385 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002386 }
2387}
2388
2389/*
2390 * "floor({float})" function
2391 */
2392 static void
2393f_floor(typval_T *argvars, typval_T *rettv)
2394{
2395 float_T f = 0.0;
2396
2397 rettv->v_type = VAR_FLOAT;
2398 if (get_float_arg(argvars, &f) == OK)
2399 rettv->vval.v_float = floor(f);
2400 else
2401 rettv->vval.v_float = 0.0;
2402}
2403
2404/*
2405 * "fmod()" function
2406 */
2407 static void
2408f_fmod(typval_T *argvars, typval_T *rettv)
2409{
2410 float_T fx = 0.0, fy = 0.0;
2411
2412 rettv->v_type = VAR_FLOAT;
2413 if (get_float_arg(argvars, &fx) == OK
2414 && get_float_arg(&argvars[1], &fy) == OK)
2415 rettv->vval.v_float = fmod(fx, fy);
2416 else
2417 rettv->vval.v_float = 0.0;
2418}
2419#endif
2420
2421/*
2422 * "fnameescape({string})" function
2423 */
2424 static void
2425f_fnameescape(typval_T *argvars, typval_T *rettv)
2426{
2427 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002428 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002429 rettv->v_type = VAR_STRING;
2430}
2431
2432/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002433 * "foreground()" function
2434 */
2435 static void
2436f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2437{
2438#ifdef FEAT_GUI
2439 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002440 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002441 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002442 return;
2443 }
2444#endif
2445#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447#endif
2448}
2449
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002451common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452{
2453 char_u *s;
2454 char_u *name;
2455 int use_string = FALSE;
2456 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002457 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458
2459 if (argvars[0].v_type == VAR_FUNC)
2460 {
2461 /* function(MyFunc, [arg], dict) */
2462 s = argvars[0].vval.v_string;
2463 }
2464 else if (argvars[0].v_type == VAR_PARTIAL
2465 && argvars[0].vval.v_partial != NULL)
2466 {
2467 /* function(dict.MyFunc, [arg]) */
2468 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002469 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470 }
2471 else
2472 {
2473 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002474 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002475 use_string = TRUE;
2476 }
2477
Bram Moolenaar843b8842016-08-21 14:36:15 +02002478 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002479 {
2480 name = s;
2481 trans_name = trans_function_name(&name, FALSE,
2482 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2483 if (*name != NUL)
2484 s = NULL;
2485 }
2486
Bram Moolenaar843b8842016-08-21 14:36:15 +02002487 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2488 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002489 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002490 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002491 else if (trans_name != NULL && (is_funcref
2492 ? find_func(trans_name) == NULL
2493 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002494 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002495 else
2496 {
2497 int dict_idx = 0;
2498 int arg_idx = 0;
2499 list_T *list = NULL;
2500
2501 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2502 {
2503 char sid_buf[25];
2504 int off = *s == 's' ? 2 : 5;
2505
2506 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2507 * also be called from another script. Using trans_function_name()
2508 * would also work, but some plugins depend on the name being
2509 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002510 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002511 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512 if (name != NULL)
2513 {
2514 STRCPY(name, sid_buf);
2515 STRCAT(name, s + off);
2516 }
2517 }
2518 else
2519 name = vim_strsave(s);
2520
2521 if (argvars[1].v_type != VAR_UNKNOWN)
2522 {
2523 if (argvars[2].v_type != VAR_UNKNOWN)
2524 {
2525 /* function(name, [args], dict) */
2526 arg_idx = 1;
2527 dict_idx = 2;
2528 }
2529 else if (argvars[1].v_type == VAR_DICT)
2530 /* function(name, dict) */
2531 dict_idx = 1;
2532 else
2533 /* function(name, [args]) */
2534 arg_idx = 1;
2535 if (dict_idx > 0)
2536 {
2537 if (argvars[dict_idx].v_type != VAR_DICT)
2538 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002539 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002540 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002541 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002542 }
2543 if (argvars[dict_idx].vval.v_dict == NULL)
2544 dict_idx = 0;
2545 }
2546 if (arg_idx > 0)
2547 {
2548 if (argvars[arg_idx].v_type != VAR_LIST)
2549 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002550 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002551 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002552 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002553 }
2554 list = argvars[arg_idx].vval.v_list;
2555 if (list == NULL || list->lv_len == 0)
2556 arg_idx = 0;
2557 }
2558 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002559 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002560 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002561 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002562
2563 /* result is a VAR_PARTIAL */
2564 if (pt == NULL)
2565 vim_free(name);
2566 else
2567 {
2568 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2569 {
2570 listitem_T *li;
2571 int i = 0;
2572 int arg_len = 0;
2573 int lv_len = 0;
2574
2575 if (arg_pt != NULL)
2576 arg_len = arg_pt->pt_argc;
2577 if (list != NULL)
2578 lv_len = list->lv_len;
2579 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002580 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002581 if (pt->pt_argv == NULL)
2582 {
2583 vim_free(pt);
2584 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002585 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002586 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002587 for (i = 0; i < arg_len; i++)
2588 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2589 if (lv_len > 0)
2590 for (li = list->lv_first; li != NULL;
2591 li = li->li_next)
2592 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 }
2594
2595 /* For "function(dict.func, [], dict)" and "func" is a partial
2596 * use "dict". That is backwards compatible. */
2597 if (dict_idx > 0)
2598 {
2599 /* The dict is bound explicitly, pt_auto is FALSE. */
2600 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2601 ++pt->pt_dict->dv_refcount;
2602 }
2603 else if (arg_pt != NULL)
2604 {
2605 /* If the dict was bound automatically the result is also
2606 * bound automatically. */
2607 pt->pt_dict = arg_pt->pt_dict;
2608 pt->pt_auto = arg_pt->pt_auto;
2609 if (pt->pt_dict != NULL)
2610 ++pt->pt_dict->dv_refcount;
2611 }
2612
2613 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002614 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2615 {
2616 pt->pt_func = arg_pt->pt_func;
2617 func_ptr_ref(pt->pt_func);
2618 vim_free(name);
2619 }
2620 else if (is_funcref)
2621 {
2622 pt->pt_func = find_func(trans_name);
2623 func_ptr_ref(pt->pt_func);
2624 vim_free(name);
2625 }
2626 else
2627 {
2628 pt->pt_name = name;
2629 func_ref(name);
2630 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002631 }
2632 rettv->v_type = VAR_PARTIAL;
2633 rettv->vval.v_partial = pt;
2634 }
2635 else
2636 {
2637 /* result is a VAR_FUNC */
2638 rettv->v_type = VAR_FUNC;
2639 rettv->vval.v_string = name;
2640 func_ref(name);
2641 }
2642 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002643theend:
2644 vim_free(trans_name);
2645}
2646
2647/*
2648 * "funcref()" function
2649 */
2650 static void
2651f_funcref(typval_T *argvars, typval_T *rettv)
2652{
2653 common_function(argvars, rettv, TRUE);
2654}
2655
2656/*
2657 * "function()" function
2658 */
2659 static void
2660f_function(typval_T *argvars, typval_T *rettv)
2661{
2662 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663}
2664
2665/*
2666 * "garbagecollect()" function
2667 */
2668 static void
2669f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2670{
2671 /* This is postponed until we are back at the toplevel, because we may be
2672 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2673 want_garbage_collect = TRUE;
2674
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002675 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002676 garbage_collect_at_exit = TRUE;
2677}
2678
2679/*
2680 * "get()" function
2681 */
2682 static void
2683f_get(typval_T *argvars, typval_T *rettv)
2684{
2685 listitem_T *li;
2686 list_T *l;
2687 dictitem_T *di;
2688 dict_T *d;
2689 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002690 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002692 if (argvars[0].v_type == VAR_BLOB)
2693 {
2694 int error = FALSE;
2695 int idx = tv_get_number_chk(&argvars[1], &error);
2696
2697 if (!error)
2698 {
2699 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002700 if (idx < 0)
2701 idx = blob_len(argvars[0].vval.v_blob) + idx;
2702 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2703 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002704 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002705 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002706 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002707 tv = rettv;
2708 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002709 }
2710 }
2711 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002712 {
2713 if ((l = argvars[0].vval.v_list) != NULL)
2714 {
2715 int error = FALSE;
2716
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002717 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002718 if (!error && li != NULL)
2719 tv = &li->li_tv;
2720 }
2721 }
2722 else if (argvars[0].v_type == VAR_DICT)
2723 {
2724 if ((d = argvars[0].vval.v_dict) != NULL)
2725 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002726 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002727 if (di != NULL)
2728 tv = &di->di_tv;
2729 }
2730 }
2731 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2732 {
2733 partial_T *pt;
2734 partial_T fref_pt;
2735
2736 if (argvars[0].v_type == VAR_PARTIAL)
2737 pt = argvars[0].vval.v_partial;
2738 else
2739 {
2740 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2741 fref_pt.pt_name = argvars[0].vval.v_string;
2742 pt = &fref_pt;
2743 }
2744
2745 if (pt != NULL)
2746 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002747 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002748 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002749
2750 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2751 {
2752 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002753 n = partial_name(pt);
2754 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002755 rettv->vval.v_string = NULL;
2756 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002757 {
2758 rettv->vval.v_string = vim_strsave(n);
2759 if (rettv->v_type == VAR_FUNC)
2760 func_ref(rettv->vval.v_string);
2761 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 }
2763 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002764 {
2765 what_is_dict = TRUE;
2766 if (pt->pt_dict != NULL)
2767 rettv_dict_set(rettv, pt->pt_dict);
2768 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002769 else if (STRCMP(what, "args") == 0)
2770 {
2771 rettv->v_type = VAR_LIST;
2772 if (rettv_list_alloc(rettv) == OK)
2773 {
2774 int i;
2775
2776 for (i = 0; i < pt->pt_argc; ++i)
2777 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2778 }
2779 }
2780 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002781 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002782
2783 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2784 // third argument
2785 if (!what_is_dict)
2786 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 }
2788 }
2789 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002790 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002791
2792 if (tv == NULL)
2793 {
2794 if (argvars[2].v_type != VAR_UNKNOWN)
2795 copy_tv(&argvars[2], rettv);
2796 }
2797 else
2798 copy_tv(tv, rettv);
2799}
2800
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002801/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002802 * "getchangelist()" function
2803 */
2804 static void
2805f_getchangelist(typval_T *argvars, typval_T *rettv)
2806{
2807#ifdef FEAT_JUMPLIST
2808 buf_T *buf;
2809 int i;
2810 list_T *l;
2811 dict_T *d;
2812#endif
2813
2814 if (rettv_list_alloc(rettv) != OK)
2815 return;
2816
2817#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002818 if (argvars[0].v_type == VAR_UNKNOWN)
2819 buf = curbuf;
2820 else
2821 {
2822 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2823 ++emsg_off;
2824 buf = tv_get_buf(&argvars[0], FALSE);
2825 --emsg_off;
2826 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002827 if (buf == NULL)
2828 return;
2829
2830 l = list_alloc();
2831 if (l == NULL)
2832 return;
2833
2834 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2835 return;
2836 /*
2837 * The current window change list index tracks only the position in the
2838 * current buffer change list. For other buffers, use the change list
2839 * length as the current index.
2840 */
2841 list_append_number(rettv->vval.v_list,
2842 (varnumber_T)((buf == curwin->w_buffer)
2843 ? curwin->w_changelistidx : buf->b_changelistlen));
2844
2845 for (i = 0; i < buf->b_changelistlen; ++i)
2846 {
2847 if (buf->b_changelist[i].lnum == 0)
2848 continue;
2849 if ((d = dict_alloc()) == NULL)
2850 return;
2851 if (list_append_dict(l, d) == FAIL)
2852 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002853 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2854 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002855 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002856 }
2857#endif
2858}
2859/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860 * "getchar()" function
2861 */
2862 static void
2863f_getchar(typval_T *argvars, typval_T *rettv)
2864{
2865 varnumber_T n;
2866 int error = FALSE;
2867
Bram Moolenaar84d93902018-09-11 20:10:20 +02002868#ifdef MESSAGE_QUEUE
2869 // vpeekc() used to check for messages, but that caused problems, invoking
2870 // a callback where it was not expected. Some plugins use getchar(1) in a
2871 // loop to await a message, therefore make sure we check for messages here.
2872 parse_queued_messages();
2873#endif
2874
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002875 /* Position the cursor. Needed after a message that ends in a space. */
2876 windgoto(msg_row, msg_col);
2877
2878 ++no_mapping;
2879 ++allow_keys;
2880 for (;;)
2881 {
2882 if (argvars[0].v_type == VAR_UNKNOWN)
2883 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01002884 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002885 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002886 /* getchar(1): only check if char avail */
2887 n = vpeekc_any();
2888 else if (error || vpeekc_any() == NUL)
2889 /* illegal argument or getchar(0) and no char avail: return zero */
2890 n = 0;
2891 else
2892 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01002893 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002894
2895 if (n == K_IGNORE)
2896 continue;
2897 break;
2898 }
2899 --no_mapping;
2900 --allow_keys;
2901
2902 set_vim_var_nr(VV_MOUSE_WIN, 0);
2903 set_vim_var_nr(VV_MOUSE_WINID, 0);
2904 set_vim_var_nr(VV_MOUSE_LNUM, 0);
2905 set_vim_var_nr(VV_MOUSE_COL, 0);
2906
2907 rettv->vval.v_number = n;
2908 if (IS_SPECIAL(n) || mod_mask != 0)
2909 {
2910 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
2911 int i = 0;
2912
2913 /* Turn a special key into three bytes, plus modifier. */
2914 if (mod_mask != 0)
2915 {
2916 temp[i++] = K_SPECIAL;
2917 temp[i++] = KS_MODIFIER;
2918 temp[i++] = mod_mask;
2919 }
2920 if (IS_SPECIAL(n))
2921 {
2922 temp[i++] = K_SPECIAL;
2923 temp[i++] = K_SECOND(n);
2924 temp[i++] = K_THIRD(n);
2925 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926 else if (has_mbyte)
2927 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002928 else
2929 temp[i++] = n;
2930 temp[i++] = NUL;
2931 rettv->v_type = VAR_STRING;
2932 rettv->vval.v_string = vim_strsave(temp);
2933
2934#ifdef FEAT_MOUSE
2935 if (is_mouse_key(n))
2936 {
2937 int row = mouse_row;
2938 int col = mouse_col;
2939 win_T *win;
2940 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002941 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002942 int winnr = 1;
2943
2944 if (row >= 0 && col >= 0)
2945 {
2946 /* Find the window at the mouse coordinates and compute the
2947 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002948 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02002949 if (win == NULL)
2950 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02002951 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002952# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02002953 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002954 winnr = 0;
2955 else
2956# endif
2957 for (wp = firstwin; wp != win && wp != NULL;
2958 wp = wp->w_next)
2959 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002960 set_vim_var_nr(VV_MOUSE_WIN, winnr);
2961 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
2962 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
2963 set_vim_var_nr(VV_MOUSE_COL, col + 1);
2964 }
2965 }
2966#endif
2967 }
2968}
2969
2970/*
2971 * "getcharmod()" function
2972 */
2973 static void
2974f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
2975{
2976 rettv->vval.v_number = mod_mask;
2977}
2978
2979/*
2980 * "getcharsearch()" function
2981 */
2982 static void
2983f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2984{
2985 if (rettv_dict_alloc(rettv) != FAIL)
2986 {
2987 dict_T *dict = rettv->vval.v_dict;
2988
Bram Moolenaare0be1672018-07-08 16:50:37 +02002989 dict_add_string(dict, "char", last_csearch());
2990 dict_add_number(dict, "forward", last_csearch_forward());
2991 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002992 }
2993}
2994
2995/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002996 * "getcmdwintype()" function
2997 */
2998 static void
2999f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
3000{
3001 rettv->v_type = VAR_STRING;
3002 rettv->vval.v_string = NULL;
3003#ifdef FEAT_CMDWIN
3004 rettv->vval.v_string = alloc(2);
3005 if (rettv->vval.v_string != NULL)
3006 {
3007 rettv->vval.v_string[0] = cmdwin_type;
3008 rettv->vval.v_string[1] = NUL;
3009 }
3010#endif
3011}
3012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003013/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003014 * "getenv()" function
3015 */
3016 static void
3017f_getenv(typval_T *argvars, typval_T *rettv)
3018{
3019 int mustfree = FALSE;
3020 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3021
3022 if (p == NULL)
3023 {
3024 rettv->v_type = VAR_SPECIAL;
3025 rettv->vval.v_number = VVAL_NULL;
3026 return;
3027 }
3028 if (!mustfree)
3029 p = vim_strsave(p);
3030 rettv->vval.v_string = p;
3031 rettv->v_type = VAR_STRING;
3032}
3033
3034/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003035 * "getfontname()" function
3036 */
3037 static void
3038f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3039{
3040 rettv->v_type = VAR_STRING;
3041 rettv->vval.v_string = NULL;
3042#ifdef FEAT_GUI
3043 if (gui.in_use)
3044 {
3045 GuiFont font;
3046 char_u *name = NULL;
3047
3048 if (argvars[0].v_type == VAR_UNKNOWN)
3049 {
3050 /* Get the "Normal" font. Either the name saved by
3051 * hl_set_font_name() or from the font ID. */
3052 font = gui.norm_font;
3053 name = hl_get_font_name();
3054 }
3055 else
3056 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003057 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 if (STRCMP(name, "*") == 0) /* don't use font dialog */
3059 return;
3060 font = gui_mch_get_font(name, FALSE);
3061 if (font == NOFONT)
3062 return; /* Invalid font name, return empty string. */
3063 }
3064 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3065 if (argvars[0].v_type != VAR_UNKNOWN)
3066 gui_mch_free_font(font);
3067 }
3068#endif
3069}
3070
3071/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003072 * "getjumplist()" function
3073 */
3074 static void
3075f_getjumplist(typval_T *argvars, typval_T *rettv)
3076{
3077#ifdef FEAT_JUMPLIST
3078 win_T *wp;
3079 int i;
3080 list_T *l;
3081 dict_T *d;
3082#endif
3083
3084 if (rettv_list_alloc(rettv) != OK)
3085 return;
3086
3087#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003088 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003089 if (wp == NULL)
3090 return;
3091
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003092 cleanup_jumplist(wp, TRUE);
3093
Bram Moolenaar4f505882018-02-10 21:06:32 +01003094 l = list_alloc();
3095 if (l == NULL)
3096 return;
3097
3098 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3099 return;
3100 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3101
3102 for (i = 0; i < wp->w_jumplistlen; ++i)
3103 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003104 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3105 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003106 if ((d = dict_alloc()) == NULL)
3107 return;
3108 if (list_append_dict(l, d) == FAIL)
3109 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003110 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3111 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003112 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003113 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003114 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003115 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003116 }
3117#endif
3118}
3119
3120/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003121 * "getpid()" function
3122 */
3123 static void
3124f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3125{
3126 rettv->vval.v_number = mch_get_pid();
3127}
3128
3129 static void
3130getpos_both(
3131 typval_T *argvars,
3132 typval_T *rettv,
3133 int getcurpos)
3134{
3135 pos_T *fp;
3136 list_T *l;
3137 int fnum = -1;
3138
3139 if (rettv_list_alloc(rettv) == OK)
3140 {
3141 l = rettv->vval.v_list;
3142 if (getcurpos)
3143 fp = &curwin->w_cursor;
3144 else
3145 fp = var2fpos(&argvars[0], TRUE, &fnum);
3146 if (fnum != -1)
3147 list_append_number(l, (varnumber_T)fnum);
3148 else
3149 list_append_number(l, (varnumber_T)0);
3150 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3151 : (varnumber_T)0);
3152 list_append_number(l, (fp != NULL)
3153 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3154 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003155 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003156 (varnumber_T)0);
3157 if (getcurpos)
3158 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003159 int save_set_curswant = curwin->w_set_curswant;
3160 colnr_T save_curswant = curwin->w_curswant;
3161 colnr_T save_virtcol = curwin->w_virtcol;
3162
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003163 update_curswant();
3164 list_append_number(l, curwin->w_curswant == MAXCOL ?
3165 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003166
3167 // Do not change "curswant", as it is unexpected that a get
3168 // function has a side effect.
3169 if (save_set_curswant)
3170 {
3171 curwin->w_set_curswant = save_set_curswant;
3172 curwin->w_curswant = save_curswant;
3173 curwin->w_virtcol = save_virtcol;
3174 curwin->w_valid &= ~VALID_VIRTCOL;
3175 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003176 }
3177 }
3178 else
3179 rettv->vval.v_number = FALSE;
3180}
3181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003182/*
3183 * "getcurpos()" function
3184 */
3185 static void
3186f_getcurpos(typval_T *argvars, typval_T *rettv)
3187{
3188 getpos_both(argvars, rettv, TRUE);
3189}
3190
3191/*
3192 * "getpos(string)" function
3193 */
3194 static void
3195f_getpos(typval_T *argvars, typval_T *rettv)
3196{
3197 getpos_both(argvars, rettv, FALSE);
3198}
3199
3200/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003201 * "getreg()" function
3202 */
3203 static void
3204f_getreg(typval_T *argvars, typval_T *rettv)
3205{
3206 char_u *strregname;
3207 int regname;
3208 int arg2 = FALSE;
3209 int return_list = FALSE;
3210 int error = FALSE;
3211
3212 if (argvars[0].v_type != VAR_UNKNOWN)
3213 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003214 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003215 error = strregname == NULL;
3216 if (argvars[1].v_type != VAR_UNKNOWN)
3217 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003218 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003219 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003220 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003221 }
3222 }
3223 else
3224 strregname = get_vim_var_str(VV_REG);
3225
3226 if (error)
3227 return;
3228
3229 regname = (strregname == NULL ? '"' : *strregname);
3230 if (regname == 0)
3231 regname = '"';
3232
3233 if (return_list)
3234 {
3235 rettv->v_type = VAR_LIST;
3236 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3237 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3238 if (rettv->vval.v_list == NULL)
3239 (void)rettv_list_alloc(rettv);
3240 else
3241 ++rettv->vval.v_list->lv_refcount;
3242 }
3243 else
3244 {
3245 rettv->v_type = VAR_STRING;
3246 rettv->vval.v_string = get_reg_contents(regname,
3247 arg2 ? GREG_EXPR_SRC : 0);
3248 }
3249}
3250
3251/*
3252 * "getregtype()" function
3253 */
3254 static void
3255f_getregtype(typval_T *argvars, typval_T *rettv)
3256{
3257 char_u *strregname;
3258 int regname;
3259 char_u buf[NUMBUFLEN + 2];
3260 long reglen = 0;
3261
3262 if (argvars[0].v_type != VAR_UNKNOWN)
3263 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003264 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003265 if (strregname == NULL) /* type error; errmsg already given */
3266 {
3267 rettv->v_type = VAR_STRING;
3268 rettv->vval.v_string = NULL;
3269 return;
3270 }
3271 }
3272 else
3273 /* Default to v:register */
3274 strregname = get_vim_var_str(VV_REG);
3275
3276 regname = (strregname == NULL ? '"' : *strregname);
3277 if (regname == 0)
3278 regname = '"';
3279
3280 buf[0] = NUL;
3281 buf[1] = NUL;
3282 switch (get_reg_type(regname, &reglen))
3283 {
3284 case MLINE: buf[0] = 'V'; break;
3285 case MCHAR: buf[0] = 'v'; break;
3286 case MBLOCK:
3287 buf[0] = Ctrl_V;
3288 sprintf((char *)buf + 1, "%ld", reglen + 1);
3289 break;
3290 }
3291 rettv->v_type = VAR_STRING;
3292 rettv->vval.v_string = vim_strsave(buf);
3293}
3294
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003295/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003296 * "gettagstack()" function
3297 */
3298 static void
3299f_gettagstack(typval_T *argvars, typval_T *rettv)
3300{
3301 win_T *wp = curwin; // default is current window
3302
3303 if (rettv_dict_alloc(rettv) != OK)
3304 return;
3305
3306 if (argvars[0].v_type != VAR_UNKNOWN)
3307 {
3308 wp = find_win_by_nr_or_id(&argvars[0]);
3309 if (wp == NULL)
3310 return;
3311 }
3312
3313 get_tagstack(wp, rettv->vval.v_dict);
3314}
3315
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316/* for VIM_VERSION_ defines */
3317#include "version.h"
3318
3319/*
3320 * "has()" function
3321 */
3322 static void
3323f_has(typval_T *argvars, typval_T *rettv)
3324{
3325 int i;
3326 char_u *name;
3327 int n = FALSE;
3328 static char *(has_list[]) =
3329 {
3330#ifdef AMIGA
3331 "amiga",
3332# ifdef FEAT_ARP
3333 "arp",
3334# endif
3335#endif
3336#ifdef __BEOS__
3337 "beos",
3338#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003339#if defined(BSD) && !defined(MACOS_X)
3340 "bsd",
3341#endif
3342#ifdef hpux
3343 "hpux",
3344#endif
3345#ifdef __linux__
3346 "linux",
3347#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003348#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003349 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3350 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003351# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003352 "macunix", /* Mac OS X, with the darwin feature */
3353 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003354# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003355#endif
3356#ifdef __QNX__
3357 "qnx",
3358#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003359#ifdef SUN_SYSTEM
3360 "sun",
3361#else
3362 "moon",
3363#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003364#ifdef UNIX
3365 "unix",
3366#endif
3367#ifdef VMS
3368 "vms",
3369#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003370#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003371 "win32",
3372#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003373#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003374 "win32unix",
3375#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003376#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377 "win64",
3378#endif
3379#ifdef EBCDIC
3380 "ebcdic",
3381#endif
3382#ifndef CASE_INSENSITIVE_FILENAME
3383 "fname_case",
3384#endif
3385#ifdef HAVE_ACL
3386 "acl",
3387#endif
3388#ifdef FEAT_ARABIC
3389 "arabic",
3390#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003392#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003393 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003394#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003395#ifdef FEAT_AUTOSERVERNAME
3396 "autoservername",
3397#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003398#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003399 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003400# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003401 "balloon_multiline",
3402# endif
3403#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003404#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003405 "balloon_eval_term",
3406#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003407#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3408 "builtin_terms",
3409# ifdef ALL_BUILTIN_TCAPS
3410 "all_builtin_terms",
3411# endif
3412#endif
3413#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003414 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003415 || defined(FEAT_GUI_MOTIF))
3416 "browsefilter",
3417#endif
3418#ifdef FEAT_BYTEOFF
3419 "byte_offset",
3420#endif
3421#ifdef FEAT_JOB_CHANNEL
3422 "channel",
3423#endif
3424#ifdef FEAT_CINDENT
3425 "cindent",
3426#endif
3427#ifdef FEAT_CLIENTSERVER
3428 "clientserver",
3429#endif
3430#ifdef FEAT_CLIPBOARD
3431 "clipboard",
3432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003433 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435#ifdef FEAT_COMMENTS
3436 "comments",
3437#endif
3438#ifdef FEAT_CONCEAL
3439 "conceal",
3440#endif
3441#ifdef FEAT_CRYPT
3442 "cryptv",
3443 "crypt-blowfish",
3444 "crypt-blowfish2",
3445#endif
3446#ifdef FEAT_CSCOPE
3447 "cscope",
3448#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003450#ifdef CURSOR_SHAPE
3451 "cursorshape",
3452#endif
3453#ifdef DEBUG
3454 "debug",
3455#endif
3456#ifdef FEAT_CON_DIALOG
3457 "dialog_con",
3458#endif
3459#ifdef FEAT_GUI_DIALOG
3460 "dialog_gui",
3461#endif
3462#ifdef FEAT_DIFF
3463 "diff",
3464#endif
3465#ifdef FEAT_DIGRAPHS
3466 "digraphs",
3467#endif
3468#ifdef FEAT_DIRECTX
3469 "directx",
3470#endif
3471#ifdef FEAT_DND
3472 "dnd",
3473#endif
3474#ifdef FEAT_EMACS_TAGS
3475 "emacs_tags",
3476#endif
3477 "eval", /* always present, of course! */
3478 "ex_extra", /* graduated feature */
3479#ifdef FEAT_SEARCH_EXTRA
3480 "extra_search",
3481#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003482#ifdef FEAT_SEARCHPATH
3483 "file_in_path",
3484#endif
3485#ifdef FEAT_FILTERPIPE
3486 "filterpipe",
3487#endif
3488#ifdef FEAT_FIND_ID
3489 "find_in_path",
3490#endif
3491#ifdef FEAT_FLOAT
3492 "float",
3493#endif
3494#ifdef FEAT_FOLDING
3495 "folding",
3496#endif
3497#ifdef FEAT_FOOTER
3498 "footer",
3499#endif
3500#if !defined(USE_SYSTEM) && defined(UNIX)
3501 "fork",
3502#endif
3503#ifdef FEAT_GETTEXT
3504 "gettext",
3505#endif
3506#ifdef FEAT_GUI
3507 "gui",
3508#endif
3509#ifdef FEAT_GUI_ATHENA
3510# ifdef FEAT_GUI_NEXTAW
3511 "gui_neXtaw",
3512# else
3513 "gui_athena",
3514# endif
3515#endif
3516#ifdef FEAT_GUI_GTK
3517 "gui_gtk",
3518# ifdef USE_GTK3
3519 "gui_gtk3",
3520# else
3521 "gui_gtk2",
3522# endif
3523#endif
3524#ifdef FEAT_GUI_GNOME
3525 "gui_gnome",
3526#endif
3527#ifdef FEAT_GUI_MAC
3528 "gui_mac",
3529#endif
3530#ifdef FEAT_GUI_MOTIF
3531 "gui_motif",
3532#endif
3533#ifdef FEAT_GUI_PHOTON
3534 "gui_photon",
3535#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003536#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003537 "gui_win32",
3538#endif
3539#ifdef FEAT_HANGULIN
3540 "hangul_input",
3541#endif
3542#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3543 "iconv",
3544#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003545 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546#ifdef FEAT_JOB_CHANNEL
3547 "job",
3548#endif
3549#ifdef FEAT_JUMPLIST
3550 "jumplist",
3551#endif
3552#ifdef FEAT_KEYMAP
3553 "keymap",
3554#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003555 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003556#ifdef FEAT_LANGMAP
3557 "langmap",
3558#endif
3559#ifdef FEAT_LIBCALL
3560 "libcall",
3561#endif
3562#ifdef FEAT_LINEBREAK
3563 "linebreak",
3564#endif
3565#ifdef FEAT_LISP
3566 "lispindent",
3567#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570#ifdef FEAT_LUA
3571# ifndef DYNAMIC_LUA
3572 "lua",
3573# endif
3574#endif
3575#ifdef FEAT_MENU
3576 "menu",
3577#endif
3578#ifdef FEAT_SESSION
3579 "mksession",
3580#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003581 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582#ifdef FEAT_MOUSE
3583 "mouse",
3584#endif
3585#ifdef FEAT_MOUSESHAPE
3586 "mouseshape",
3587#endif
3588#if defined(UNIX) || defined(VMS)
3589# ifdef FEAT_MOUSE_DEC
3590 "mouse_dec",
3591# endif
3592# ifdef FEAT_MOUSE_GPM
3593 "mouse_gpm",
3594# endif
3595# ifdef FEAT_MOUSE_JSB
3596 "mouse_jsbterm",
3597# endif
3598# ifdef FEAT_MOUSE_NET
3599 "mouse_netterm",
3600# endif
3601# ifdef FEAT_MOUSE_PTERM
3602 "mouse_pterm",
3603# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003604# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605 "mouse_sgr",
3606# endif
3607# ifdef FEAT_SYSMOUSE
3608 "mouse_sysmouse",
3609# endif
3610# ifdef FEAT_MOUSE_URXVT
3611 "mouse_urxvt",
3612# endif
3613# ifdef FEAT_MOUSE_XTERM
3614 "mouse_xterm",
3615# endif
3616#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003617 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003618#ifdef FEAT_MBYTE_IME
3619 "multi_byte_ime",
3620#endif
3621#ifdef FEAT_MULTI_LANG
3622 "multi_lang",
3623#endif
3624#ifdef FEAT_MZSCHEME
3625#ifndef DYNAMIC_MZSCHEME
3626 "mzscheme",
3627#endif
3628#endif
3629#ifdef FEAT_NUM64
3630 "num64",
3631#endif
3632#ifdef FEAT_OLE
3633 "ole",
3634#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003635#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003637#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638#ifdef FEAT_PATH_EXTRA
3639 "path_extra",
3640#endif
3641#ifdef FEAT_PERL
3642#ifndef DYNAMIC_PERL
3643 "perl",
3644#endif
3645#endif
3646#ifdef FEAT_PERSISTENT_UNDO
3647 "persistent_undo",
3648#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003649#if defined(FEAT_PYTHON)
3650 "python_compiled",
3651# if defined(DYNAMIC_PYTHON)
3652 "python_dynamic",
3653# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003655 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003656# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003657#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003658#if defined(FEAT_PYTHON3)
3659 "python3_compiled",
3660# if defined(DYNAMIC_PYTHON3)
3661 "python3_dynamic",
3662# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003663 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003664 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003665# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003666#endif
3667#ifdef FEAT_POSTSCRIPT
3668 "postscript",
3669#endif
3670#ifdef FEAT_PRINTER
3671 "printer",
3672#endif
3673#ifdef FEAT_PROFILE
3674 "profile",
3675#endif
3676#ifdef FEAT_RELTIME
3677 "reltime",
3678#endif
3679#ifdef FEAT_QUICKFIX
3680 "quickfix",
3681#endif
3682#ifdef FEAT_RIGHTLEFT
3683 "rightleft",
3684#endif
3685#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3686 "ruby",
3687#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003688 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003689#ifdef FEAT_CMDL_INFO
3690 "showcmd",
3691 "cmdline_info",
3692#endif
3693#ifdef FEAT_SIGNS
3694 "signs",
3695#endif
3696#ifdef FEAT_SMARTINDENT
3697 "smartindent",
3698#endif
3699#ifdef STARTUPTIME
3700 "startuptime",
3701#endif
3702#ifdef FEAT_STL_OPT
3703 "statusline",
3704#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003705#ifdef FEAT_NETBEANS_INTG
3706 "netbeans_intg",
3707#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003708#ifdef FEAT_SOUND
3709 "sound",
3710#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003711#ifdef FEAT_SPELL
3712 "spell",
3713#endif
3714#ifdef FEAT_SYN_HL
3715 "syntax",
3716#endif
3717#if defined(USE_SYSTEM) || !defined(UNIX)
3718 "system",
3719#endif
3720#ifdef FEAT_TAG_BINS
3721 "tag_binary",
3722#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003723#ifdef FEAT_TCL
3724# ifndef DYNAMIC_TCL
3725 "tcl",
3726# endif
3727#endif
3728#ifdef FEAT_TERMGUICOLORS
3729 "termguicolors",
3730#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003731#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003732 "terminal",
3733#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003734#ifdef TERMINFO
3735 "terminfo",
3736#endif
3737#ifdef FEAT_TERMRESPONSE
3738 "termresponse",
3739#endif
3740#ifdef FEAT_TEXTOBJ
3741 "textobjects",
3742#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003743#ifdef FEAT_TEXT_PROP
3744 "textprop",
3745#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003746#ifdef HAVE_TGETENT
3747 "tgetent",
3748#endif
3749#ifdef FEAT_TIMERS
3750 "timers",
3751#endif
3752#ifdef FEAT_TITLE
3753 "title",
3754#endif
3755#ifdef FEAT_TOOLBAR
3756 "toolbar",
3757#endif
3758#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3759 "unnamedplus",
3760#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003761 "user-commands", /* was accidentally included in 5.4 */
3762 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003763#ifdef FEAT_VARTABS
3764 "vartabs",
3765#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003766 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767#ifdef FEAT_VIMINFO
3768 "viminfo",
3769#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003770 "vimscript-1",
3771 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003772 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003773 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003774 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003776 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003777#ifdef FEAT_VTP
3778 "vtp",
3779#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003780#ifdef FEAT_WILDIGN
3781 "wildignore",
3782#endif
3783#ifdef FEAT_WILDMENU
3784 "wildmenu",
3785#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003786 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787#ifdef FEAT_WAK
3788 "winaltkeys",
3789#endif
3790#ifdef FEAT_WRITEBACKUP
3791 "writebackup",
3792#endif
3793#ifdef FEAT_XIM
3794 "xim",
3795#endif
3796#ifdef FEAT_XFONTSET
3797 "xfontset",
3798#endif
3799#ifdef FEAT_XPM_W32
3800 "xpm",
3801 "xpm_w32", /* for backward compatibility */
3802#else
3803# if defined(HAVE_XPM)
3804 "xpm",
3805# endif
3806#endif
3807#ifdef USE_XSMP
3808 "xsmp",
3809#endif
3810#ifdef USE_XSMP_INTERACT
3811 "xsmp_interact",
3812#endif
3813#ifdef FEAT_XCLIPBOARD
3814 "xterm_clipboard",
3815#endif
3816#ifdef FEAT_XTERM_SAVE
3817 "xterm_save",
3818#endif
3819#if defined(UNIX) && defined(FEAT_X11)
3820 "X11",
3821#endif
3822 NULL
3823 };
3824
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003825 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826 for (i = 0; has_list[i] != NULL; ++i)
3827 if (STRICMP(name, has_list[i]) == 0)
3828 {
3829 n = TRUE;
3830 break;
3831 }
3832
3833 if (n == FALSE)
3834 {
3835 if (STRNICMP(name, "patch", 5) == 0)
3836 {
3837 if (name[5] == '-'
3838 && STRLEN(name) >= 11
3839 && vim_isdigit(name[6])
3840 && vim_isdigit(name[8])
3841 && vim_isdigit(name[10]))
3842 {
3843 int major = atoi((char *)name + 6);
3844 int minor = atoi((char *)name + 8);
3845
3846 /* Expect "patch-9.9.01234". */
3847 n = (major < VIM_VERSION_MAJOR
3848 || (major == VIM_VERSION_MAJOR
3849 && (minor < VIM_VERSION_MINOR
3850 || (minor == VIM_VERSION_MINOR
3851 && has_patch(atoi((char *)name + 10))))));
3852 }
3853 else
3854 n = has_patch(atoi((char *)name + 5));
3855 }
3856 else if (STRICMP(name, "vim_starting") == 0)
3857 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003858 else if (STRICMP(name, "ttyin") == 0)
3859 n = mch_input_isatty();
3860 else if (STRICMP(name, "ttyout") == 0)
3861 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003862 else if (STRICMP(name, "multi_byte_encoding") == 0)
3863 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003864#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003865 else if (STRICMP(name, "balloon_multiline") == 0)
3866 n = multiline_balloon_available();
3867#endif
3868#ifdef DYNAMIC_TCL
3869 else if (STRICMP(name, "tcl") == 0)
3870 n = tcl_enabled(FALSE);
3871#endif
3872#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3873 else if (STRICMP(name, "iconv") == 0)
3874 n = iconv_enabled(FALSE);
3875#endif
3876#ifdef DYNAMIC_LUA
3877 else if (STRICMP(name, "lua") == 0)
3878 n = lua_enabled(FALSE);
3879#endif
3880#ifdef DYNAMIC_MZSCHEME
3881 else if (STRICMP(name, "mzscheme") == 0)
3882 n = mzscheme_enabled(FALSE);
3883#endif
3884#ifdef DYNAMIC_RUBY
3885 else if (STRICMP(name, "ruby") == 0)
3886 n = ruby_enabled(FALSE);
3887#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003888#ifdef DYNAMIC_PYTHON
3889 else if (STRICMP(name, "python") == 0)
3890 n = python_enabled(FALSE);
3891#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003892#ifdef DYNAMIC_PYTHON3
3893 else if (STRICMP(name, "python3") == 0)
3894 n = python3_enabled(FALSE);
3895#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003896#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3897 else if (STRICMP(name, "pythonx") == 0)
3898 {
3899# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3900 if (p_pyx == 0)
3901 n = python3_enabled(FALSE) || python_enabled(FALSE);
3902 else if (p_pyx == 3)
3903 n = python3_enabled(FALSE);
3904 else if (p_pyx == 2)
3905 n = python_enabled(FALSE);
3906# elif defined(DYNAMIC_PYTHON)
3907 n = python_enabled(FALSE);
3908# elif defined(DYNAMIC_PYTHON3)
3909 n = python3_enabled(FALSE);
3910# endif
3911 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912#endif
3913#ifdef DYNAMIC_PERL
3914 else if (STRICMP(name, "perl") == 0)
3915 n = perl_enabled(FALSE);
3916#endif
3917#ifdef FEAT_GUI
3918 else if (STRICMP(name, "gui_running") == 0)
3919 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920# ifdef FEAT_BROWSE
3921 else if (STRICMP(name, "browse") == 0)
3922 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3923# endif
3924#endif
3925#ifdef FEAT_SYN_HL
3926 else if (STRICMP(name, "syntax_items") == 0)
3927 n = syntax_present(curwin);
3928#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003929#ifdef FEAT_VTP
3930 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003931 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932#endif
3933#ifdef FEAT_NETBEANS_INTG
3934 else if (STRICMP(name, "netbeans_enabled") == 0)
3935 n = netbeans_active();
3936#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003937#ifdef FEAT_MOUSE_GPM
3938 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3939 n = gpm_enabled();
3940#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003941#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003942 else if (STRICMP(name, "terminal") == 0)
3943 n = terminal_enabled();
3944#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003945#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003946 else if (STRICMP(name, "conpty") == 0)
3947 n = use_conpty();
3948#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003949#ifdef FEAT_CLIPBOARD
3950 else if (STRICMP(name, "clipboard_working") == 0)
3951 n = clip_star.available;
3952#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953 }
3954
3955 rettv->vval.v_number = n;
3956}
3957
3958/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003959 * "haslocaldir()" function
3960 */
3961 static void
3962f_haslocaldir(typval_T *argvars, typval_T *rettv)
3963{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003964 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003965 win_T *wp = NULL;
3966
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003967 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3968
3969 // Check for window-local and tab-local directories
3970 if (wp != NULL && wp->w_localdir != NULL)
3971 rettv->vval.v_number = 1;
3972 else if (tp != NULL && tp->tp_localdir != NULL)
3973 rettv->vval.v_number = 2;
3974 else
3975 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003976}
3977
3978/*
3979 * "hasmapto()" function
3980 */
3981 static void
3982f_hasmapto(typval_T *argvars, typval_T *rettv)
3983{
3984 char_u *name;
3985 char_u *mode;
3986 char_u buf[NUMBUFLEN];
3987 int abbr = FALSE;
3988
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003989 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003990 if (argvars[1].v_type == VAR_UNKNOWN)
3991 mode = (char_u *)"nvo";
3992 else
3993 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003994 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003995 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003996 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003997 }
3998
3999 if (map_to_exists(name, mode, abbr))
4000 rettv->vval.v_number = TRUE;
4001 else
4002 rettv->vval.v_number = FALSE;
4003}
4004
4005/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004006 * "highlightID(name)" function
4007 */
4008 static void
4009f_hlID(typval_T *argvars, typval_T *rettv)
4010{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004011 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012}
4013
4014/*
4015 * "highlight_exists()" function
4016 */
4017 static void
4018f_hlexists(typval_T *argvars, typval_T *rettv)
4019{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004020 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021}
4022
4023/*
4024 * "hostname()" function
4025 */
4026 static void
4027f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4028{
4029 char_u hostname[256];
4030
4031 mch_get_host_name(hostname, 256);
4032 rettv->v_type = VAR_STRING;
4033 rettv->vval.v_string = vim_strsave(hostname);
4034}
4035
4036/*
4037 * iconv() function
4038 */
4039 static void
4040f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4041{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004042 char_u buf1[NUMBUFLEN];
4043 char_u buf2[NUMBUFLEN];
4044 char_u *from, *to, *str;
4045 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004046
4047 rettv->v_type = VAR_STRING;
4048 rettv->vval.v_string = NULL;
4049
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004050 str = tv_get_string(&argvars[0]);
4051 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4052 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004053 vimconv.vc_type = CONV_NONE;
4054 convert_setup(&vimconv, from, to);
4055
4056 /* If the encodings are equal, no conversion needed. */
4057 if (vimconv.vc_type == CONV_NONE)
4058 rettv->vval.v_string = vim_strsave(str);
4059 else
4060 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4061
4062 convert_setup(&vimconv, NULL, NULL);
4063 vim_free(from);
4064 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004065}
4066
4067/*
4068 * "indent()" function
4069 */
4070 static void
4071f_indent(typval_T *argvars, typval_T *rettv)
4072{
4073 linenr_T lnum;
4074
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004075 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004076 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4077 rettv->vval.v_number = get_indent_lnum(lnum);
4078 else
4079 rettv->vval.v_number = -1;
4080}
4081
4082/*
4083 * "index()" function
4084 */
4085 static void
4086f_index(typval_T *argvars, typval_T *rettv)
4087{
4088 list_T *l;
4089 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004090 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091 long idx = 0;
4092 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004093 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004094
4095 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004096 if (argvars[0].v_type == VAR_BLOB)
4097 {
4098 typval_T tv;
4099 int start = 0;
4100
4101 if (argvars[2].v_type != VAR_UNKNOWN)
4102 {
4103 start = tv_get_number_chk(&argvars[2], &error);
4104 if (error)
4105 return;
4106 }
4107 b = argvars[0].vval.v_blob;
4108 if (b == NULL)
4109 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004110 if (start < 0)
4111 {
4112 start = blob_len(b) + start;
4113 if (start < 0)
4114 start = 0;
4115 }
4116
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004117 for (idx = start; idx < blob_len(b); ++idx)
4118 {
4119 tv.v_type = VAR_NUMBER;
4120 tv.vval.v_number = blob_get(b, idx);
4121 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4122 {
4123 rettv->vval.v_number = idx;
4124 return;
4125 }
4126 }
4127 return;
4128 }
4129 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004130 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004131 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004132 return;
4133 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004134
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004135 l = argvars[0].vval.v_list;
4136 if (l != NULL)
4137 {
4138 item = l->lv_first;
4139 if (argvars[2].v_type != VAR_UNKNOWN)
4140 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 /* Start at specified item. Use the cached index that list_find()
4142 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004143 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004144 idx = l->lv_idx;
4145 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004146 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004147 if (error)
4148 item = NULL;
4149 }
4150
4151 for ( ; item != NULL; item = item->li_next, ++idx)
4152 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4153 {
4154 rettv->vval.v_number = idx;
4155 break;
4156 }
4157 }
4158}
4159
4160static int inputsecret_flag = 0;
4161
4162/*
4163 * "input()" function
4164 * Also handles inputsecret() when inputsecret is set.
4165 */
4166 static void
4167f_input(typval_T *argvars, typval_T *rettv)
4168{
4169 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4170}
4171
4172/*
4173 * "inputdialog()" function
4174 */
4175 static void
4176f_inputdialog(typval_T *argvars, typval_T *rettv)
4177{
4178#if defined(FEAT_GUI_TEXTDIALOG)
4179 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4180 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4181 {
4182 char_u *message;
4183 char_u buf[NUMBUFLEN];
4184 char_u *defstr = (char_u *)"";
4185
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004186 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004187 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004188 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004189 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4190 else
4191 IObuff[0] = NUL;
4192 if (message != NULL && defstr != NULL
4193 && do_dialog(VIM_QUESTION, NULL, message,
4194 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4195 rettv->vval.v_string = vim_strsave(IObuff);
4196 else
4197 {
4198 if (message != NULL && defstr != NULL
4199 && argvars[1].v_type != VAR_UNKNOWN
4200 && argvars[2].v_type != VAR_UNKNOWN)
4201 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004202 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 else
4204 rettv->vval.v_string = NULL;
4205 }
4206 rettv->v_type = VAR_STRING;
4207 }
4208 else
4209#endif
4210 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4211}
4212
4213/*
4214 * "inputlist()" function
4215 */
4216 static void
4217f_inputlist(typval_T *argvars, typval_T *rettv)
4218{
4219 listitem_T *li;
4220 int selected;
4221 int mouse_used;
4222
4223#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004224 /* While starting up, there is no place to enter text. When running tests
4225 * with --not-a-term we assume feedkeys() will be used. */
4226 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004227 return;
4228#endif
4229 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4230 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004231 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004232 return;
4233 }
4234
4235 msg_start();
4236 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4237 lines_left = Rows; /* avoid more prompt */
4238 msg_scroll = TRUE;
4239 msg_clr_eos();
4240
4241 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4242 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004243 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004244 msg_putchar('\n');
4245 }
4246
4247 /* Ask for choice. */
4248 selected = prompt_for_number(&mouse_used);
4249 if (mouse_used)
4250 selected -= lines_left;
4251
4252 rettv->vval.v_number = selected;
4253}
4254
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4256
4257/*
4258 * "inputrestore()" function
4259 */
4260 static void
4261f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4262{
4263 if (ga_userinput.ga_len > 0)
4264 {
4265 --ga_userinput.ga_len;
4266 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4267 + ga_userinput.ga_len);
4268 /* default return is zero == OK */
4269 }
4270 else if (p_verbose > 1)
4271 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004272 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004273 rettv->vval.v_number = 1; /* Failed */
4274 }
4275}
4276
4277/*
4278 * "inputsave()" function
4279 */
4280 static void
4281f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4282{
4283 /* Add an entry to the stack of typeahead storage. */
4284 if (ga_grow(&ga_userinput, 1) == OK)
4285 {
4286 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4287 + ga_userinput.ga_len);
4288 ++ga_userinput.ga_len;
4289 /* default return is zero == OK */
4290 }
4291 else
4292 rettv->vval.v_number = 1; /* Failed */
4293}
4294
4295/*
4296 * "inputsecret()" function
4297 */
4298 static void
4299f_inputsecret(typval_T *argvars, typval_T *rettv)
4300{
4301 ++cmdline_star;
4302 ++inputsecret_flag;
4303 f_input(argvars, rettv);
4304 --cmdline_star;
4305 --inputsecret_flag;
4306}
4307
4308/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004309 * "invert(expr)" function
4310 */
4311 static void
4312f_invert(typval_T *argvars, typval_T *rettv)
4313{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004314 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004315}
4316
4317/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004318 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4319 * or it refers to a List or Dictionary that is locked.
4320 */
4321 static int
4322tv_islocked(typval_T *tv)
4323{
4324 return (tv->v_lock & VAR_LOCKED)
4325 || (tv->v_type == VAR_LIST
4326 && tv->vval.v_list != NULL
4327 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4328 || (tv->v_type == VAR_DICT
4329 && tv->vval.v_dict != NULL
4330 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4331}
4332
4333/*
4334 * "islocked()" function
4335 */
4336 static void
4337f_islocked(typval_T *argvars, typval_T *rettv)
4338{
4339 lval_T lv;
4340 char_u *end;
4341 dictitem_T *di;
4342
4343 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004344 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004345 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004346 if (end != NULL && lv.ll_name != NULL)
4347 {
4348 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004349 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004350 else
4351 {
4352 if (lv.ll_tv == NULL)
4353 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004354 di = find_var(lv.ll_name, NULL, TRUE);
4355 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004356 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004357 /* Consider a variable locked when:
4358 * 1. the variable itself is locked
4359 * 2. the value of the variable is locked.
4360 * 3. the List or Dict value is locked.
4361 */
4362 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4363 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004364 }
4365 }
4366 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004367 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004368 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004369 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004370 else if (lv.ll_list != NULL)
4371 /* List item. */
4372 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4373 else
4374 /* Dictionary item. */
4375 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4376 }
4377 }
4378
4379 clear_lval(&lv);
4380}
4381
4382#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4383/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004384 * "isinf()" function
4385 */
4386 static void
4387f_isinf(typval_T *argvars, typval_T *rettv)
4388{
4389 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4390 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4391}
4392
4393/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004394 * "isnan()" function
4395 */
4396 static void
4397f_isnan(typval_T *argvars, typval_T *rettv)
4398{
4399 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4400 && isnan(argvars[0].vval.v_float);
4401}
4402#endif
4403
4404/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004405 * "last_buffer_nr()" function.
4406 */
4407 static void
4408f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4409{
4410 int n = 0;
4411 buf_T *buf;
4412
Bram Moolenaar29323592016-07-24 22:04:11 +02004413 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004414 if (n < buf->b_fnum)
4415 n = buf->b_fnum;
4416
4417 rettv->vval.v_number = n;
4418}
4419
4420/*
4421 * "len()" function
4422 */
4423 static void
4424f_len(typval_T *argvars, typval_T *rettv)
4425{
4426 switch (argvars[0].v_type)
4427 {
4428 case VAR_STRING:
4429 case VAR_NUMBER:
4430 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004431 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004432 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004433 case VAR_BLOB:
4434 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4435 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004436 case VAR_LIST:
4437 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4438 break;
4439 case VAR_DICT:
4440 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4441 break;
4442 case VAR_UNKNOWN:
4443 case VAR_SPECIAL:
4444 case VAR_FLOAT:
4445 case VAR_FUNC:
4446 case VAR_PARTIAL:
4447 case VAR_JOB:
4448 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004449 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004450 break;
4451 }
4452}
4453
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004454 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004455libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004456{
4457#ifdef FEAT_LIBCALL
4458 char_u *string_in;
4459 char_u **string_result;
4460 int nr_result;
4461#endif
4462
4463 rettv->v_type = type;
4464 if (type != VAR_NUMBER)
4465 rettv->vval.v_string = NULL;
4466
4467 if (check_restricted() || check_secure())
4468 return;
4469
4470#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004471 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004472 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4473 {
4474 string_in = NULL;
4475 if (argvars[2].v_type == VAR_STRING)
4476 string_in = argvars[2].vval.v_string;
4477 if (type == VAR_NUMBER)
4478 string_result = NULL;
4479 else
4480 string_result = &rettv->vval.v_string;
4481 if (mch_libcall(argvars[0].vval.v_string,
4482 argvars[1].vval.v_string,
4483 string_in,
4484 argvars[2].vval.v_number,
4485 string_result,
4486 &nr_result) == OK
4487 && type == VAR_NUMBER)
4488 rettv->vval.v_number = nr_result;
4489 }
4490#endif
4491}
4492
4493/*
4494 * "libcall()" function
4495 */
4496 static void
4497f_libcall(typval_T *argvars, typval_T *rettv)
4498{
4499 libcall_common(argvars, rettv, VAR_STRING);
4500}
4501
4502/*
4503 * "libcallnr()" function
4504 */
4505 static void
4506f_libcallnr(typval_T *argvars, typval_T *rettv)
4507{
4508 libcall_common(argvars, rettv, VAR_NUMBER);
4509}
4510
4511/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004512 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004513 */
4514 static void
4515f_line(typval_T *argvars, typval_T *rettv)
4516{
4517 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004518 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004520 int id;
4521 tabpage_T *tp;
4522 win_T *wp;
4523 win_T *save_curwin;
4524 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004525
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004526 if (argvars[1].v_type != VAR_UNKNOWN)
4527 {
4528 // use window specified in the second argument
4529 id = (int)tv_get_number(&argvars[1]);
4530 wp = win_id2wp_tp(id, &tp);
4531 if (wp != NULL && tp != NULL)
4532 {
4533 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4534 == OK)
4535 {
4536 check_cursor();
4537 fp = var2fpos(&argvars[0], TRUE, &fnum);
4538 }
4539 restore_win_noblock(save_curwin, save_curtab, TRUE);
4540 }
4541 }
4542 else
4543 // use current window
4544 fp = var2fpos(&argvars[0], TRUE, &fnum);
4545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004546 if (fp != NULL)
4547 lnum = fp->lnum;
4548 rettv->vval.v_number = lnum;
4549}
4550
4551/*
4552 * "line2byte(lnum)" function
4553 */
4554 static void
4555f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4556{
4557#ifndef FEAT_BYTEOFF
4558 rettv->vval.v_number = -1;
4559#else
4560 linenr_T lnum;
4561
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004562 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4564 rettv->vval.v_number = -1;
4565 else
4566 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4567 if (rettv->vval.v_number >= 0)
4568 ++rettv->vval.v_number;
4569#endif
4570}
4571
4572/*
4573 * "lispindent(lnum)" function
4574 */
4575 static void
4576f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
4577{
4578#ifdef FEAT_LISP
4579 pos_T pos;
4580 linenr_T lnum;
4581
4582 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004583 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004584 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4585 {
4586 curwin->w_cursor.lnum = lnum;
4587 rettv->vval.v_number = get_lisp_indent();
4588 curwin->w_cursor = pos;
4589 }
4590 else
4591#endif
4592 rettv->vval.v_number = -1;
4593}
4594
4595/*
4596 * "localtime()" function
4597 */
4598 static void
4599f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4600{
4601 rettv->vval.v_number = (varnumber_T)time(NULL);
4602}
4603
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004604#ifdef FEAT_FLOAT
4605/*
4606 * "log()" function
4607 */
4608 static void
4609f_log(typval_T *argvars, typval_T *rettv)
4610{
4611 float_T f = 0.0;
4612
4613 rettv->v_type = VAR_FLOAT;
4614 if (get_float_arg(argvars, &f) == OK)
4615 rettv->vval.v_float = log(f);
4616 else
4617 rettv->vval.v_float = 0.0;
4618}
4619
4620/*
4621 * "log10()" function
4622 */
4623 static void
4624f_log10(typval_T *argvars, typval_T *rettv)
4625{
4626 float_T f = 0.0;
4627
4628 rettv->v_type = VAR_FLOAT;
4629 if (get_float_arg(argvars, &f) == OK)
4630 rettv->vval.v_float = log10(f);
4631 else
4632 rettv->vval.v_float = 0.0;
4633}
4634#endif
4635
4636#ifdef FEAT_LUA
4637/*
4638 * "luaeval()" function
4639 */
4640 static void
4641f_luaeval(typval_T *argvars, typval_T *rettv)
4642{
4643 char_u *str;
4644 char_u buf[NUMBUFLEN];
4645
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004646 if (check_restricted() || check_secure())
4647 return;
4648
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004649 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004650 do_luaeval(str, argvars + 1, rettv);
4651}
4652#endif
4653
4654/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004655 * "maparg()" function
4656 */
4657 static void
4658f_maparg(typval_T *argvars, typval_T *rettv)
4659{
4660 get_maparg(argvars, rettv, TRUE);
4661}
4662
4663/*
4664 * "mapcheck()" function
4665 */
4666 static void
4667f_mapcheck(typval_T *argvars, typval_T *rettv)
4668{
4669 get_maparg(argvars, rettv, FALSE);
4670}
4671
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004672typedef enum
4673{
4674 MATCH_END, /* matchend() */
4675 MATCH_MATCH, /* match() */
4676 MATCH_STR, /* matchstr() */
4677 MATCH_LIST, /* matchlist() */
4678 MATCH_POS /* matchstrpos() */
4679} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680
4681 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004682find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004683{
4684 char_u *str = NULL;
4685 long len = 0;
4686 char_u *expr = NULL;
4687 char_u *pat;
4688 regmatch_T regmatch;
4689 char_u patbuf[NUMBUFLEN];
4690 char_u strbuf[NUMBUFLEN];
4691 char_u *save_cpo;
4692 long start = 0;
4693 long nth = 1;
4694 colnr_T startcol = 0;
4695 int match = 0;
4696 list_T *l = NULL;
4697 listitem_T *li = NULL;
4698 long idx = 0;
4699 char_u *tofree = NULL;
4700
4701 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4702 save_cpo = p_cpo;
4703 p_cpo = (char_u *)"";
4704
4705 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004706 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004707 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004708 /* type MATCH_LIST: return empty list when there are no matches.
4709 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710 if (rettv_list_alloc(rettv) == FAIL)
4711 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004712 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004713 && (list_append_string(rettv->vval.v_list,
4714 (char_u *)"", 0) == FAIL
4715 || list_append_number(rettv->vval.v_list,
4716 (varnumber_T)-1) == 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 {
4722 list_free(rettv->vval.v_list);
4723 rettv->vval.v_list = NULL;
4724 goto theend;
4725 }
4726 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004727 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004728 {
4729 rettv->v_type = VAR_STRING;
4730 rettv->vval.v_string = NULL;
4731 }
4732
4733 if (argvars[0].v_type == VAR_LIST)
4734 {
4735 if ((l = argvars[0].vval.v_list) == NULL)
4736 goto theend;
4737 li = l->lv_first;
4738 }
4739 else
4740 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004741 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004742 len = (long)STRLEN(str);
4743 }
4744
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004745 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 if (pat == NULL)
4747 goto theend;
4748
4749 if (argvars[2].v_type != VAR_UNKNOWN)
4750 {
4751 int error = FALSE;
4752
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004753 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004754 if (error)
4755 goto theend;
4756 if (l != NULL)
4757 {
4758 li = list_find(l, start);
4759 if (li == NULL)
4760 goto theend;
4761 idx = l->lv_idx; /* use the cached index */
4762 }
4763 else
4764 {
4765 if (start < 0)
4766 start = 0;
4767 if (start > len)
4768 goto theend;
4769 /* When "count" argument is there ignore matches before "start",
4770 * otherwise skip part of the string. Differs when pattern is "^"
4771 * or "\<". */
4772 if (argvars[3].v_type != VAR_UNKNOWN)
4773 startcol = start;
4774 else
4775 {
4776 str += start;
4777 len -= start;
4778 }
4779 }
4780
4781 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004782 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004783 if (error)
4784 goto theend;
4785 }
4786
4787 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4788 if (regmatch.regprog != NULL)
4789 {
4790 regmatch.rm_ic = p_ic;
4791
4792 for (;;)
4793 {
4794 if (l != NULL)
4795 {
4796 if (li == NULL)
4797 {
4798 match = FALSE;
4799 break;
4800 }
4801 vim_free(tofree);
4802 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4803 if (str == NULL)
4804 break;
4805 }
4806
4807 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4808
4809 if (match && --nth <= 0)
4810 break;
4811 if (l == NULL && !match)
4812 break;
4813
4814 /* Advance to just after the match. */
4815 if (l != NULL)
4816 {
4817 li = li->li_next;
4818 ++idx;
4819 }
4820 else
4821 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004822 startcol = (colnr_T)(regmatch.startp[0]
4823 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004824 if (startcol > (colnr_T)len
4825 || str + startcol <= regmatch.startp[0])
4826 {
4827 match = FALSE;
4828 break;
4829 }
4830 }
4831 }
4832
4833 if (match)
4834 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004835 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004836 {
4837 listitem_T *li1 = rettv->vval.v_list->lv_first;
4838 listitem_T *li2 = li1->li_next;
4839 listitem_T *li3 = li2->li_next;
4840 listitem_T *li4 = li3->li_next;
4841
4842 vim_free(li1->li_tv.vval.v_string);
4843 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4844 (int)(regmatch.endp[0] - regmatch.startp[0]));
4845 li3->li_tv.vval.v_number =
4846 (varnumber_T)(regmatch.startp[0] - expr);
4847 li4->li_tv.vval.v_number =
4848 (varnumber_T)(regmatch.endp[0] - expr);
4849 if (l != NULL)
4850 li2->li_tv.vval.v_number = (varnumber_T)idx;
4851 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004852 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853 {
4854 int i;
4855
4856 /* return list with matched string and submatches */
4857 for (i = 0; i < NSUBEXP; ++i)
4858 {
4859 if (regmatch.endp[i] == NULL)
4860 {
4861 if (list_append_string(rettv->vval.v_list,
4862 (char_u *)"", 0) == FAIL)
4863 break;
4864 }
4865 else if (list_append_string(rettv->vval.v_list,
4866 regmatch.startp[i],
4867 (int)(regmatch.endp[i] - regmatch.startp[i]))
4868 == FAIL)
4869 break;
4870 }
4871 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004872 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004873 {
4874 /* return matched string */
4875 if (l != NULL)
4876 copy_tv(&li->li_tv, rettv);
4877 else
4878 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4879 (int)(regmatch.endp[0] - regmatch.startp[0]));
4880 }
4881 else if (l != NULL)
4882 rettv->vval.v_number = idx;
4883 else
4884 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004885 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004886 rettv->vval.v_number =
4887 (varnumber_T)(regmatch.startp[0] - str);
4888 else
4889 rettv->vval.v_number =
4890 (varnumber_T)(regmatch.endp[0] - str);
4891 rettv->vval.v_number += (varnumber_T)(str - expr);
4892 }
4893 }
4894 vim_regfree(regmatch.regprog);
4895 }
4896
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004897theend:
4898 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004899 /* matchstrpos() without a list: drop the second item. */
4900 listitem_remove(rettv->vval.v_list,
4901 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004902 vim_free(tofree);
4903 p_cpo = save_cpo;
4904}
4905
4906/*
4907 * "match()" function
4908 */
4909 static void
4910f_match(typval_T *argvars, typval_T *rettv)
4911{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004912 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004913}
4914
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915/*
4916 * "matchend()" function
4917 */
4918 static void
4919f_matchend(typval_T *argvars, typval_T *rettv)
4920{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004921 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922}
4923
4924/*
4925 * "matchlist()" function
4926 */
4927 static void
4928f_matchlist(typval_T *argvars, typval_T *rettv)
4929{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004930 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931}
4932
4933/*
4934 * "matchstr()" function
4935 */
4936 static void
4937f_matchstr(typval_T *argvars, typval_T *rettv)
4938{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004939 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940}
4941
4942/*
4943 * "matchstrpos()" function
4944 */
4945 static void
4946f_matchstrpos(typval_T *argvars, typval_T *rettv)
4947{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004948 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004949}
4950
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004951 static void
4952max_min(typval_T *argvars, typval_T *rettv, int domax)
4953{
4954 varnumber_T n = 0;
4955 varnumber_T i;
4956 int error = FALSE;
4957
4958 if (argvars[0].v_type == VAR_LIST)
4959 {
4960 list_T *l;
4961 listitem_T *li;
4962
4963 l = argvars[0].vval.v_list;
4964 if (l != NULL)
4965 {
4966 li = l->lv_first;
4967 if (li != NULL)
4968 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004969 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004970 for (;;)
4971 {
4972 li = li->li_next;
4973 if (li == NULL)
4974 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004975 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 if (domax ? i > n : i < n)
4977 n = i;
4978 }
4979 }
4980 }
4981 }
4982 else if (argvars[0].v_type == VAR_DICT)
4983 {
4984 dict_T *d;
4985 int first = TRUE;
4986 hashitem_T *hi;
4987 int todo;
4988
4989 d = argvars[0].vval.v_dict;
4990 if (d != NULL)
4991 {
4992 todo = (int)d->dv_hashtab.ht_used;
4993 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4994 {
4995 if (!HASHITEM_EMPTY(hi))
4996 {
4997 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004998 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004999 if (first)
5000 {
5001 n = i;
5002 first = FALSE;
5003 }
5004 else if (domax ? i > n : i < n)
5005 n = i;
5006 }
5007 }
5008 }
5009 }
5010 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005011 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005012 rettv->vval.v_number = error ? 0 : n;
5013}
5014
5015/*
5016 * "max()" function
5017 */
5018 static void
5019f_max(typval_T *argvars, typval_T *rettv)
5020{
5021 max_min(argvars, rettv, TRUE);
5022}
5023
5024/*
5025 * "min()" function
5026 */
5027 static void
5028f_min(typval_T *argvars, typval_T *rettv)
5029{
5030 max_min(argvars, rettv, FALSE);
5031}
5032
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005033/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034 * "mode()" function
5035 */
5036 static void
5037f_mode(typval_T *argvars, typval_T *rettv)
5038{
Bram Moolenaar612cc382018-07-29 15:34:26 +02005039 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005040
Bram Moolenaar612cc382018-07-29 15:34:26 +02005041 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042
5043 if (time_for_testing == 93784)
5044 {
5045 /* Testing the two-character code. */
5046 buf[0] = 'x';
5047 buf[1] = '!';
5048 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02005049#ifdef FEAT_TERMINAL
5050 else if (term_use_loop())
5051 buf[0] = 't';
5052#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053 else if (VIsual_active)
5054 {
5055 if (VIsual_select)
5056 buf[0] = VIsual_mode + 's' - 'v';
5057 else
5058 buf[0] = VIsual_mode;
5059 }
5060 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
5061 || State == CONFIRM)
5062 {
5063 buf[0] = 'r';
5064 if (State == ASKMORE)
5065 buf[1] = 'm';
5066 else if (State == CONFIRM)
5067 buf[1] = '?';
5068 }
5069 else if (State == EXTERNCMD)
5070 buf[0] = '!';
5071 else if (State & INSERT)
5072 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005073 if (State & VREPLACE_FLAG)
5074 {
5075 buf[0] = 'R';
5076 buf[1] = 'v';
5077 }
5078 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01005079 {
5080 if (State & REPLACE_FLAG)
5081 buf[0] = 'R';
5082 else
5083 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005084 if (ins_compl_active())
5085 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01005086 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01005087 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005088 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005089 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01005090 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005091 {
5092 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005093 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005095 else if (exmode_active == EXMODE_NORMAL)
5096 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097 }
5098 else
5099 {
5100 buf[0] = 'n';
5101 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01005102 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01005104 // to be able to detect force-linewise/blockwise/characterwise operations
5105 buf[2] = motion_force;
5106 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02005107 else if (restart_edit == 'I' || restart_edit == 'R'
5108 || restart_edit == 'V')
5109 {
5110 buf[1] = 'i';
5111 buf[2] = restart_edit;
5112 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113 }
5114
5115 /* Clear out the minor mode when the argument is not a non-zero number or
5116 * non-empty string. */
5117 if (!non_zero_arg(&argvars[0]))
5118 buf[1] = NUL;
5119
5120 rettv->vval.v_string = vim_strsave(buf);
5121 rettv->v_type = VAR_STRING;
5122}
5123
5124#if defined(FEAT_MZSCHEME) || defined(PROTO)
5125/*
5126 * "mzeval()" function
5127 */
5128 static void
5129f_mzeval(typval_T *argvars, typval_T *rettv)
5130{
5131 char_u *str;
5132 char_u buf[NUMBUFLEN];
5133
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005134 if (check_restricted() || check_secure())
5135 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005136 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 do_mzeval(str, rettv);
5138}
5139
5140 void
5141mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5142{
5143 typval_T argvars[3];
5144
5145 argvars[0].v_type = VAR_STRING;
5146 argvars[0].vval.v_string = name;
5147 copy_tv(args, &argvars[1]);
5148 argvars[2].v_type = VAR_UNKNOWN;
5149 f_call(argvars, rettv);
5150 clear_tv(&argvars[1]);
5151}
5152#endif
5153
5154/*
5155 * "nextnonblank()" function
5156 */
5157 static void
5158f_nextnonblank(typval_T *argvars, typval_T *rettv)
5159{
5160 linenr_T lnum;
5161
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005162 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005163 {
5164 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5165 {
5166 lnum = 0;
5167 break;
5168 }
5169 if (*skipwhite(ml_get(lnum)) != NUL)
5170 break;
5171 }
5172 rettv->vval.v_number = lnum;
5173}
5174
5175/*
5176 * "nr2char()" function
5177 */
5178 static void
5179f_nr2char(typval_T *argvars, typval_T *rettv)
5180{
5181 char_u buf[NUMBUFLEN];
5182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005183 if (has_mbyte)
5184 {
5185 int utf8 = 0;
5186
5187 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005188 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005189 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005190 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005191 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005192 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193 }
5194 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005195 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005196 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005197 buf[1] = NUL;
5198 }
5199 rettv->v_type = VAR_STRING;
5200 rettv->vval.v_string = vim_strsave(buf);
5201}
5202
5203/*
5204 * "or(expr, expr)" function
5205 */
5206 static void
5207f_or(typval_T *argvars, typval_T *rettv)
5208{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005209 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5210 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005211}
5212
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005213#ifdef FEAT_PERL
5214/*
5215 * "perleval()" function
5216 */
5217 static void
5218f_perleval(typval_T *argvars, typval_T *rettv)
5219{
5220 char_u *str;
5221 char_u buf[NUMBUFLEN];
5222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005223 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005224 do_perleval(str, rettv);
5225}
5226#endif
5227
5228#ifdef FEAT_FLOAT
5229/*
5230 * "pow()" function
5231 */
5232 static void
5233f_pow(typval_T *argvars, typval_T *rettv)
5234{
5235 float_T fx = 0.0, fy = 0.0;
5236
5237 rettv->v_type = VAR_FLOAT;
5238 if (get_float_arg(argvars, &fx) == OK
5239 && get_float_arg(&argvars[1], &fy) == OK)
5240 rettv->vval.v_float = pow(fx, fy);
5241 else
5242 rettv->vval.v_float = 0.0;
5243}
5244#endif
5245
5246/*
5247 * "prevnonblank()" function
5248 */
5249 static void
5250f_prevnonblank(typval_T *argvars, typval_T *rettv)
5251{
5252 linenr_T lnum;
5253
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005254 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005255 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5256 lnum = 0;
5257 else
5258 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5259 --lnum;
5260 rettv->vval.v_number = lnum;
5261}
5262
5263/* This dummy va_list is here because:
5264 * - passing a NULL pointer doesn't work when va_list isn't a pointer
5265 * - locally in the function results in a "used before set" warning
5266 * - using va_start() to initialize it gives "function with fixed args" error */
5267static va_list ap;
5268
5269/*
5270 * "printf()" function
5271 */
5272 static void
5273f_printf(typval_T *argvars, typval_T *rettv)
5274{
5275 char_u buf[NUMBUFLEN];
5276 int len;
5277 char_u *s;
5278 int saved_did_emsg = did_emsg;
5279 char *fmt;
5280
5281 rettv->v_type = VAR_STRING;
5282 rettv->vval.v_string = NULL;
5283
5284 /* Get the required length, allocate the buffer and do it for real. */
5285 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005286 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005287 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288 if (!did_emsg)
5289 {
5290 s = alloc(len + 1);
5291 if (s != NULL)
5292 {
5293 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005294 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5295 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296 }
5297 }
5298 did_emsg |= saved_did_emsg;
5299}
5300
5301/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005302 * "pum_getpos()" function
5303 */
5304 static void
5305f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5306{
5307 if (rettv_dict_alloc(rettv) != OK)
5308 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005309 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005310}
5311
5312/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005313 * "pumvisible()" function
5314 */
5315 static void
5316f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5317{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005318 if (pum_visible())
5319 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005320}
5321
5322#ifdef FEAT_PYTHON3
5323/*
5324 * "py3eval()" function
5325 */
5326 static void
5327f_py3eval(typval_T *argvars, typval_T *rettv)
5328{
5329 char_u *str;
5330 char_u buf[NUMBUFLEN];
5331
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005332 if (check_restricted() || check_secure())
5333 return;
5334
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005335 if (p_pyx == 0)
5336 p_pyx = 3;
5337
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005338 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005339 do_py3eval(str, rettv);
5340}
5341#endif
5342
5343#ifdef FEAT_PYTHON
5344/*
5345 * "pyeval()" function
5346 */
5347 static void
5348f_pyeval(typval_T *argvars, typval_T *rettv)
5349{
5350 char_u *str;
5351 char_u buf[NUMBUFLEN];
5352
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005353 if (check_restricted() || check_secure())
5354 return;
5355
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005356 if (p_pyx == 0)
5357 p_pyx = 2;
5358
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005359 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005360 do_pyeval(str, rettv);
5361}
5362#endif
5363
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005364#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5365/*
5366 * "pyxeval()" function
5367 */
5368 static void
5369f_pyxeval(typval_T *argvars, typval_T *rettv)
5370{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005371 if (check_restricted() || check_secure())
5372 return;
5373
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005374# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5375 init_pyxversion();
5376 if (p_pyx == 2)
5377 f_pyeval(argvars, rettv);
5378 else
5379 f_py3eval(argvars, rettv);
5380# elif defined(FEAT_PYTHON)
5381 f_pyeval(argvars, rettv);
5382# elif defined(FEAT_PYTHON3)
5383 f_py3eval(argvars, rettv);
5384# endif
5385}
5386#endif
5387
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005388/*
5389 * "range()" function
5390 */
5391 static void
5392f_range(typval_T *argvars, typval_T *rettv)
5393{
5394 varnumber_T start;
5395 varnumber_T end;
5396 varnumber_T stride = 1;
5397 varnumber_T i;
5398 int error = FALSE;
5399
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005400 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005401 if (argvars[1].v_type == VAR_UNKNOWN)
5402 {
5403 end = start - 1;
5404 start = 0;
5405 }
5406 else
5407 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005408 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005409 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005410 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005411 }
5412
5413 if (error)
5414 return; /* type error; errmsg already given */
5415 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005416 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005418 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005419 else
5420 {
5421 if (rettv_list_alloc(rettv) == OK)
5422 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5423 if (list_append_number(rettv->vval.v_list,
5424 (varnumber_T)i) == FAIL)
5425 break;
5426 }
5427}
5428
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005429 static void
5430return_register(int regname, typval_T *rettv)
5431{
5432 char_u buf[2] = {0, 0};
5433
5434 buf[0] = (char_u)regname;
5435 rettv->v_type = VAR_STRING;
5436 rettv->vval.v_string = vim_strsave(buf);
5437}
5438
5439/*
5440 * "reg_executing()" function
5441 */
5442 static void
5443f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5444{
5445 return_register(reg_executing, rettv);
5446}
5447
5448/*
5449 * "reg_recording()" function
5450 */
5451 static void
5452f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5453{
5454 return_register(reg_recording, rettv);
5455}
5456
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005458/*
5459 * Convert a List to proftime_T.
5460 * Return FAIL when there is something wrong.
5461 */
5462 static int
5463list2proftime(typval_T *arg, proftime_T *tm)
5464{
5465 long n1, n2;
5466 int error = FALSE;
5467
5468 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5469 || arg->vval.v_list->lv_len != 2)
5470 return FAIL;
5471 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5472 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005473# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005474 tm->HighPart = n1;
5475 tm->LowPart = n2;
5476# else
5477 tm->tv_sec = n1;
5478 tm->tv_usec = n2;
5479# endif
5480 return error ? FAIL : OK;
5481}
5482#endif /* FEAT_RELTIME */
5483
5484/*
5485 * "reltime()" function
5486 */
5487 static void
5488f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5489{
5490#ifdef FEAT_RELTIME
5491 proftime_T res;
5492 proftime_T start;
5493
5494 if (argvars[0].v_type == VAR_UNKNOWN)
5495 {
5496 /* No arguments: get current time. */
5497 profile_start(&res);
5498 }
5499 else if (argvars[1].v_type == VAR_UNKNOWN)
5500 {
5501 if (list2proftime(&argvars[0], &res) == FAIL)
5502 return;
5503 profile_end(&res);
5504 }
5505 else
5506 {
5507 /* Two arguments: compute the difference. */
5508 if (list2proftime(&argvars[0], &start) == FAIL
5509 || list2proftime(&argvars[1], &res) == FAIL)
5510 return;
5511 profile_sub(&res, &start);
5512 }
5513
5514 if (rettv_list_alloc(rettv) == OK)
5515 {
5516 long n1, n2;
5517
Bram Moolenaar4f974752019-02-17 17:44:42 +01005518# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005519 n1 = res.HighPart;
5520 n2 = res.LowPart;
5521# else
5522 n1 = res.tv_sec;
5523 n2 = res.tv_usec;
5524# endif
5525 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5526 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5527 }
5528#endif
5529}
5530
5531#ifdef FEAT_FLOAT
5532/*
5533 * "reltimefloat()" function
5534 */
5535 static void
5536f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5537{
5538# ifdef FEAT_RELTIME
5539 proftime_T tm;
5540# endif
5541
5542 rettv->v_type = VAR_FLOAT;
5543 rettv->vval.v_float = 0;
5544# ifdef FEAT_RELTIME
5545 if (list2proftime(&argvars[0], &tm) == OK)
5546 rettv->vval.v_float = profile_float(&tm);
5547# endif
5548}
5549#endif
5550
5551/*
5552 * "reltimestr()" function
5553 */
5554 static void
5555f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5556{
5557#ifdef FEAT_RELTIME
5558 proftime_T tm;
5559#endif
5560
5561 rettv->v_type = VAR_STRING;
5562 rettv->vval.v_string = NULL;
5563#ifdef FEAT_RELTIME
5564 if (list2proftime(&argvars[0], &tm) == OK)
5565 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5566#endif
5567}
5568
5569#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005570 static void
5571make_connection(void)
5572{
5573 if (X_DISPLAY == NULL
5574# ifdef FEAT_GUI
5575 && !gui.in_use
5576# endif
5577 )
5578 {
5579 x_force_connect = TRUE;
5580 setup_term_clip();
5581 x_force_connect = FALSE;
5582 }
5583}
5584
5585 static int
5586check_connection(void)
5587{
5588 make_connection();
5589 if (X_DISPLAY == NULL)
5590 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005591 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005592 return FAIL;
5593 }
5594 return OK;
5595}
5596#endif
5597
5598#ifdef FEAT_CLIENTSERVER
5599 static void
5600remote_common(typval_T *argvars, typval_T *rettv, int expr)
5601{
5602 char_u *server_name;
5603 char_u *keys;
5604 char_u *r = NULL;
5605 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005606 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005607# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005608 HWND w;
5609# else
5610 Window w;
5611# endif
5612
5613 if (check_restricted() || check_secure())
5614 return;
5615
5616# ifdef FEAT_X11
5617 if (check_connection() == FAIL)
5618 return;
5619# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005620 if (argvars[2].v_type != VAR_UNKNOWN
5621 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005622 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005623
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005624 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625 if (server_name == NULL)
5626 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005627 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005628# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005629 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005631 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5632 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005633# endif
5634 {
5635 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005636 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005637 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005638 vim_free(r);
5639 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005640 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005641 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642 return;
5643 }
5644
5645 rettv->vval.v_string = r;
5646
5647 if (argvars[2].v_type != VAR_UNKNOWN)
5648 {
5649 dictitem_T v;
5650 char_u str[30];
5651 char_u *idvar;
5652
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005653 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005654 if (idvar != NULL && *idvar != NUL)
5655 {
5656 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5657 v.di_tv.v_type = VAR_STRING;
5658 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005660 vim_free(v.di_tv.vval.v_string);
5661 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005662 }
5663}
5664#endif
5665
5666/*
5667 * "remote_expr()" function
5668 */
5669 static void
5670f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5671{
5672 rettv->v_type = VAR_STRING;
5673 rettv->vval.v_string = NULL;
5674#ifdef FEAT_CLIENTSERVER
5675 remote_common(argvars, rettv, TRUE);
5676#endif
5677}
5678
5679/*
5680 * "remote_foreground()" function
5681 */
5682 static void
5683f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5684{
5685#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005686# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005687 /* On Win32 it's done in this application. */
5688 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005689 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005690
5691 if (server_name != NULL)
5692 serverForeground(server_name);
5693 }
5694# else
5695 /* Send a foreground() expression to the server. */
5696 argvars[1].v_type = VAR_STRING;
5697 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5698 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005699 rettv->v_type = VAR_STRING;
5700 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005701 remote_common(argvars, rettv, TRUE);
5702 vim_free(argvars[1].vval.v_string);
5703# endif
5704#endif
5705}
5706
5707 static void
5708f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5709{
5710#ifdef FEAT_CLIENTSERVER
5711 dictitem_T v;
5712 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005713# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005714 long_u n = 0;
5715# endif
5716 char_u *serverid;
5717
5718 if (check_restricted() || check_secure())
5719 {
5720 rettv->vval.v_number = -1;
5721 return;
5722 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005723 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005724 if (serverid == NULL)
5725 {
5726 rettv->vval.v_number = -1;
5727 return; /* type error; errmsg already given */
5728 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005729# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005730 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5731 if (n == 0)
5732 rettv->vval.v_number = -1;
5733 else
5734 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005735 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005736 rettv->vval.v_number = (s != NULL);
5737 }
5738# else
5739 if (check_connection() == FAIL)
5740 return;
5741
5742 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5743 serverStrToWin(serverid), &s);
5744# endif
5745
5746 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5747 {
5748 char_u *retvar;
5749
5750 v.di_tv.v_type = VAR_STRING;
5751 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005752 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005753 if (retvar != NULL)
5754 set_var(retvar, &v.di_tv, FALSE);
5755 vim_free(v.di_tv.vval.v_string);
5756 }
5757#else
5758 rettv->vval.v_number = -1;
5759#endif
5760}
5761
5762 static void
5763f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5764{
5765 char_u *r = NULL;
5766
5767#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005768 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005769
5770 if (serverid != NULL && !check_restricted() && !check_secure())
5771 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005772 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005773# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005774 /* The server's HWND is encoded in the 'id' parameter */
5775 long_u n = 0;
5776# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005777
5778 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005779 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005780
Bram Moolenaar4f974752019-02-17 17:44:42 +01005781# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5783 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005784 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005785 if (r == NULL)
5786# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005787 if (check_connection() == FAIL
5788 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5789 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005791 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 }
5793#endif
5794 rettv->v_type = VAR_STRING;
5795 rettv->vval.v_string = r;
5796}
5797
5798/*
5799 * "remote_send()" function
5800 */
5801 static void
5802f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5803{
5804 rettv->v_type = VAR_STRING;
5805 rettv->vval.v_string = NULL;
5806#ifdef FEAT_CLIENTSERVER
5807 remote_common(argvars, rettv, FALSE);
5808#endif
5809}
5810
5811/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005812 * "remote_startserver()" function
5813 */
5814 static void
5815f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5816{
5817#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005818 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005819
5820 if (server == NULL)
5821 return; /* type error; errmsg already given */
5822 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005823 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005824 else
5825 {
5826# ifdef FEAT_X11
5827 if (check_connection() == OK)
5828 serverRegisterName(X_DISPLAY, server);
5829# else
5830 serverSetName(server);
5831# endif
5832 }
5833#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005834 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005835#endif
5836}
5837
5838/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005839 * "rename({from}, {to})" function
5840 */
5841 static void
5842f_rename(typval_T *argvars, typval_T *rettv)
5843{
5844 char_u buf[NUMBUFLEN];
5845
5846 if (check_restricted() || check_secure())
5847 rettv->vval.v_number = -1;
5848 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005849 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5850 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005851}
5852
5853/*
5854 * "repeat()" function
5855 */
5856 static void
5857f_repeat(typval_T *argvars, typval_T *rettv)
5858{
5859 char_u *p;
5860 int n;
5861 int slen;
5862 int len;
5863 char_u *r;
5864 int i;
5865
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005866 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005867 if (argvars[0].v_type == VAR_LIST)
5868 {
5869 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5870 while (n-- > 0)
5871 if (list_extend(rettv->vval.v_list,
5872 argvars[0].vval.v_list, NULL) == FAIL)
5873 break;
5874 }
5875 else
5876 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005877 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005878 rettv->v_type = VAR_STRING;
5879 rettv->vval.v_string = NULL;
5880
5881 slen = (int)STRLEN(p);
5882 len = slen * n;
5883 if (len <= 0)
5884 return;
5885
5886 r = alloc(len + 1);
5887 if (r != NULL)
5888 {
5889 for (i = 0; i < n; i++)
5890 mch_memmove(r + i * slen, p, (size_t)slen);
5891 r[len] = NUL;
5892 }
5893
5894 rettv->vval.v_string = r;
5895 }
5896}
5897
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005898#define SP_NOMOVE 0x01 /* don't move cursor */
5899#define SP_REPEAT 0x02 /* repeat to find outer pair */
5900#define SP_RETCOUNT 0x04 /* return matchcount */
5901#define SP_SETPCMARK 0x08 /* set previous context mark */
5902#define SP_START 0x10 /* accept match at start position */
5903#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5904#define SP_END 0x40 /* leave cursor at end of match */
5905#define SP_COLUMN 0x80 /* start at cursor column */
5906
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005907/*
5908 * Get flags for a search function.
5909 * Possibly sets "p_ws".
5910 * Returns BACKWARD, FORWARD or zero (for an error).
5911 */
5912 static int
5913get_search_arg(typval_T *varp, int *flagsp)
5914{
5915 int dir = FORWARD;
5916 char_u *flags;
5917 char_u nbuf[NUMBUFLEN];
5918 int mask;
5919
5920 if (varp->v_type != VAR_UNKNOWN)
5921 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005922 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005923 if (flags == NULL)
5924 return 0; /* type error; errmsg already given */
5925 while (*flags != NUL)
5926 {
5927 switch (*flags)
5928 {
5929 case 'b': dir = BACKWARD; break;
5930 case 'w': p_ws = TRUE; break;
5931 case 'W': p_ws = FALSE; break;
5932 default: mask = 0;
5933 if (flagsp != NULL)
5934 switch (*flags)
5935 {
5936 case 'c': mask = SP_START; break;
5937 case 'e': mask = SP_END; break;
5938 case 'm': mask = SP_RETCOUNT; break;
5939 case 'n': mask = SP_NOMOVE; break;
5940 case 'p': mask = SP_SUBPAT; break;
5941 case 'r': mask = SP_REPEAT; break;
5942 case 's': mask = SP_SETPCMARK; break;
5943 case 'z': mask = SP_COLUMN; break;
5944 }
5945 if (mask == 0)
5946 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005947 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005948 dir = 0;
5949 }
5950 else
5951 *flagsp |= mask;
5952 }
5953 if (dir == 0)
5954 break;
5955 ++flags;
5956 }
5957 }
5958 return dir;
5959}
5960
5961/*
5962 * Shared by search() and searchpos() functions.
5963 */
5964 static int
5965search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5966{
5967 int flags;
5968 char_u *pat;
5969 pos_T pos;
5970 pos_T save_cursor;
5971 int save_p_ws = p_ws;
5972 int dir;
5973 int retval = 0; /* default: FAIL */
5974 long lnum_stop = 0;
5975 proftime_T tm;
5976#ifdef FEAT_RELTIME
5977 long time_limit = 0;
5978#endif
5979 int options = SEARCH_KEEP;
5980 int subpatnum;
5981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005982 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005983 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5984 if (dir == 0)
5985 goto theend;
5986 flags = *flagsp;
5987 if (flags & SP_START)
5988 options |= SEARCH_START;
5989 if (flags & SP_END)
5990 options |= SEARCH_END;
5991 if (flags & SP_COLUMN)
5992 options |= SEARCH_COL;
5993
5994 /* Optional arguments: line number to stop searching and timeout. */
5995 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5996 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005997 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005998 if (lnum_stop < 0)
5999 goto theend;
6000#ifdef FEAT_RELTIME
6001 if (argvars[3].v_type != VAR_UNKNOWN)
6002 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006003 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006004 if (time_limit < 0)
6005 goto theend;
6006 }
6007#endif
6008 }
6009
6010#ifdef FEAT_RELTIME
6011 /* Set the time limit, if there is one. */
6012 profile_setlimit(time_limit, &tm);
6013#endif
6014
6015 /*
6016 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6017 * Check to make sure only those flags are set.
6018 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6019 * flags cannot be set. Check for that condition also.
6020 */
6021 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6022 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6023 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006024 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006025 goto theend;
6026 }
6027
6028 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006029 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006030 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006031 if (subpatnum != FAIL)
6032 {
6033 if (flags & SP_SUBPAT)
6034 retval = subpatnum;
6035 else
6036 retval = pos.lnum;
6037 if (flags & SP_SETPCMARK)
6038 setpcmark();
6039 curwin->w_cursor = pos;
6040 if (match_pos != NULL)
6041 {
6042 /* Store the match cursor position */
6043 match_pos->lnum = pos.lnum;
6044 match_pos->col = pos.col + 1;
6045 }
6046 /* "/$" will put the cursor after the end of the line, may need to
6047 * correct that here */
6048 check_cursor();
6049 }
6050
6051 /* If 'n' flag is used: restore cursor position. */
6052 if (flags & SP_NOMOVE)
6053 curwin->w_cursor = save_cursor;
6054 else
6055 curwin->w_set_curswant = TRUE;
6056theend:
6057 p_ws = save_p_ws;
6058
6059 return retval;
6060}
6061
6062#ifdef FEAT_FLOAT
6063
6064/*
6065 * round() is not in C90, use ceil() or floor() instead.
6066 */
6067 float_T
6068vim_round(float_T f)
6069{
6070 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6071}
6072
6073/*
6074 * "round({float})" function
6075 */
6076 static void
6077f_round(typval_T *argvars, typval_T *rettv)
6078{
6079 float_T f = 0.0;
6080
6081 rettv->v_type = VAR_FLOAT;
6082 if (get_float_arg(argvars, &f) == OK)
6083 rettv->vval.v_float = vim_round(f);
6084 else
6085 rettv->vval.v_float = 0.0;
6086}
6087#endif
6088
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006089#ifdef FEAT_RUBY
6090/*
6091 * "rubyeval()" function
6092 */
6093 static void
6094f_rubyeval(typval_T *argvars, typval_T *rettv)
6095{
6096 char_u *str;
6097 char_u buf[NUMBUFLEN];
6098
6099 str = tv_get_string_buf(&argvars[0], buf);
6100 do_rubyeval(str, rettv);
6101}
6102#endif
6103
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006104/*
6105 * "screenattr()" function
6106 */
6107 static void
6108f_screenattr(typval_T *argvars, typval_T *rettv)
6109{
6110 int row;
6111 int col;
6112 int c;
6113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006114 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6115 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006116 if (row < 0 || row >= screen_Rows
6117 || col < 0 || col >= screen_Columns)
6118 c = -1;
6119 else
6120 c = ScreenAttrs[LineOffset[row] + col];
6121 rettv->vval.v_number = c;
6122}
6123
6124/*
6125 * "screenchar()" function
6126 */
6127 static void
6128f_screenchar(typval_T *argvars, typval_T *rettv)
6129{
6130 int row;
6131 int col;
6132 int off;
6133 int c;
6134
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006135 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6136 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006137 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006138 c = -1;
6139 else
6140 {
6141 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006142 if (enc_utf8 && ScreenLinesUC[off] != 0)
6143 c = ScreenLinesUC[off];
6144 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006145 c = ScreenLines[off];
6146 }
6147 rettv->vval.v_number = c;
6148}
6149
6150/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006151 * "screenchars()" function
6152 */
6153 static void
6154f_screenchars(typval_T *argvars, typval_T *rettv)
6155{
6156 int row;
6157 int col;
6158 int off;
6159 int c;
6160 int i;
6161
6162 if (rettv_list_alloc(rettv) == FAIL)
6163 return;
6164 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6165 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6166 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6167 return;
6168
6169 off = LineOffset[row] + col;
6170 if (enc_utf8 && ScreenLinesUC[off] != 0)
6171 c = ScreenLinesUC[off];
6172 else
6173 c = ScreenLines[off];
6174 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6175
6176 if (enc_utf8)
6177
6178 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6179 list_append_number(rettv->vval.v_list,
6180 (varnumber_T)ScreenLinesC[i][off]);
6181}
6182
6183/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006184 * "screencol()" function
6185 *
6186 * First column is 1 to be consistent with virtcol().
6187 */
6188 static void
6189f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6190{
6191 rettv->vval.v_number = screen_screencol() + 1;
6192}
6193
6194/*
6195 * "screenrow()" function
6196 */
6197 static void
6198f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6199{
6200 rettv->vval.v_number = screen_screenrow() + 1;
6201}
6202
6203/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006204 * "screenstring()" function
6205 */
6206 static void
6207f_screenstring(typval_T *argvars, typval_T *rettv)
6208{
6209 int row;
6210 int col;
6211 int off;
6212 int c;
6213 int i;
6214 char_u buf[MB_MAXBYTES + 1];
6215 int buflen = 0;
6216
6217 rettv->vval.v_string = NULL;
6218 rettv->v_type = VAR_STRING;
6219
6220 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6221 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6222 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6223 return;
6224
6225 off = LineOffset[row] + col;
6226 if (enc_utf8 && ScreenLinesUC[off] != 0)
6227 c = ScreenLinesUC[off];
6228 else
6229 c = ScreenLines[off];
6230 buflen += mb_char2bytes(c, buf);
6231
6232 if (enc_utf8)
6233 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6234 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6235
6236 buf[buflen] = NUL;
6237 rettv->vval.v_string = vim_strsave(buf);
6238}
6239
6240/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006241 * "search()" function
6242 */
6243 static void
6244f_search(typval_T *argvars, typval_T *rettv)
6245{
6246 int flags = 0;
6247
6248 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6249}
6250
6251/*
6252 * "searchdecl()" function
6253 */
6254 static void
6255f_searchdecl(typval_T *argvars, typval_T *rettv)
6256{
6257 int locally = 1;
6258 int thisblock = 0;
6259 int error = FALSE;
6260 char_u *name;
6261
6262 rettv->vval.v_number = 1; /* default: FAIL */
6263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006264 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006265 if (argvars[1].v_type != VAR_UNKNOWN)
6266 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006267 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006269 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 }
6271 if (!error && name != NULL)
6272 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6273 locally, thisblock, SEARCH_KEEP) == FAIL;
6274}
6275
6276/*
6277 * Used by searchpair() and searchpairpos()
6278 */
6279 static int
6280searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6281{
6282 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006283 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006284 int save_p_ws = p_ws;
6285 int dir;
6286 int flags = 0;
6287 char_u nbuf1[NUMBUFLEN];
6288 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006289 int retval = 0; /* default: FAIL */
6290 long lnum_stop = 0;
6291 long time_limit = 0;
6292
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006293 /* Get the three pattern arguments: start, middle, end. Will result in an
6294 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006295 spat = tv_get_string_chk(&argvars[0]);
6296 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6297 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006298 if (spat == NULL || mpat == NULL || epat == NULL)
6299 goto theend; /* type error */
6300
6301 /* Handle the optional fourth argument: flags */
6302 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6303 if (dir == 0)
6304 goto theend;
6305
6306 /* Don't accept SP_END or SP_SUBPAT.
6307 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6308 */
6309 if ((flags & (SP_END | SP_SUBPAT)) != 0
6310 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6311 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006312 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 goto theend;
6314 }
6315
6316 /* Using 'r' implies 'W', otherwise it doesn't work. */
6317 if (flags & SP_REPEAT)
6318 p_ws = FALSE;
6319
6320 /* Optional fifth argument: skip expression */
6321 if (argvars[3].v_type == VAR_UNKNOWN
6322 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006323 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006324 else
6325 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006326 skip = &argvars[4];
6327 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6328 && skip->v_type != VAR_STRING)
6329 {
6330 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006331 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006332 goto theend;
6333 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006334 if (argvars[5].v_type != VAR_UNKNOWN)
6335 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006336 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006338 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006339 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006340 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006341 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006342#ifdef FEAT_RELTIME
6343 if (argvars[6].v_type != VAR_UNKNOWN)
6344 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006345 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006346 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006347 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006348 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006349 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006350 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 }
6352#endif
6353 }
6354 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355
6356 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6357 match_pos, lnum_stop, time_limit);
6358
6359theend:
6360 p_ws = save_p_ws;
6361
6362 return retval;
6363}
6364
6365/*
6366 * "searchpair()" function
6367 */
6368 static void
6369f_searchpair(typval_T *argvars, typval_T *rettv)
6370{
6371 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6372}
6373
6374/*
6375 * "searchpairpos()" function
6376 */
6377 static void
6378f_searchpairpos(typval_T *argvars, typval_T *rettv)
6379{
6380 pos_T match_pos;
6381 int lnum = 0;
6382 int col = 0;
6383
6384 if (rettv_list_alloc(rettv) == FAIL)
6385 return;
6386
6387 if (searchpair_cmn(argvars, &match_pos) > 0)
6388 {
6389 lnum = match_pos.lnum;
6390 col = match_pos.col;
6391 }
6392
6393 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6394 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6395}
6396
6397/*
6398 * Search for a start/middle/end thing.
6399 * Used by searchpair(), see its documentation for the details.
6400 * Returns 0 or -1 for no match,
6401 */
6402 long
6403do_searchpair(
6404 char_u *spat, /* start pattern */
6405 char_u *mpat, /* middle pattern */
6406 char_u *epat, /* end pattern */
6407 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006408 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006409 int flags, /* SP_SETPCMARK and other SP_ values */
6410 pos_T *match_pos,
6411 linenr_T lnum_stop, /* stop at this line if not zero */
6412 long time_limit UNUSED) /* stop after this many msec */
6413{
6414 char_u *save_cpo;
6415 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6416 long retval = 0;
6417 pos_T pos;
6418 pos_T firstpos;
6419 pos_T foundpos;
6420 pos_T save_cursor;
6421 pos_T save_pos;
6422 int n;
6423 int r;
6424 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006425 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 int err;
6427 int options = SEARCH_KEEP;
6428 proftime_T tm;
6429
6430 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6431 save_cpo = p_cpo;
6432 p_cpo = empty_option;
6433
6434#ifdef FEAT_RELTIME
6435 /* Set the time limit, if there is one. */
6436 profile_setlimit(time_limit, &tm);
6437#endif
6438
6439 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6440 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006441 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6442 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443 if (pat2 == NULL || pat3 == NULL)
6444 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006445 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006446 if (*mpat == NUL)
6447 STRCPY(pat3, pat2);
6448 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006449 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006450 spat, epat, mpat);
6451 if (flags & SP_START)
6452 options |= SEARCH_START;
6453
Bram Moolenaar48570482017-10-30 21:48:41 +01006454 if (skip != NULL)
6455 {
6456 /* Empty string means to not use the skip expression. */
6457 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6458 use_skip = skip->vval.v_string != NULL
6459 && *skip->vval.v_string != NUL;
6460 }
6461
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 save_cursor = curwin->w_cursor;
6463 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006464 CLEAR_POS(&firstpos);
6465 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466 pat = pat3;
6467 for (;;)
6468 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006469 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006470 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006471 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472 /* didn't find it or found the first match again: FAIL */
6473 break;
6474
6475 if (firstpos.lnum == 0)
6476 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006477 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478 {
6479 /* Found the same position again. Can happen with a pattern that
6480 * has "\zs" at the end and searching backwards. Advance one
6481 * character and try again. */
6482 if (dir == BACKWARD)
6483 decl(&pos);
6484 else
6485 incl(&pos);
6486 }
6487 foundpos = pos;
6488
6489 /* clear the start flag to avoid getting stuck here */
6490 options &= ~SEARCH_START;
6491
6492 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006493 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006494 {
6495 save_pos = curwin->w_cursor;
6496 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006497 err = FALSE;
6498 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499 curwin->w_cursor = save_pos;
6500 if (err)
6501 {
6502 /* Evaluating {skip} caused an error, break here. */
6503 curwin->w_cursor = save_cursor;
6504 retval = -1;
6505 break;
6506 }
6507 if (r)
6508 continue;
6509 }
6510
6511 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6512 {
6513 /* Found end when searching backwards or start when searching
6514 * forward: nested pair. */
6515 ++nest;
6516 pat = pat2; /* nested, don't search for middle */
6517 }
6518 else
6519 {
6520 /* Found end when searching forward or start when searching
6521 * backward: end of (nested) pair; or found middle in outer pair. */
6522 if (--nest == 1)
6523 pat = pat3; /* outer level, search for middle */
6524 }
6525
6526 if (nest == 0)
6527 {
6528 /* Found the match: return matchcount or line number. */
6529 if (flags & SP_RETCOUNT)
6530 ++retval;
6531 else
6532 retval = pos.lnum;
6533 if (flags & SP_SETPCMARK)
6534 setpcmark();
6535 curwin->w_cursor = pos;
6536 if (!(flags & SP_REPEAT))
6537 break;
6538 nest = 1; /* search for next unmatched */
6539 }
6540 }
6541
6542 if (match_pos != NULL)
6543 {
6544 /* Store the match cursor position */
6545 match_pos->lnum = curwin->w_cursor.lnum;
6546 match_pos->col = curwin->w_cursor.col + 1;
6547 }
6548
6549 /* If 'n' flag is used or search failed: restore cursor position. */
6550 if ((flags & SP_NOMOVE) || retval == 0)
6551 curwin->w_cursor = save_cursor;
6552
6553theend:
6554 vim_free(pat2);
6555 vim_free(pat3);
6556 if (p_cpo == empty_option)
6557 p_cpo = save_cpo;
6558 else
6559 /* Darn, evaluating the {skip} expression changed the value. */
6560 free_string_option(save_cpo);
6561
6562 return retval;
6563}
6564
6565/*
6566 * "searchpos()" function
6567 */
6568 static void
6569f_searchpos(typval_T *argvars, typval_T *rettv)
6570{
6571 pos_T match_pos;
6572 int lnum = 0;
6573 int col = 0;
6574 int n;
6575 int flags = 0;
6576
6577 if (rettv_list_alloc(rettv) == FAIL)
6578 return;
6579
6580 n = search_cmn(argvars, &match_pos, &flags);
6581 if (n > 0)
6582 {
6583 lnum = match_pos.lnum;
6584 col = match_pos.col;
6585 }
6586
6587 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6588 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6589 if (flags & SP_SUBPAT)
6590 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6591}
6592
6593 static void
6594f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6595{
6596#ifdef FEAT_CLIENTSERVER
6597 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006598 char_u *server = tv_get_string_chk(&argvars[0]);
6599 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600
6601 rettv->vval.v_number = -1;
6602 if (server == NULL || reply == NULL)
6603 return;
6604 if (check_restricted() || check_secure())
6605 return;
6606# ifdef FEAT_X11
6607 if (check_connection() == FAIL)
6608 return;
6609# endif
6610
6611 if (serverSendReply(server, reply) < 0)
6612 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006613 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006614 return;
6615 }
6616 rettv->vval.v_number = 0;
6617#else
6618 rettv->vval.v_number = -1;
6619#endif
6620}
6621
6622 static void
6623f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6624{
6625 char_u *r = NULL;
6626
6627#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006628# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006629 r = serverGetVimNames();
6630# else
6631 make_connection();
6632 if (X_DISPLAY != NULL)
6633 r = serverGetVimNames(X_DISPLAY);
6634# endif
6635#endif
6636 rettv->v_type = VAR_STRING;
6637 rettv->vval.v_string = r;
6638}
6639
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640 static void
6641f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6642{
6643 dict_T *d;
6644 dictitem_T *di;
6645 char_u *csearch;
6646
6647 if (argvars[0].v_type != VAR_DICT)
6648 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006649 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650 return;
6651 }
6652
6653 if ((d = argvars[0].vval.v_dict) != NULL)
6654 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006655 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006656 if (csearch != NULL)
6657 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006658 if (enc_utf8)
6659 {
6660 int pcc[MAX_MCO];
6661 int c = utfc_ptr2char(csearch, pcc);
6662
6663 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6664 }
6665 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006666 set_last_csearch(PTR2CHAR(csearch),
6667 csearch, MB_PTR2LEN(csearch));
6668 }
6669
6670 di = dict_find(d, (char_u *)"forward", -1);
6671 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006672 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006673 ? FORWARD : BACKWARD);
6674
6675 di = dict_find(d, (char_u *)"until", -1);
6676 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006677 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006678 }
6679}
6680
6681/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006682 * "setenv()" function
6683 */
6684 static void
6685f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6686{
6687 char_u namebuf[NUMBUFLEN];
6688 char_u valbuf[NUMBUFLEN];
6689 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6690
6691 if (argvars[1].v_type == VAR_SPECIAL
6692 && argvars[1].vval.v_number == VVAL_NULL)
6693 vim_unsetenv(name);
6694 else
6695 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6696}
6697
6698/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699 * "setfperm({fname}, {mode})" function
6700 */
6701 static void
6702f_setfperm(typval_T *argvars, typval_T *rettv)
6703{
6704 char_u *fname;
6705 char_u modebuf[NUMBUFLEN];
6706 char_u *mode_str;
6707 int i;
6708 int mask;
6709 int mode = 0;
6710
6711 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006712 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006713 if (fname == NULL)
6714 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006715 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006716 if (mode_str == NULL)
6717 return;
6718 if (STRLEN(mode_str) != 9)
6719 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006720 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006721 return;
6722 }
6723
6724 mask = 1;
6725 for (i = 8; i >= 0; --i)
6726 {
6727 if (mode_str[i] != '-')
6728 mode |= mask;
6729 mask = mask << 1;
6730 }
6731 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6732}
6733
6734/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006735 * "setpos()" function
6736 */
6737 static void
6738f_setpos(typval_T *argvars, typval_T *rettv)
6739{
6740 pos_T pos;
6741 int fnum;
6742 char_u *name;
6743 colnr_T curswant = -1;
6744
6745 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006746 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006747 if (name != NULL)
6748 {
6749 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6750 {
6751 if (--pos.col < 0)
6752 pos.col = 0;
6753 if (name[0] == '.' && name[1] == NUL)
6754 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006755 /* set cursor; "fnum" is ignored */
6756 curwin->w_cursor = pos;
6757 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006759 curwin->w_curswant = curswant - 1;
6760 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006761 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006762 check_cursor();
6763 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006764 }
6765 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6766 {
6767 /* set mark */
6768 if (setmark_pos(name[1], &pos, fnum) == OK)
6769 rettv->vval.v_number = 0;
6770 }
6771 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006772 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 }
6774 }
6775}
6776
6777/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006778 * "setreg()" function
6779 */
6780 static void
6781f_setreg(typval_T *argvars, typval_T *rettv)
6782{
6783 int regname;
6784 char_u *strregname;
6785 char_u *stropt;
6786 char_u *strval;
6787 int append;
6788 char_u yank_type;
6789 long block_len;
6790
6791 block_len = -1;
6792 yank_type = MAUTO;
6793 append = FALSE;
6794
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006795 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 rettv->vval.v_number = 1; /* FAIL is default */
6797
6798 if (strregname == NULL)
6799 return; /* type error; errmsg already given */
6800 regname = *strregname;
6801 if (regname == 0 || regname == '@')
6802 regname = '"';
6803
6804 if (argvars[2].v_type != VAR_UNKNOWN)
6805 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006806 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006807 if (stropt == NULL)
6808 return; /* type error */
6809 for (; *stropt != NUL; ++stropt)
6810 switch (*stropt)
6811 {
6812 case 'a': case 'A': /* append */
6813 append = TRUE;
6814 break;
6815 case 'v': case 'c': /* character-wise selection */
6816 yank_type = MCHAR;
6817 break;
6818 case 'V': case 'l': /* line-wise selection */
6819 yank_type = MLINE;
6820 break;
6821 case 'b': case Ctrl_V: /* block-wise selection */
6822 yank_type = MBLOCK;
6823 if (VIM_ISDIGIT(stropt[1]))
6824 {
6825 ++stropt;
6826 block_len = getdigits(&stropt) - 1;
6827 --stropt;
6828 }
6829 break;
6830 }
6831 }
6832
6833 if (argvars[1].v_type == VAR_LIST)
6834 {
6835 char_u **lstval;
6836 char_u **allocval;
6837 char_u buf[NUMBUFLEN];
6838 char_u **curval;
6839 char_u **curallocval;
6840 list_T *ll = argvars[1].vval.v_list;
6841 listitem_T *li;
6842 int len;
6843
6844 /* If the list is NULL handle like an empty list. */
6845 len = ll == NULL ? 0 : ll->lv_len;
6846
6847 /* First half: use for pointers to result lines; second half: use for
6848 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006849 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850 if (lstval == NULL)
6851 return;
6852 curval = lstval;
6853 allocval = lstval + len + 2;
6854 curallocval = allocval;
6855
6856 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6857 li = li->li_next)
6858 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006859 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006860 if (strval == NULL)
6861 goto free_lstval;
6862 if (strval == buf)
6863 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006864 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865 * overwrite the string. */
6866 strval = vim_strsave(buf);
6867 if (strval == NULL)
6868 goto free_lstval;
6869 *curallocval++ = strval;
6870 }
6871 *curval++ = strval;
6872 }
6873 *curval++ = NULL;
6874
6875 write_reg_contents_lst(regname, lstval, -1,
6876 append, yank_type, block_len);
6877free_lstval:
6878 while (curallocval > allocval)
6879 vim_free(*--curallocval);
6880 vim_free(lstval);
6881 }
6882 else
6883 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006884 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006885 if (strval == NULL)
6886 return;
6887 write_reg_contents_ex(regname, strval, -1,
6888 append, yank_type, block_len);
6889 }
6890 rettv->vval.v_number = 0;
6891}
6892
6893/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006894 * "settagstack()" function
6895 */
6896 static void
6897f_settagstack(typval_T *argvars, typval_T *rettv)
6898{
6899 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6900 win_T *wp;
6901 dict_T *d;
6902 int action = 'r';
6903
6904 rettv->vval.v_number = -1;
6905
6906 // first argument: window number or id
6907 wp = find_win_by_nr_or_id(&argvars[0]);
6908 if (wp == NULL)
6909 return;
6910
6911 // second argument: dict with items to set in the tag stack
6912 if (argvars[1].v_type != VAR_DICT)
6913 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006914 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006915 return;
6916 }
6917 d = argvars[1].vval.v_dict;
6918 if (d == NULL)
6919 return;
6920
6921 // third argument: action - 'a' for append and 'r' for replace.
6922 // default is to replace the stack.
6923 if (argvars[2].v_type == VAR_UNKNOWN)
6924 action = 'r';
6925 else if (argvars[2].v_type == VAR_STRING)
6926 {
6927 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006928 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006929 if (actstr == NULL)
6930 return;
6931 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6932 action = *actstr;
6933 else
6934 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006935 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006936 return;
6937 }
6938 }
6939 else
6940 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006941 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006942 return;
6943 }
6944
6945 if (set_tagstack(wp, d, action) == OK)
6946 rettv->vval.v_number = 0;
6947}
6948
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006949#ifdef FEAT_CRYPT
6950/*
6951 * "sha256({string})" function
6952 */
6953 static void
6954f_sha256(typval_T *argvars, typval_T *rettv)
6955{
6956 char_u *p;
6957
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006958 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959 rettv->vval.v_string = vim_strsave(
6960 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6961 rettv->v_type = VAR_STRING;
6962}
6963#endif /* FEAT_CRYPT */
6964
6965/*
6966 * "shellescape({string})" function
6967 */
6968 static void
6969f_shellescape(typval_T *argvars, typval_T *rettv)
6970{
Bram Moolenaar20615522017-06-05 18:46:26 +02006971 int do_special = non_zero_arg(&argvars[1]);
6972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006973 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006974 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 rettv->v_type = VAR_STRING;
6976}
6977
6978/*
6979 * shiftwidth() function
6980 */
6981 static void
6982f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6983{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006984 rettv->vval.v_number = 0;
6985
6986 if (argvars[0].v_type != VAR_UNKNOWN)
6987 {
6988 long col;
6989
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006990 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006991 if (col < 0)
6992 return; // type error; errmsg already given
6993#ifdef FEAT_VARTABS
6994 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6995 return;
6996#endif
6997 }
6998
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006999 rettv->vval.v_number = get_sw_value(curbuf);
7000}
7001
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007002#ifdef FEAT_FLOAT
7003/*
7004 * "sin()" function
7005 */
7006 static void
7007f_sin(typval_T *argvars, typval_T *rettv)
7008{
7009 float_T f = 0.0;
7010
7011 rettv->v_type = VAR_FLOAT;
7012 if (get_float_arg(argvars, &f) == OK)
7013 rettv->vval.v_float = sin(f);
7014 else
7015 rettv->vval.v_float = 0.0;
7016}
7017
7018/*
7019 * "sinh()" function
7020 */
7021 static void
7022f_sinh(typval_T *argvars, typval_T *rettv)
7023{
7024 float_T f = 0.0;
7025
7026 rettv->v_type = VAR_FLOAT;
7027 if (get_float_arg(argvars, &f) == OK)
7028 rettv->vval.v_float = sinh(f);
7029 else
7030 rettv->vval.v_float = 0.0;
7031}
7032#endif
7033
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034/*
7035 * "soundfold({word})" function
7036 */
7037 static void
7038f_soundfold(typval_T *argvars, typval_T *rettv)
7039{
7040 char_u *s;
7041
7042 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007043 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007044#ifdef FEAT_SPELL
7045 rettv->vval.v_string = eval_soundfold(s);
7046#else
7047 rettv->vval.v_string = vim_strsave(s);
7048#endif
7049}
7050
7051/*
7052 * "spellbadword()" function
7053 */
7054 static void
7055f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7056{
7057 char_u *word = (char_u *)"";
7058 hlf_T attr = HLF_COUNT;
7059 int len = 0;
7060
7061 if (rettv_list_alloc(rettv) == FAIL)
7062 return;
7063
7064#ifdef FEAT_SPELL
7065 if (argvars[0].v_type == VAR_UNKNOWN)
7066 {
7067 /* Find the start and length of the badly spelled word. */
7068 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7069 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007070 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007072 curwin->w_set_curswant = TRUE;
7073 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074 }
7075 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7076 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007077 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078 int capcol = -1;
7079
7080 if (str != NULL)
7081 {
7082 /* Check the argument for spelling. */
7083 while (*str != NUL)
7084 {
7085 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7086 if (attr != HLF_COUNT)
7087 {
7088 word = str;
7089 break;
7090 }
7091 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007092 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007093 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007094 }
7095 }
7096 }
7097#endif
7098
7099 list_append_string(rettv->vval.v_list, word, len);
7100 list_append_string(rettv->vval.v_list, (char_u *)(
7101 attr == HLF_SPB ? "bad" :
7102 attr == HLF_SPR ? "rare" :
7103 attr == HLF_SPL ? "local" :
7104 attr == HLF_SPC ? "caps" :
7105 ""), -1);
7106}
7107
7108/*
7109 * "spellsuggest()" function
7110 */
7111 static void
7112f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7113{
7114#ifdef FEAT_SPELL
7115 char_u *str;
7116 int typeerr = FALSE;
7117 int maxcount;
7118 garray_T ga;
7119 int i;
7120 listitem_T *li;
7121 int need_capital = FALSE;
7122#endif
7123
7124 if (rettv_list_alloc(rettv) == FAIL)
7125 return;
7126
7127#ifdef FEAT_SPELL
7128 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7129 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007130 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 if (argvars[1].v_type != VAR_UNKNOWN)
7132 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007133 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007134 if (maxcount <= 0)
7135 return;
7136 if (argvars[2].v_type != VAR_UNKNOWN)
7137 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007138 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007139 if (typeerr)
7140 return;
7141 }
7142 }
7143 else
7144 maxcount = 25;
7145
7146 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7147
7148 for (i = 0; i < ga.ga_len; ++i)
7149 {
7150 str = ((char_u **)ga.ga_data)[i];
7151
7152 li = listitem_alloc();
7153 if (li == NULL)
7154 vim_free(str);
7155 else
7156 {
7157 li->li_tv.v_type = VAR_STRING;
7158 li->li_tv.v_lock = 0;
7159 li->li_tv.vval.v_string = str;
7160 list_append(rettv->vval.v_list, li);
7161 }
7162 }
7163 ga_clear(&ga);
7164 }
7165#endif
7166}
7167
7168 static void
7169f_split(typval_T *argvars, typval_T *rettv)
7170{
7171 char_u *str;
7172 char_u *end;
7173 char_u *pat = NULL;
7174 regmatch_T regmatch;
7175 char_u patbuf[NUMBUFLEN];
7176 char_u *save_cpo;
7177 int match;
7178 colnr_T col = 0;
7179 int keepempty = FALSE;
7180 int typeerr = FALSE;
7181
7182 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7183 save_cpo = p_cpo;
7184 p_cpo = (char_u *)"";
7185
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007186 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187 if (argvars[1].v_type != VAR_UNKNOWN)
7188 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007189 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007190 if (pat == NULL)
7191 typeerr = TRUE;
7192 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007193 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007194 }
7195 if (pat == NULL || *pat == NUL)
7196 pat = (char_u *)"[\\x01- ]\\+";
7197
7198 if (rettv_list_alloc(rettv) == FAIL)
7199 return;
7200 if (typeerr)
7201 return;
7202
7203 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7204 if (regmatch.regprog != NULL)
7205 {
7206 regmatch.rm_ic = FALSE;
7207 while (*str != NUL || keepempty)
7208 {
7209 if (*str == NUL)
7210 match = FALSE; /* empty item at the end */
7211 else
7212 match = vim_regexec_nl(&regmatch, str, col);
7213 if (match)
7214 end = regmatch.startp[0];
7215 else
7216 end = str + STRLEN(str);
7217 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7218 && *str != NUL && match && end < regmatch.endp[0]))
7219 {
7220 if (list_append_string(rettv->vval.v_list, str,
7221 (int)(end - str)) == FAIL)
7222 break;
7223 }
7224 if (!match)
7225 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007226 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007227 if (regmatch.endp[0] > str)
7228 col = 0;
7229 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007230 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007231 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007232 str = regmatch.endp[0];
7233 }
7234
7235 vim_regfree(regmatch.regprog);
7236 }
7237
7238 p_cpo = save_cpo;
7239}
7240
7241#ifdef FEAT_FLOAT
7242/*
7243 * "sqrt()" function
7244 */
7245 static void
7246f_sqrt(typval_T *argvars, typval_T *rettv)
7247{
7248 float_T f = 0.0;
7249
7250 rettv->v_type = VAR_FLOAT;
7251 if (get_float_arg(argvars, &f) == OK)
7252 rettv->vval.v_float = sqrt(f);
7253 else
7254 rettv->vval.v_float = 0.0;
7255}
7256
7257/*
7258 * "str2float()" function
7259 */
7260 static void
7261f_str2float(typval_T *argvars, typval_T *rettv)
7262{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007263 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007264 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007265
Bram Moolenaar08243d22017-01-10 16:12:29 +01007266 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 p = skipwhite(p + 1);
7268 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007269 if (isneg)
7270 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007271 rettv->v_type = VAR_FLOAT;
7272}
7273#endif
7274
7275/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007276 * "str2list()" function
7277 */
7278 static void
7279f_str2list(typval_T *argvars, typval_T *rettv)
7280{
7281 char_u *p;
7282 int utf8 = FALSE;
7283
7284 if (rettv_list_alloc(rettv) == FAIL)
7285 return;
7286
7287 if (argvars[1].v_type != VAR_UNKNOWN)
7288 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7289
7290 p = tv_get_string(&argvars[0]);
7291
7292 if (has_mbyte || utf8)
7293 {
7294 int (*ptr2len)(char_u *);
7295 int (*ptr2char)(char_u *);
7296
7297 if (utf8 || enc_utf8)
7298 {
7299 ptr2len = utf_ptr2len;
7300 ptr2char = utf_ptr2char;
7301 }
7302 else
7303 {
7304 ptr2len = mb_ptr2len;
7305 ptr2char = mb_ptr2char;
7306 }
7307
7308 for ( ; *p != NUL; p += (*ptr2len)(p))
7309 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7310 }
7311 else
7312 for ( ; *p != NUL; ++p)
7313 list_append_number(rettv->vval.v_list, *p);
7314}
7315
7316/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007317 * "str2nr()" function
7318 */
7319 static void
7320f_str2nr(typval_T *argvars, typval_T *rettv)
7321{
7322 int base = 10;
7323 char_u *p;
7324 varnumber_T n;
7325 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007326 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007327
7328 if (argvars[1].v_type != VAR_UNKNOWN)
7329 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007330 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007331 if (base != 2 && base != 8 && base != 10 && base != 16)
7332 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007333 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007334 return;
7335 }
7336 }
7337
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007338 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007339 isneg = (*p == '-');
7340 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007341 p = skipwhite(p + 1);
7342 switch (base)
7343 {
7344 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
7345 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
7346 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
7347 default: what = 0;
7348 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007349 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7350 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007351 if (isneg)
7352 rettv->vval.v_number = -n;
7353 else
7354 rettv->vval.v_number = n;
7355
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356}
7357
7358#ifdef HAVE_STRFTIME
7359/*
7360 * "strftime({format}[, {time}])" function
7361 */
7362 static void
7363f_strftime(typval_T *argvars, typval_T *rettv)
7364{
7365 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007366 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007367 struct tm *curtime;
7368 time_t seconds;
7369 char_u *p;
7370
7371 rettv->v_type = VAR_STRING;
7372
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007373 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 if (argvars[1].v_type == VAR_UNKNOWN)
7375 seconds = time(NULL);
7376 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007378 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007379 /* MSVC returns NULL for an invalid value of seconds. */
7380 if (curtime == NULL)
7381 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7382 else
7383 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384 vimconv_T conv;
7385 char_u *enc;
7386
7387 conv.vc_type = CONV_NONE;
7388 enc = enc_locale();
7389 convert_setup(&conv, p_enc, enc);
7390 if (conv.vc_type != CONV_NONE)
7391 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 if (p != NULL)
7393 (void)strftime((char *)result_buf, sizeof(result_buf),
7394 (char *)p, curtime);
7395 else
7396 result_buf[0] = NUL;
7397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398 if (conv.vc_type != CONV_NONE)
7399 vim_free(p);
7400 convert_setup(&conv, enc, p_enc);
7401 if (conv.vc_type != CONV_NONE)
7402 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7403 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007404 rettv->vval.v_string = vim_strsave(result_buf);
7405
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007406 /* Release conversion descriptors */
7407 convert_setup(&conv, NULL, NULL);
7408 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409 }
7410}
7411#endif
7412
7413/*
7414 * "strgetchar()" function
7415 */
7416 static void
7417f_strgetchar(typval_T *argvars, typval_T *rettv)
7418{
7419 char_u *str;
7420 int len;
7421 int error = FALSE;
7422 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007423 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424
7425 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007426 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427 if (str == NULL)
7428 return;
7429 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007430 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431 if (error)
7432 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433
Bram Moolenaar13505972019-01-24 15:04:48 +01007434 while (charidx >= 0 && byteidx < len)
7435 {
7436 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007437 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007438 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7439 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007441 --charidx;
7442 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007443 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007444}
7445
7446/*
7447 * "stridx()" function
7448 */
7449 static void
7450f_stridx(typval_T *argvars, typval_T *rettv)
7451{
7452 char_u buf[NUMBUFLEN];
7453 char_u *needle;
7454 char_u *haystack;
7455 char_u *save_haystack;
7456 char_u *pos;
7457 int start_idx;
7458
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007459 needle = tv_get_string_chk(&argvars[1]);
7460 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007461 rettv->vval.v_number = -1;
7462 if (needle == NULL || haystack == NULL)
7463 return; /* type error; errmsg already given */
7464
7465 if (argvars[2].v_type != VAR_UNKNOWN)
7466 {
7467 int error = FALSE;
7468
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007469 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470 if (error || start_idx >= (int)STRLEN(haystack))
7471 return;
7472 if (start_idx >= 0)
7473 haystack += start_idx;
7474 }
7475
7476 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7477 if (pos != NULL)
7478 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7479}
7480
7481/*
7482 * "string()" function
7483 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007484 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007485f_string(typval_T *argvars, typval_T *rettv)
7486{
7487 char_u *tofree;
7488 char_u numbuf[NUMBUFLEN];
7489
7490 rettv->v_type = VAR_STRING;
7491 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7492 get_copyID());
7493 /* Make a copy if we have a value but it's not in allocated memory. */
7494 if (rettv->vval.v_string != NULL && tofree == NULL)
7495 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7496}
7497
7498/*
7499 * "strlen()" function
7500 */
7501 static void
7502f_strlen(typval_T *argvars, typval_T *rettv)
7503{
7504 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007505 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506}
7507
7508/*
7509 * "strchars()" function
7510 */
7511 static void
7512f_strchars(typval_T *argvars, typval_T *rettv)
7513{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007514 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516 varnumber_T len = 0;
7517 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518
7519 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007520 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007522 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007523 else
7524 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7526 while (*s != NUL)
7527 {
7528 func_mb_ptr2char_adv(&s);
7529 ++len;
7530 }
7531 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 }
7533}
7534
7535/*
7536 * "strdisplaywidth()" function
7537 */
7538 static void
7539f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7540{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007541 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007542 int col = 0;
7543
7544 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007545 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546
7547 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7548}
7549
7550/*
7551 * "strwidth()" function
7552 */
7553 static void
7554f_strwidth(typval_T *argvars, typval_T *rettv)
7555{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007556 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007557
Bram Moolenaar13505972019-01-24 15:04:48 +01007558 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007559}
7560
7561/*
7562 * "strcharpart()" function
7563 */
7564 static void
7565f_strcharpart(typval_T *argvars, typval_T *rettv)
7566{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567 char_u *p;
7568 int nchar;
7569 int nbyte = 0;
7570 int charlen;
7571 int len = 0;
7572 int slen;
7573 int error = FALSE;
7574
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007575 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007576 slen = (int)STRLEN(p);
7577
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007578 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007579 if (!error)
7580 {
7581 if (nchar > 0)
7582 while (nchar > 0 && nbyte < slen)
7583 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007584 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585 --nchar;
7586 }
7587 else
7588 nbyte = nchar;
7589 if (argvars[2].v_type != VAR_UNKNOWN)
7590 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007591 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007592 while (charlen > 0 && nbyte + len < slen)
7593 {
7594 int off = nbyte + len;
7595
7596 if (off < 0)
7597 len += 1;
7598 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007599 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600 --charlen;
7601 }
7602 }
7603 else
7604 len = slen - nbyte; /* default: all bytes that are available. */
7605 }
7606
7607 /*
7608 * Only return the overlap between the specified part and the actual
7609 * string.
7610 */
7611 if (nbyte < 0)
7612 {
7613 len += nbyte;
7614 nbyte = 0;
7615 }
7616 else if (nbyte > slen)
7617 nbyte = slen;
7618 if (len < 0)
7619 len = 0;
7620 else if (nbyte + len > slen)
7621 len = slen - nbyte;
7622
7623 rettv->v_type = VAR_STRING;
7624 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007625}
7626
7627/*
7628 * "strpart()" function
7629 */
7630 static void
7631f_strpart(typval_T *argvars, typval_T *rettv)
7632{
7633 char_u *p;
7634 int n;
7635 int len;
7636 int slen;
7637 int error = FALSE;
7638
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007639 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007640 slen = (int)STRLEN(p);
7641
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007642 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007643 if (error)
7644 len = 0;
7645 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007646 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 else
7648 len = slen - n; /* default len: all bytes that are available. */
7649
7650 /*
7651 * Only return the overlap between the specified part and the actual
7652 * string.
7653 */
7654 if (n < 0)
7655 {
7656 len += n;
7657 n = 0;
7658 }
7659 else if (n > slen)
7660 n = slen;
7661 if (len < 0)
7662 len = 0;
7663 else if (n + len > slen)
7664 len = slen - n;
7665
7666 rettv->v_type = VAR_STRING;
7667 rettv->vval.v_string = vim_strnsave(p + n, len);
7668}
7669
7670/*
7671 * "strridx()" function
7672 */
7673 static void
7674f_strridx(typval_T *argvars, typval_T *rettv)
7675{
7676 char_u buf[NUMBUFLEN];
7677 char_u *needle;
7678 char_u *haystack;
7679 char_u *rest;
7680 char_u *lastmatch = NULL;
7681 int haystack_len, end_idx;
7682
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007683 needle = tv_get_string_chk(&argvars[1]);
7684 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007685
7686 rettv->vval.v_number = -1;
7687 if (needle == NULL || haystack == NULL)
7688 return; /* type error; errmsg already given */
7689
7690 haystack_len = (int)STRLEN(haystack);
7691 if (argvars[2].v_type != VAR_UNKNOWN)
7692 {
7693 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007694 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007695 if (end_idx < 0)
7696 return; /* can never find a match */
7697 }
7698 else
7699 end_idx = haystack_len;
7700
7701 if (*needle == NUL)
7702 {
7703 /* Empty string matches past the end. */
7704 lastmatch = haystack + end_idx;
7705 }
7706 else
7707 {
7708 for (rest = haystack; *rest != '\0'; ++rest)
7709 {
7710 rest = (char_u *)strstr((char *)rest, (char *)needle);
7711 if (rest == NULL || rest > haystack + end_idx)
7712 break;
7713 lastmatch = rest;
7714 }
7715 }
7716
7717 if (lastmatch == NULL)
7718 rettv->vval.v_number = -1;
7719 else
7720 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7721}
7722
7723/*
7724 * "strtrans()" function
7725 */
7726 static void
7727f_strtrans(typval_T *argvars, typval_T *rettv)
7728{
7729 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007730 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007731}
7732
7733/*
7734 * "submatch()" function
7735 */
7736 static void
7737f_submatch(typval_T *argvars, typval_T *rettv)
7738{
7739 int error = FALSE;
7740 int no;
7741 int retList = 0;
7742
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007743 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 if (error)
7745 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007746 if (no < 0 || no >= NSUBEXP)
7747 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007748 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007749 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007750 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007751 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007752 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007753 if (error)
7754 return;
7755
7756 if (retList == 0)
7757 {
7758 rettv->v_type = VAR_STRING;
7759 rettv->vval.v_string = reg_submatch(no);
7760 }
7761 else
7762 {
7763 rettv->v_type = VAR_LIST;
7764 rettv->vval.v_list = reg_submatch_list(no);
7765 }
7766}
7767
7768/*
7769 * "substitute()" function
7770 */
7771 static void
7772f_substitute(typval_T *argvars, typval_T *rettv)
7773{
7774 char_u patbuf[NUMBUFLEN];
7775 char_u subbuf[NUMBUFLEN];
7776 char_u flagsbuf[NUMBUFLEN];
7777
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007778 char_u *str = tv_get_string_chk(&argvars[0]);
7779 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007780 char_u *sub = NULL;
7781 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007782 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007783
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007784 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7785 expr = &argvars[2];
7786 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007787 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007788
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007789 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007790 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7791 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007792 rettv->vval.v_string = NULL;
7793 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007794 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795}
7796
7797/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007798 * "swapinfo(swap_filename)" function
7799 */
7800 static void
7801f_swapinfo(typval_T *argvars, typval_T *rettv)
7802{
7803 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007804 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007805}
7806
7807/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007808 * "swapname(expr)" function
7809 */
7810 static void
7811f_swapname(typval_T *argvars, typval_T *rettv)
7812{
7813 buf_T *buf;
7814
7815 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007816 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007817 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7818 || buf->b_ml.ml_mfp->mf_fname == NULL)
7819 rettv->vval.v_string = NULL;
7820 else
7821 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7822}
7823
7824/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825 * "synID(lnum, col, trans)" function
7826 */
7827 static void
7828f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7829{
7830 int id = 0;
7831#ifdef FEAT_SYN_HL
7832 linenr_T lnum;
7833 colnr_T col;
7834 int trans;
7835 int transerr = FALSE;
7836
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007837 lnum = tv_get_lnum(argvars); /* -1 on type error */
7838 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7839 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840
7841 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7842 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7843 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7844#endif
7845
7846 rettv->vval.v_number = id;
7847}
7848
7849/*
7850 * "synIDattr(id, what [, mode])" function
7851 */
7852 static void
7853f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7854{
7855 char_u *p = NULL;
7856#ifdef FEAT_SYN_HL
7857 int id;
7858 char_u *what;
7859 char_u *mode;
7860 char_u modebuf[NUMBUFLEN];
7861 int modec;
7862
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007863 id = (int)tv_get_number(&argvars[0]);
7864 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007865 if (argvars[2].v_type != VAR_UNKNOWN)
7866 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007867 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 modec = TOLOWER_ASC(mode[0]);
7869 if (modec != 't' && modec != 'c' && modec != 'g')
7870 modec = 0; /* replace invalid with current */
7871 }
7872 else
7873 {
7874#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7875 if (USE_24BIT)
7876 modec = 'g';
7877 else
7878#endif
7879 if (t_colors > 1)
7880 modec = 'c';
7881 else
7882 modec = 't';
7883 }
7884
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885 switch (TOLOWER_ASC(what[0]))
7886 {
7887 case 'b':
7888 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7889 p = highlight_color(id, what, modec);
7890 else /* bold */
7891 p = highlight_has_attr(id, HL_BOLD, modec);
7892 break;
7893
7894 case 'f': /* fg[#] or font */
7895 p = highlight_color(id, what, modec);
7896 break;
7897
7898 case 'i':
7899 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7900 p = highlight_has_attr(id, HL_INVERSE, modec);
7901 else /* italic */
7902 p = highlight_has_attr(id, HL_ITALIC, modec);
7903 break;
7904
7905 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007906 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007907 break;
7908
7909 case 'r': /* reverse */
7910 p = highlight_has_attr(id, HL_INVERSE, modec);
7911 break;
7912
7913 case 's':
7914 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7915 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007916 /* strikeout */
7917 else if (TOLOWER_ASC(what[1]) == 't' &&
7918 TOLOWER_ASC(what[2]) == 'r')
7919 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007920 else /* standout */
7921 p = highlight_has_attr(id, HL_STANDOUT, modec);
7922 break;
7923
7924 case 'u':
7925 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7926 /* underline */
7927 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7928 else
7929 /* undercurl */
7930 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7931 break;
7932 }
7933
7934 if (p != NULL)
7935 p = vim_strsave(p);
7936#endif
7937 rettv->v_type = VAR_STRING;
7938 rettv->vval.v_string = p;
7939}
7940
7941/*
7942 * "synIDtrans(id)" function
7943 */
7944 static void
7945f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7946{
7947 int id;
7948
7949#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007950 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951
7952 if (id > 0)
7953 id = syn_get_final_id(id);
7954 else
7955#endif
7956 id = 0;
7957
7958 rettv->vval.v_number = id;
7959}
7960
7961/*
7962 * "synconcealed(lnum, col)" function
7963 */
7964 static void
7965f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7966{
7967#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7968 linenr_T lnum;
7969 colnr_T col;
7970 int syntax_flags = 0;
7971 int cchar;
7972 int matchid = 0;
7973 char_u str[NUMBUFLEN];
7974#endif
7975
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007976 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007977
7978#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007979 lnum = tv_get_lnum(argvars); /* -1 on type error */
7980 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007981
7982 vim_memset(str, NUL, sizeof(str));
7983
7984 if (rettv_list_alloc(rettv) != FAIL)
7985 {
7986 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7987 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7988 && curwin->w_p_cole > 0)
7989 {
7990 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7991 syntax_flags = get_syntax_info(&matchid);
7992
7993 /* get the conceal character */
7994 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7995 {
7996 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007997 if (cchar == NUL && curwin->w_p_cole == 1)
7998 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007999 if (cchar != NUL)
8000 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008001 if (has_mbyte)
8002 (*mb_char2bytes)(cchar, str);
8003 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 str[0] = cchar;
8005 }
8006 }
8007 }
8008
8009 list_append_number(rettv->vval.v_list,
8010 (syntax_flags & HL_CONCEAL) != 0);
8011 /* -1 to auto-determine strlen */
8012 list_append_string(rettv->vval.v_list, str, -1);
8013 list_append_number(rettv->vval.v_list, matchid);
8014 }
8015#endif
8016}
8017
8018/*
8019 * "synstack(lnum, col)" function
8020 */
8021 static void
8022f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8023{
8024#ifdef FEAT_SYN_HL
8025 linenr_T lnum;
8026 colnr_T col;
8027 int i;
8028 int id;
8029#endif
8030
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008031 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008032
8033#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008034 lnum = tv_get_lnum(argvars); /* -1 on type error */
8035 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008036
8037 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8038 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8039 && rettv_list_alloc(rettv) != FAIL)
8040 {
8041 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8042 for (i = 0; ; ++i)
8043 {
8044 id = syn_get_stack_item(i);
8045 if (id < 0)
8046 break;
8047 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8048 break;
8049 }
8050 }
8051#endif
8052}
8053
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008054/*
8055 * "tabpagebuflist()" function
8056 */
8057 static void
8058f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8059{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008060 tabpage_T *tp;
8061 win_T *wp = NULL;
8062
8063 if (argvars[0].v_type == VAR_UNKNOWN)
8064 wp = firstwin;
8065 else
8066 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008067 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008068 if (tp != NULL)
8069 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8070 }
8071 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8072 {
8073 for (; wp != NULL; wp = wp->w_next)
8074 if (list_append_number(rettv->vval.v_list,
8075 wp->w_buffer->b_fnum) == FAIL)
8076 break;
8077 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078}
8079
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008080/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081 * "tagfiles()" function
8082 */
8083 static void
8084f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8085{
8086 char_u *fname;
8087 tagname_T tn;
8088 int first;
8089
8090 if (rettv_list_alloc(rettv) == FAIL)
8091 return;
8092 fname = alloc(MAXPATHL);
8093 if (fname == NULL)
8094 return;
8095
8096 for (first = TRUE; ; first = FALSE)
8097 if (get_tagfname(&tn, first, fname) == FAIL
8098 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8099 break;
8100 tagname_free(&tn);
8101 vim_free(fname);
8102}
8103
8104/*
8105 * "taglist()" function
8106 */
8107 static void
8108f_taglist(typval_T *argvars, typval_T *rettv)
8109{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008110 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111 char_u *tag_pattern;
8112
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008113 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008114
8115 rettv->vval.v_number = FALSE;
8116 if (*tag_pattern == NUL)
8117 return;
8118
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008119 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008120 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008121 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008122 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008123}
8124
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008125#ifdef FEAT_FLOAT
8126/*
8127 * "tan()" function
8128 */
8129 static void
8130f_tan(typval_T *argvars, typval_T *rettv)
8131{
8132 float_T f = 0.0;
8133
8134 rettv->v_type = VAR_FLOAT;
8135 if (get_float_arg(argvars, &f) == OK)
8136 rettv->vval.v_float = tan(f);
8137 else
8138 rettv->vval.v_float = 0.0;
8139}
8140
8141/*
8142 * "tanh()" function
8143 */
8144 static void
8145f_tanh(typval_T *argvars, typval_T *rettv)
8146{
8147 float_T f = 0.0;
8148
8149 rettv->v_type = VAR_FLOAT;
8150 if (get_float_arg(argvars, &f) == OK)
8151 rettv->vval.v_float = tanh(f);
8152 else
8153 rettv->vval.v_float = 0.0;
8154}
8155#endif
8156
8157/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158 * "tolower(string)" function
8159 */
8160 static void
8161f_tolower(typval_T *argvars, typval_T *rettv)
8162{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008164 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165}
8166
8167/*
8168 * "toupper(string)" function
8169 */
8170 static void
8171f_toupper(typval_T *argvars, typval_T *rettv)
8172{
8173 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008174 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008175}
8176
8177/*
8178 * "tr(string, fromstr, tostr)" function
8179 */
8180 static void
8181f_tr(typval_T *argvars, typval_T *rettv)
8182{
8183 char_u *in_str;
8184 char_u *fromstr;
8185 char_u *tostr;
8186 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008187 int inlen;
8188 int fromlen;
8189 int tolen;
8190 int idx;
8191 char_u *cpstr;
8192 int cplen;
8193 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008194 char_u buf[NUMBUFLEN];
8195 char_u buf2[NUMBUFLEN];
8196 garray_T ga;
8197
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008198 in_str = tv_get_string(&argvars[0]);
8199 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8200 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201
8202 /* Default return value: empty string. */
8203 rettv->v_type = VAR_STRING;
8204 rettv->vval.v_string = NULL;
8205 if (fromstr == NULL || tostr == NULL)
8206 return; /* type error; errmsg already given */
8207 ga_init2(&ga, (int)sizeof(char), 80);
8208
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008210 /* not multi-byte: fromstr and tostr must be the same length */
8211 if (STRLEN(fromstr) != STRLEN(tostr))
8212 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008214 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008215 ga_clear(&ga);
8216 return;
8217 }
8218
8219 /* fromstr and tostr have to contain the same number of chars */
8220 while (*in_str != NUL)
8221 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008222 if (has_mbyte)
8223 {
8224 inlen = (*mb_ptr2len)(in_str);
8225 cpstr = in_str;
8226 cplen = inlen;
8227 idx = 0;
8228 for (p = fromstr; *p != NUL; p += fromlen)
8229 {
8230 fromlen = (*mb_ptr2len)(p);
8231 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8232 {
8233 for (p = tostr; *p != NUL; p += tolen)
8234 {
8235 tolen = (*mb_ptr2len)(p);
8236 if (idx-- == 0)
8237 {
8238 cplen = tolen;
8239 cpstr = p;
8240 break;
8241 }
8242 }
8243 if (*p == NUL) /* tostr is shorter than fromstr */
8244 goto error;
8245 break;
8246 }
8247 ++idx;
8248 }
8249
8250 if (first && cpstr == in_str)
8251 {
8252 /* Check that fromstr and tostr have the same number of
8253 * (multi-byte) characters. Done only once when a character
8254 * of in_str doesn't appear in fromstr. */
8255 first = FALSE;
8256 for (p = tostr; *p != NUL; p += tolen)
8257 {
8258 tolen = (*mb_ptr2len)(p);
8259 --idx;
8260 }
8261 if (idx != 0)
8262 goto error;
8263 }
8264
8265 (void)ga_grow(&ga, cplen);
8266 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8267 ga.ga_len += cplen;
8268
8269 in_str += inlen;
8270 }
8271 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008272 {
8273 /* When not using multi-byte chars we can do it faster. */
8274 p = vim_strchr(fromstr, *in_str);
8275 if (p != NULL)
8276 ga_append(&ga, tostr[p - fromstr]);
8277 else
8278 ga_append(&ga, *in_str);
8279 ++in_str;
8280 }
8281 }
8282
8283 /* add a terminating NUL */
8284 (void)ga_grow(&ga, 1);
8285 ga_append(&ga, NUL);
8286
8287 rettv->vval.v_string = ga.ga_data;
8288}
8289
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008290/*
8291 * "trim({expr})" function
8292 */
8293 static void
8294f_trim(typval_T *argvars, typval_T *rettv)
8295{
8296 char_u buf1[NUMBUFLEN];
8297 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008298 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008299 char_u *mask = NULL;
8300 char_u *tail;
8301 char_u *prev;
8302 char_u *p;
8303 int c1;
8304
8305 rettv->v_type = VAR_STRING;
8306 if (head == NULL)
8307 {
8308 rettv->vval.v_string = NULL;
8309 return;
8310 }
8311
8312 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008313 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008314
8315 while (*head != NUL)
8316 {
8317 c1 = PTR2CHAR(head);
8318 if (mask == NULL)
8319 {
8320 if (c1 > ' ' && c1 != 0xa0)
8321 break;
8322 }
8323 else
8324 {
8325 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8326 if (c1 == PTR2CHAR(p))
8327 break;
8328 if (*p == NUL)
8329 break;
8330 }
8331 MB_PTR_ADV(head);
8332 }
8333
8334 for (tail = head + STRLEN(head); tail > head; tail = prev)
8335 {
8336 prev = tail;
8337 MB_PTR_BACK(head, prev);
8338 c1 = PTR2CHAR(prev);
8339 if (mask == NULL)
8340 {
8341 if (c1 > ' ' && c1 != 0xa0)
8342 break;
8343 }
8344 else
8345 {
8346 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8347 if (c1 == PTR2CHAR(p))
8348 break;
8349 if (*p == NUL)
8350 break;
8351 }
8352 }
8353 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8354}
8355
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008356#ifdef FEAT_FLOAT
8357/*
8358 * "trunc({float})" function
8359 */
8360 static void
8361f_trunc(typval_T *argvars, typval_T *rettv)
8362{
8363 float_T f = 0.0;
8364
8365 rettv->v_type = VAR_FLOAT;
8366 if (get_float_arg(argvars, &f) == OK)
8367 /* trunc() is not in C90, use floor() or ceil() instead. */
8368 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8369 else
8370 rettv->vval.v_float = 0.0;
8371}
8372#endif
8373
8374/*
8375 * "type(expr)" function
8376 */
8377 static void
8378f_type(typval_T *argvars, typval_T *rettv)
8379{
8380 int n = -1;
8381
8382 switch (argvars[0].v_type)
8383 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008384 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8385 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008387 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8388 case VAR_LIST: n = VAR_TYPE_LIST; break;
8389 case VAR_DICT: n = VAR_TYPE_DICT; break;
8390 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008391 case VAR_SPECIAL:
8392 if (argvars[0].vval.v_number == VVAL_FALSE
8393 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008394 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008395 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008396 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008397 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008398 case VAR_JOB: n = VAR_TYPE_JOB; break;
8399 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008400 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008401 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008402 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008403 n = -1;
8404 break;
8405 }
8406 rettv->vval.v_number = n;
8407}
8408
8409/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008410 * "virtcol(string)" function
8411 */
8412 static void
8413f_virtcol(typval_T *argvars, typval_T *rettv)
8414{
8415 colnr_T vcol = 0;
8416 pos_T *fp;
8417 int fnum = curbuf->b_fnum;
8418
8419 fp = var2fpos(&argvars[0], FALSE, &fnum);
8420 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8421 && fnum == curbuf->b_fnum)
8422 {
8423 getvvcol(curwin, fp, NULL, NULL, &vcol);
8424 ++vcol;
8425 }
8426
8427 rettv->vval.v_number = vcol;
8428}
8429
8430/*
8431 * "visualmode()" function
8432 */
8433 static void
8434f_visualmode(typval_T *argvars, typval_T *rettv)
8435{
8436 char_u str[2];
8437
8438 rettv->v_type = VAR_STRING;
8439 str[0] = curbuf->b_visual_mode_eval;
8440 str[1] = NUL;
8441 rettv->vval.v_string = vim_strsave(str);
8442
8443 /* A non-zero number or non-empty string argument: reset mode. */
8444 if (non_zero_arg(&argvars[0]))
8445 curbuf->b_visual_mode_eval = NUL;
8446}
8447
8448/*
8449 * "wildmenumode()" function
8450 */
8451 static void
8452f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8453{
8454#ifdef FEAT_WILDMENU
8455 if (wild_menu_showing)
8456 rettv->vval.v_number = 1;
8457#endif
8458}
8459
8460/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008461 * "wordcount()" function
8462 */
8463 static void
8464f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8465{
8466 if (rettv_dict_alloc(rettv) == FAIL)
8467 return;
8468 cursor_pos_info(rettv->vval.v_dict);
8469}
8470
8471/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008472 * "xor(expr, expr)" function
8473 */
8474 static void
8475f_xor(typval_T *argvars, typval_T *rettv)
8476{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008477 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8478 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008479}
8480
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008481#endif /* FEAT_EVAL */