blob: 438aac8eac44ebdd62304d86869e667153498e64 [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 Moolenaard20dcb32019-09-10 21:22:58 +0200853 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200854 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200855 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200856 {"winheight", 1, 1, FEARG_1, f_winheight},
857 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200858 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200859 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200860 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200861 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200862 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200863 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200864 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200865 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200866 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200867};
868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200869/*
870 * Function given to ExpandGeneric() to obtain the list of internal
871 * or user defined function names.
872 */
873 char_u *
874get_function_name(expand_T *xp, int idx)
875{
876 static int intidx = -1;
877 char_u *name;
878
879 if (idx == 0)
880 intidx = -1;
881 if (intidx < 0)
882 {
883 name = get_user_func_name(xp, idx);
884 if (name != NULL)
885 return name;
886 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200887 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200889 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200891 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200892 STRCAT(IObuff, ")");
893 return IObuff;
894 }
895
896 return NULL;
897}
898
899/*
900 * Function given to ExpandGeneric() to obtain the list of internal or
901 * user defined variable or function names.
902 */
903 char_u *
904get_expr_name(expand_T *xp, int idx)
905{
906 static int intidx = -1;
907 char_u *name;
908
909 if (idx == 0)
910 intidx = -1;
911 if (intidx < 0)
912 {
913 name = get_function_name(xp, idx);
914 if (name != NULL)
915 return name;
916 }
917 return get_user_var_name(xp, ++intidx);
918}
919
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200921 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922 * Return index, or -1 if not found
923 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200924 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200925find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926{
927 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200928 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929 int cmp;
930 int x;
931
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200932 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200933
934 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935 while (first <= last)
936 {
937 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200938 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939 if (cmp < 0)
940 last = x - 1;
941 else if (cmp > 0)
942 first = x + 1;
943 else
944 return x;
945 }
946 return -1;
947}
948
949 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200950has_internal_func(char_u *name)
951{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200952 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200953}
954
955 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956call_internal_func(
957 char_u *name,
958 int argcount,
959 typval_T *argvars,
960 typval_T *rettv)
961{
962 int i;
963
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200964 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965 if (i < 0)
966 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200967 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200968 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200969 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200970 return ERROR_TOOMANY;
971 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200972 global_functions[i].f_func(argvars, rettv);
973 return ERROR_NONE;
974}
975
976/*
977 * Invoke a method for base->method().
978 */
979 int
980call_internal_method(
981 char_u *name,
982 int argcount,
983 typval_T *argvars,
984 typval_T *rettv,
985 typval_T *basetv)
986{
987 int i;
988 int fi;
989 typval_T argv[MAX_FUNC_ARGS + 1];
990
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200991 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +0200992 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200993 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +0200994 if (global_functions[fi].f_argtype == 0)
995 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200996 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200997 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200998 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200999 return ERROR_TOOMANY;
1000
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001001 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001002 {
1003 // base value goes last
1004 for (i = 0; i < argcount; ++i)
1005 argv[i] = argvars[i];
1006 argv[argcount] = *basetv;
1007 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001008 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001009 {
1010 // base value goes second
1011 argv[0] = argvars[0];
1012 argv[1] = *basetv;
1013 for (i = 1; i < argcount; ++i)
1014 argv[i + 1] = argvars[i];
1015 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001016 else if (global_functions[fi].f_argtype == FEARG_3)
1017 {
1018 // base value goes third
1019 argv[0] = argvars[0];
1020 argv[1] = argvars[1];
1021 argv[2] = *basetv;
1022 for (i = 2; i < argcount; ++i)
1023 argv[i + 1] = argvars[i];
1024 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001025 else if (global_functions[fi].f_argtype == FEARG_4)
1026 {
1027 // base value goes fourth
1028 argv[0] = argvars[0];
1029 argv[1] = argvars[1];
1030 argv[2] = argvars[2];
1031 argv[3] = *basetv;
1032 for (i = 3; i < argcount; ++i)
1033 argv[i + 1] = argvars[i];
1034 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001035 else
1036 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001037 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001038 argv[0] = *basetv;
1039 for (i = 0; i < argcount; ++i)
1040 argv[i + 1] = argvars[i];
1041 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042 argv[argcount + 1].v_type = VAR_UNKNOWN;
1043
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001044 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001045 return ERROR_NONE;
1046}
1047
1048/*
1049 * Return TRUE for a non-zero Number and a non-empty String.
1050 */
1051 static int
1052non_zero_arg(typval_T *argvars)
1053{
1054 return ((argvars[0].v_type == VAR_NUMBER
1055 && argvars[0].vval.v_number != 0)
1056 || (argvars[0].v_type == VAR_SPECIAL
1057 && argvars[0].vval.v_number == VVAL_TRUE)
1058 || (argvars[0].v_type == VAR_STRING
1059 && argvars[0].vval.v_string != NULL
1060 && *argvars[0].vval.v_string != NUL));
1061}
1062
1063/*
1064 * Get the lnum from the first argument.
1065 * Also accepts ".", "$", etc., but that only works for the current buffer.
1066 * Returns -1 on error.
1067 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001068 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001069tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001070{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001071 linenr_T lnum;
1072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001073 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001074 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001075 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001076 int fnum;
1077 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1078
1079 if (fp != NULL)
1080 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001081 }
1082 return lnum;
1083}
1084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001085/*
1086 * Get the lnum from the first argument.
1087 * Also accepts "$", then "buf" is used.
1088 * Returns 0 on error.
1089 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001090 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001091tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1092{
1093 if (argvars[0].v_type == VAR_STRING
1094 && argvars[0].vval.v_string != NULL
1095 && argvars[0].vval.v_string[0] == '$'
1096 && buf != NULL)
1097 return buf->b_ml.ml_line_count;
1098 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1099}
1100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001101#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001102/*
1103 * Get the float value of "argvars[0]" into "f".
1104 * Returns FAIL when the argument is not a Number or Float.
1105 */
1106 static int
1107get_float_arg(typval_T *argvars, float_T *f)
1108{
1109 if (argvars[0].v_type == VAR_FLOAT)
1110 {
1111 *f = argvars[0].vval.v_float;
1112 return OK;
1113 }
1114 if (argvars[0].v_type == VAR_NUMBER)
1115 {
1116 *f = (float_T)argvars[0].vval.v_number;
1117 return OK;
1118 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001119 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001120 return FAIL;
1121}
1122
1123/*
1124 * "abs(expr)" function
1125 */
1126 static void
1127f_abs(typval_T *argvars, typval_T *rettv)
1128{
1129 if (argvars[0].v_type == VAR_FLOAT)
1130 {
1131 rettv->v_type = VAR_FLOAT;
1132 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1133 }
1134 else
1135 {
1136 varnumber_T n;
1137 int error = FALSE;
1138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001139 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001140 if (error)
1141 rettv->vval.v_number = -1;
1142 else if (n > 0)
1143 rettv->vval.v_number = n;
1144 else
1145 rettv->vval.v_number = -n;
1146 }
1147}
1148
1149/*
1150 * "acos()" function
1151 */
1152 static void
1153f_acos(typval_T *argvars, typval_T *rettv)
1154{
1155 float_T f = 0.0;
1156
1157 rettv->v_type = VAR_FLOAT;
1158 if (get_float_arg(argvars, &f) == OK)
1159 rettv->vval.v_float = acos(f);
1160 else
1161 rettv->vval.v_float = 0.0;
1162}
1163#endif
1164
1165/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001166 * "and(expr, expr)" function
1167 */
1168 static void
1169f_and(typval_T *argvars, typval_T *rettv)
1170{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001171 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1172 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001173}
1174
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001175#ifdef FEAT_FLOAT
1176/*
1177 * "asin()" function
1178 */
1179 static void
1180f_asin(typval_T *argvars, typval_T *rettv)
1181{
1182 float_T f = 0.0;
1183
1184 rettv->v_type = VAR_FLOAT;
1185 if (get_float_arg(argvars, &f) == OK)
1186 rettv->vval.v_float = asin(f);
1187 else
1188 rettv->vval.v_float = 0.0;
1189}
1190
1191/*
1192 * "atan()" function
1193 */
1194 static void
1195f_atan(typval_T *argvars, typval_T *rettv)
1196{
1197 float_T f = 0.0;
1198
1199 rettv->v_type = VAR_FLOAT;
1200 if (get_float_arg(argvars, &f) == OK)
1201 rettv->vval.v_float = atan(f);
1202 else
1203 rettv->vval.v_float = 0.0;
1204}
1205
1206/*
1207 * "atan2()" function
1208 */
1209 static void
1210f_atan2(typval_T *argvars, typval_T *rettv)
1211{
1212 float_T fx = 0.0, fy = 0.0;
1213
1214 rettv->v_type = VAR_FLOAT;
1215 if (get_float_arg(argvars, &fx) == OK
1216 && get_float_arg(&argvars[1], &fy) == OK)
1217 rettv->vval.v_float = atan2(fx, fy);
1218 else
1219 rettv->vval.v_float = 0.0;
1220}
1221#endif
1222
1223/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001224 * "balloon_show()" function
1225 */
1226#ifdef FEAT_BEVAL
1227 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001228f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1229{
1230 rettv->v_type = VAR_STRING;
1231 if (balloonEval != NULL)
1232 {
1233 if (balloonEval->msg == NULL)
1234 rettv->vval.v_string = NULL;
1235 else
1236 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1237 }
1238}
1239
1240 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001241f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1242{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001243 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001244 {
1245 if (argvars[0].v_type == VAR_LIST
1246# ifdef FEAT_GUI
1247 && !gui.in_use
1248# endif
1249 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001250 {
1251 list_T *l = argvars[0].vval.v_list;
1252
1253 // empty list removes the balloon
1254 post_balloon(balloonEval, NULL,
1255 l == NULL || l->lv_len == 0 ? NULL : l);
1256 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001257 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001258 {
1259 char_u *mesg = tv_get_string_chk(&argvars[0]);
1260
1261 if (mesg != NULL)
1262 // empty string removes the balloon
1263 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1264 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001265 }
1266}
1267
Bram Moolenaar669a8282017-11-19 20:13:05 +01001268# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001269 static void
1270f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1271{
1272 if (rettv_list_alloc(rettv) == OK)
1273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001274 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001275
1276 if (msg != NULL)
1277 {
1278 pumitem_T *array;
1279 int size = split_message(msg, &array);
1280 int i;
1281
1282 /* Skip the first and last item, they are always empty. */
1283 for (i = 1; i < size - 1; ++i)
1284 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001285 while (size > 0)
1286 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001287 vim_free(array);
1288 }
1289 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001290}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001291# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001292#endif
1293
1294/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 * Get buffer by number or pattern.
1296 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001297 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001298tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001299{
1300 char_u *name = tv->vval.v_string;
1301 buf_T *buf;
1302
1303 if (tv->v_type == VAR_NUMBER)
1304 return buflist_findnr((int)tv->vval.v_number);
1305 if (tv->v_type != VAR_STRING)
1306 return NULL;
1307 if (name == NULL || *name == NUL)
1308 return curbuf;
1309 if (name[0] == '$' && name[1] == NUL)
1310 return lastbuf;
1311
1312 buf = buflist_find_by_name(name, curtab_only);
1313
1314 /* If not found, try expanding the name, like done for bufexists(). */
1315 if (buf == NULL)
1316 buf = find_buffer(tv);
1317
1318 return buf;
1319}
1320
1321/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001322 * Get the buffer from "arg" and give an error and return NULL if it is not
1323 * valid.
1324 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001325 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001326get_buf_arg(typval_T *arg)
1327{
1328 buf_T *buf;
1329
1330 ++emsg_off;
1331 buf = tv_get_buf(arg, FALSE);
1332 --emsg_off;
1333 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001334 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001335 return buf;
1336}
1337
1338/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001339 * "byte2line(byte)" function
1340 */
1341 static void
1342f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1343{
1344#ifndef FEAT_BYTEOFF
1345 rettv->vval.v_number = -1;
1346#else
1347 long boff = 0;
1348
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001349 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 if (boff < 0)
1351 rettv->vval.v_number = -1;
1352 else
1353 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1354 (linenr_T)0, &boff);
1355#endif
1356}
1357
1358 static void
1359byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1360{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 char_u *str;
1363 varnumber_T idx;
1364
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001365 str = tv_get_string_chk(&argvars[0]);
1366 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 rettv->vval.v_number = -1;
1368 if (str == NULL || idx < 0)
1369 return;
1370
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001371 t = str;
1372 for ( ; idx > 0; idx--)
1373 {
1374 if (*t == NUL) /* EOL reached */
1375 return;
1376 if (enc_utf8 && comp)
1377 t += utf_ptr2len(t);
1378 else
1379 t += (*mb_ptr2len)(t);
1380 }
1381 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382}
1383
1384/*
1385 * "byteidx()" function
1386 */
1387 static void
1388f_byteidx(typval_T *argvars, typval_T *rettv)
1389{
1390 byteidx(argvars, rettv, FALSE);
1391}
1392
1393/*
1394 * "byteidxcomp()" function
1395 */
1396 static void
1397f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1398{
1399 byteidx(argvars, rettv, TRUE);
1400}
1401
1402/*
1403 * "call(func, arglist [, dict])" function
1404 */
1405 static void
1406f_call(typval_T *argvars, typval_T *rettv)
1407{
1408 char_u *func;
1409 partial_T *partial = NULL;
1410 dict_T *selfdict = NULL;
1411
1412 if (argvars[1].v_type != VAR_LIST)
1413 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001414 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001415 return;
1416 }
1417 if (argvars[1].vval.v_list == NULL)
1418 return;
1419
1420 if (argvars[0].v_type == VAR_FUNC)
1421 func = argvars[0].vval.v_string;
1422 else if (argvars[0].v_type == VAR_PARTIAL)
1423 {
1424 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001425 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001426 }
1427 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001428 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001429 if (*func == NUL)
1430 return; /* type error or empty name */
1431
1432 if (argvars[2].v_type != VAR_UNKNOWN)
1433 {
1434 if (argvars[2].v_type != VAR_DICT)
1435 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001436 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001437 return;
1438 }
1439 selfdict = argvars[2].vval.v_dict;
1440 }
1441
1442 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1443}
1444
1445#ifdef FEAT_FLOAT
1446/*
1447 * "ceil({float})" function
1448 */
1449 static void
1450f_ceil(typval_T *argvars, typval_T *rettv)
1451{
1452 float_T f = 0.0;
1453
1454 rettv->v_type = VAR_FLOAT;
1455 if (get_float_arg(argvars, &f) == OK)
1456 rettv->vval.v_float = ceil(f);
1457 else
1458 rettv->vval.v_float = 0.0;
1459}
1460#endif
1461
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001462/*
1463 * "changenr()" function
1464 */
1465 static void
1466f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1467{
1468 rettv->vval.v_number = curbuf->b_u_seq_cur;
1469}
1470
1471/*
1472 * "char2nr(string)" function
1473 */
1474 static void
1475f_char2nr(typval_T *argvars, typval_T *rettv)
1476{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001477 if (has_mbyte)
1478 {
1479 int utf8 = 0;
1480
1481 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001482 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483
1484 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001485 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001487 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488 }
1489 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001490 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001491}
1492
1493/*
1494 * "cindent(lnum)" function
1495 */
1496 static void
1497f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1498{
1499#ifdef FEAT_CINDENT
1500 pos_T pos;
1501 linenr_T lnum;
1502
1503 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001504 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001505 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1506 {
1507 curwin->w_cursor.lnum = lnum;
1508 rettv->vval.v_number = get_c_indent();
1509 curwin->w_cursor = pos;
1510 }
1511 else
1512#endif
1513 rettv->vval.v_number = -1;
1514}
1515
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001516 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001517get_optional_window(typval_T *argvars, int idx)
1518{
1519 win_T *win = curwin;
1520
1521 if (argvars[idx].v_type != VAR_UNKNOWN)
1522 {
1523 win = find_win_by_nr_or_id(&argvars[idx]);
1524 if (win == NULL)
1525 {
1526 emsg(_(e_invalwindow));
1527 return NULL;
1528 }
1529 }
1530 return win;
1531}
1532
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001534 * "col(string)" function
1535 */
1536 static void
1537f_col(typval_T *argvars, typval_T *rettv)
1538{
1539 colnr_T col = 0;
1540 pos_T *fp;
1541 int fnum = curbuf->b_fnum;
1542
1543 fp = var2fpos(&argvars[0], FALSE, &fnum);
1544 if (fp != NULL && fnum == curbuf->b_fnum)
1545 {
1546 if (fp->col == MAXCOL)
1547 {
1548 /* '> can be MAXCOL, get the length of the line then */
1549 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1550 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1551 else
1552 col = MAXCOL;
1553 }
1554 else
1555 {
1556 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001557 /* col(".") when the cursor is on the NUL at the end of the line
1558 * because of "coladd" can be seen as an extra column. */
1559 if (virtual_active() && fp == &curwin->w_cursor)
1560 {
1561 char_u *p = ml_get_cursor();
1562
1563 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1564 curwin->w_virtcol - curwin->w_cursor.coladd))
1565 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001566 int l;
1567
1568 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1569 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 }
1571 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572 }
1573 }
1574 rettv->vval.v_number = col;
1575}
1576
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001577/*
1578 * "confirm(message, buttons[, default [, type]])" function
1579 */
1580 static void
1581f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1582{
1583#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1584 char_u *message;
1585 char_u *buttons = NULL;
1586 char_u buf[NUMBUFLEN];
1587 char_u buf2[NUMBUFLEN];
1588 int def = 1;
1589 int type = VIM_GENERIC;
1590 char_u *typestr;
1591 int error = FALSE;
1592
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001593 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001594 if (message == NULL)
1595 error = TRUE;
1596 if (argvars[1].v_type != VAR_UNKNOWN)
1597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001598 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001599 if (buttons == NULL)
1600 error = TRUE;
1601 if (argvars[2].v_type != VAR_UNKNOWN)
1602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001603 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001604 if (argvars[3].v_type != VAR_UNKNOWN)
1605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001606 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607 if (typestr == NULL)
1608 error = TRUE;
1609 else
1610 {
1611 switch (TOUPPER_ASC(*typestr))
1612 {
1613 case 'E': type = VIM_ERROR; break;
1614 case 'Q': type = VIM_QUESTION; break;
1615 case 'I': type = VIM_INFO; break;
1616 case 'W': type = VIM_WARNING; break;
1617 case 'G': type = VIM_GENERIC; break;
1618 }
1619 }
1620 }
1621 }
1622 }
1623
1624 if (buttons == NULL || *buttons == NUL)
1625 buttons = (char_u *)_("&Ok");
1626
1627 if (!error)
1628 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1629 def, NULL, FALSE);
1630#endif
1631}
1632
1633/*
1634 * "copy()" function
1635 */
1636 static void
1637f_copy(typval_T *argvars, typval_T *rettv)
1638{
1639 item_copy(&argvars[0], rettv, FALSE, 0);
1640}
1641
1642#ifdef FEAT_FLOAT
1643/*
1644 * "cos()" function
1645 */
1646 static void
1647f_cos(typval_T *argvars, typval_T *rettv)
1648{
1649 float_T f = 0.0;
1650
1651 rettv->v_type = VAR_FLOAT;
1652 if (get_float_arg(argvars, &f) == OK)
1653 rettv->vval.v_float = cos(f);
1654 else
1655 rettv->vval.v_float = 0.0;
1656}
1657
1658/*
1659 * "cosh()" function
1660 */
1661 static void
1662f_cosh(typval_T *argvars, typval_T *rettv)
1663{
1664 float_T f = 0.0;
1665
1666 rettv->v_type = VAR_FLOAT;
1667 if (get_float_arg(argvars, &f) == OK)
1668 rettv->vval.v_float = cosh(f);
1669 else
1670 rettv->vval.v_float = 0.0;
1671}
1672#endif
1673
1674/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 * "cursor(lnum, col)" function, or
1676 * "cursor(list)"
1677 *
1678 * Moves the cursor to the specified line and column.
1679 * Returns 0 when the position could be set, -1 otherwise.
1680 */
1681 static void
1682f_cursor(typval_T *argvars, typval_T *rettv)
1683{
1684 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 int set_curswant = TRUE;
1687
1688 rettv->vval.v_number = -1;
1689 if (argvars[1].v_type == VAR_UNKNOWN)
1690 {
1691 pos_T pos;
1692 colnr_T curswant = -1;
1693
1694 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1695 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001696 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697 return;
1698 }
1699 line = pos.lnum;
1700 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001701 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702 if (curswant >= 0)
1703 {
1704 curwin->w_curswant = curswant - 1;
1705 set_curswant = FALSE;
1706 }
1707 }
1708 else
1709 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001710 line = tv_get_lnum(argvars);
1711 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001713 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001715 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 return; /* type error; errmsg already given */
1717 if (line > 0)
1718 curwin->w_cursor.lnum = line;
1719 if (col > 0)
1720 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001721 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722
1723 /* Make sure the cursor is in a valid position. */
1724 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 /* Correct cursor for multi-byte character. */
1726 if (has_mbyte)
1727 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728
1729 curwin->w_set_curswant = set_curswant;
1730 rettv->vval.v_number = 0;
1731}
1732
Bram Moolenaar4f974752019-02-17 17:44:42 +01001733#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001734/*
1735 * "debugbreak()" function
1736 */
1737 static void
1738f_debugbreak(typval_T *argvars, typval_T *rettv)
1739{
1740 int pid;
1741
1742 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001743 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001744 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001745 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001746 else
1747 {
1748 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1749
1750 if (hProcess != NULL)
1751 {
1752 DebugBreakProcess(hProcess);
1753 CloseHandle(hProcess);
1754 rettv->vval.v_number = OK;
1755 }
1756 }
1757}
1758#endif
1759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001760/*
1761 * "deepcopy()" function
1762 */
1763 static void
1764f_deepcopy(typval_T *argvars, typval_T *rettv)
1765{
1766 int noref = 0;
1767 int copyID;
1768
1769 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001770 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001771 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001772 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773 else
1774 {
1775 copyID = get_copyID();
1776 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1777 }
1778}
1779
1780/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001781 * "did_filetype()" function
1782 */
1783 static void
1784f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1785{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001786 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001787}
1788
1789/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790 * "empty({expr})" function
1791 */
1792 static void
1793f_empty(typval_T *argvars, typval_T *rettv)
1794{
1795 int n = FALSE;
1796
1797 switch (argvars[0].v_type)
1798 {
1799 case VAR_STRING:
1800 case VAR_FUNC:
1801 n = argvars[0].vval.v_string == NULL
1802 || *argvars[0].vval.v_string == NUL;
1803 break;
1804 case VAR_PARTIAL:
1805 n = FALSE;
1806 break;
1807 case VAR_NUMBER:
1808 n = argvars[0].vval.v_number == 0;
1809 break;
1810 case VAR_FLOAT:
1811#ifdef FEAT_FLOAT
1812 n = argvars[0].vval.v_float == 0.0;
1813 break;
1814#endif
1815 case VAR_LIST:
1816 n = argvars[0].vval.v_list == NULL
1817 || argvars[0].vval.v_list->lv_first == NULL;
1818 break;
1819 case VAR_DICT:
1820 n = argvars[0].vval.v_dict == NULL
1821 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1822 break;
1823 case VAR_SPECIAL:
1824 n = argvars[0].vval.v_number != VVAL_TRUE;
1825 break;
1826
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001827 case VAR_BLOB:
1828 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001829 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1830 break;
1831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 case VAR_JOB:
1833#ifdef FEAT_JOB_CHANNEL
1834 n = argvars[0].vval.v_job == NULL
1835 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1836 break;
1837#endif
1838 case VAR_CHANNEL:
1839#ifdef FEAT_JOB_CHANNEL
1840 n = argvars[0].vval.v_channel == NULL
1841 || !channel_is_open(argvars[0].vval.v_channel);
1842 break;
1843#endif
1844 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001845 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846 n = TRUE;
1847 break;
1848 }
1849
1850 rettv->vval.v_number = n;
1851}
1852
1853/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001854 * "environ()" function
1855 */
1856 static void
1857f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1858{
1859#if !defined(AMIGA)
1860 int i = 0;
1861 char_u *entry, *value;
1862# ifdef MSWIN
1863 extern wchar_t **_wenviron;
1864# else
1865 extern char **environ;
1866# endif
1867
1868 if (rettv_dict_alloc(rettv) != OK)
1869 return;
1870
1871# ifdef MSWIN
1872 if (*_wenviron == NULL)
1873 return;
1874# else
1875 if (*environ == NULL)
1876 return;
1877# endif
1878
1879 for (i = 0; ; ++i)
1880 {
1881# ifdef MSWIN
1882 short_u *p;
1883
1884 if ((p = (short_u *)_wenviron[i]) == NULL)
1885 return;
1886 entry = utf16_to_enc(p, NULL);
1887# else
1888 if ((entry = (char_u *)environ[i]) == NULL)
1889 return;
1890 entry = vim_strsave(entry);
1891# endif
1892 if (entry == NULL) // out of memory
1893 return;
1894 if ((value = vim_strchr(entry, '=')) == NULL)
1895 {
1896 vim_free(entry);
1897 continue;
1898 }
1899 *value++ = NUL;
1900 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1901 vim_free(entry);
1902 }
1903#endif
1904}
1905
1906/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001907 * "escape({string}, {chars})" function
1908 */
1909 static void
1910f_escape(typval_T *argvars, typval_T *rettv)
1911{
1912 char_u buf[NUMBUFLEN];
1913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001914 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1915 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001916 rettv->v_type = VAR_STRING;
1917}
1918
1919/*
1920 * "eval()" function
1921 */
1922 static void
1923f_eval(typval_T *argvars, typval_T *rettv)
1924{
1925 char_u *s, *p;
1926
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001927 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 if (s != NULL)
1929 s = skipwhite(s);
1930
1931 p = s;
1932 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1933 {
1934 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001935 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001936 need_clr_eos = FALSE;
1937 rettv->v_type = VAR_NUMBER;
1938 rettv->vval.v_number = 0;
1939 }
1940 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001941 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942}
1943
1944/*
1945 * "eventhandler()" function
1946 */
1947 static void
1948f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1949{
1950 rettv->vval.v_number = vgetc_busy;
1951}
1952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001953static garray_T redir_execute_ga;
1954
1955/*
1956 * Append "value[value_len]" to the execute() output.
1957 */
1958 void
1959execute_redir_str(char_u *value, int value_len)
1960{
1961 int len;
1962
1963 if (value_len == -1)
1964 len = (int)STRLEN(value); /* Append the entire string */
1965 else
1966 len = value_len; /* Append only "value_len" characters */
1967 if (ga_grow(&redir_execute_ga, len) == OK)
1968 {
1969 mch_memmove((char *)redir_execute_ga.ga_data
1970 + redir_execute_ga.ga_len, value, len);
1971 redir_execute_ga.ga_len += len;
1972 }
1973}
1974
1975/*
1976 * Get next line from a list.
1977 * Called by do_cmdline() to get the next line.
1978 * Returns allocated string, or NULL for end of function.
1979 */
1980
1981 static char_u *
1982get_list_line(
1983 int c UNUSED,
1984 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001985 int indent UNUSED,
1986 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987{
1988 listitem_T **p = (listitem_T **)cookie;
1989 listitem_T *item = *p;
1990 char_u buf[NUMBUFLEN];
1991 char_u *s;
1992
1993 if (item == NULL)
1994 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001995 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996 *p = item->li_next;
1997 return s == NULL ? NULL : vim_strsave(s);
1998}
1999
2000/*
2001 * "execute()" function
2002 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002003 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002004execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002005{
2006 char_u *cmd = NULL;
2007 list_T *list = NULL;
2008 int save_msg_silent = msg_silent;
2009 int save_emsg_silent = emsg_silent;
2010 int save_emsg_noredir = emsg_noredir;
2011 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002012 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002014 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002015 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002016
2017 rettv->vval.v_string = NULL;
2018 rettv->v_type = VAR_STRING;
2019
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002020 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002022 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023 if (list == NULL || list->lv_first == NULL)
2024 /* empty list, no commands, empty output */
2025 return;
2026 ++list->lv_refcount;
2027 }
2028 else
2029 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002030 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002031 if (cmd == NULL)
2032 return;
2033 }
2034
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002035 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002036 {
2037 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002038 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039
2040 if (s == NULL)
2041 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002042 if (*s == NUL)
2043 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002044 if (STRNCMP(s, "silent", 6) == 0)
2045 ++msg_silent;
2046 if (STRCMP(s, "silent!") == 0)
2047 {
2048 emsg_silent = TRUE;
2049 emsg_noredir = TRUE;
2050 }
2051 }
2052 else
2053 ++msg_silent;
2054
2055 if (redir_execute)
2056 save_ga = redir_execute_ga;
2057 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2058 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002059 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002060 if (!echo_output)
2061 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002062
2063 if (cmd != NULL)
2064 do_cmdline_cmd(cmd);
2065 else
2066 {
2067 listitem_T *item = list->lv_first;
2068
2069 do_cmdline(NULL, get_list_line, (void *)&item,
2070 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2071 --list->lv_refcount;
2072 }
2073
Bram Moolenaard297f352017-01-29 20:31:21 +01002074 /* Need to append a NUL to the result. */
2075 if (ga_grow(&redir_execute_ga, 1) == OK)
2076 {
2077 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2078 rettv->vval.v_string = redir_execute_ga.ga_data;
2079 }
2080 else
2081 {
2082 ga_clear(&redir_execute_ga);
2083 rettv->vval.v_string = NULL;
2084 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002085 msg_silent = save_msg_silent;
2086 emsg_silent = save_emsg_silent;
2087 emsg_noredir = save_emsg_noredir;
2088
2089 redir_execute = save_redir_execute;
2090 if (redir_execute)
2091 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002092 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002094 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002095 if (echo_output)
2096 // When not working silently: put it in column zero. A following
2097 // "echon" will overwrite the message, unavoidably.
2098 msg_col = 0;
2099 else
2100 // When working silently: Put it back where it was, since nothing
2101 // should have been written.
2102 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002103}
2104
2105/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002106 * "execute()" function
2107 */
2108 static void
2109f_execute(typval_T *argvars, typval_T *rettv)
2110{
2111 execute_common(argvars, rettv, 0);
2112}
2113
2114/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002115 * "exists()" function
2116 */
2117 static void
2118f_exists(typval_T *argvars, typval_T *rettv)
2119{
2120 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002121 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002123 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002124 if (*p == '$') /* environment variable */
2125 {
2126 /* first try "normal" environment variables (fast) */
2127 if (mch_getenv(p + 1) != NULL)
2128 n = TRUE;
2129 else
2130 {
2131 /* try expanding things like $VIM and ${HOME} */
2132 p = expand_env_save(p);
2133 if (p != NULL && *p != '$')
2134 n = TRUE;
2135 vim_free(p);
2136 }
2137 }
2138 else if (*p == '&' || *p == '+') /* option */
2139 {
2140 n = (get_option_tv(&p, NULL, TRUE) == OK);
2141 if (*skipwhite(p) != NUL)
2142 n = FALSE; /* trailing garbage */
2143 }
2144 else if (*p == '*') /* internal or user defined function */
2145 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002146 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147 }
2148 else if (*p == ':')
2149 {
2150 n = cmd_exists(p + 1);
2151 }
2152 else if (*p == '#')
2153 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 if (p[1] == '#')
2155 n = autocmd_supported(p + 2);
2156 else
2157 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 }
2159 else /* internal variable */
2160 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002161 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162 }
2163
2164 rettv->vval.v_number = n;
2165}
2166
2167#ifdef FEAT_FLOAT
2168/*
2169 * "exp()" function
2170 */
2171 static void
2172f_exp(typval_T *argvars, typval_T *rettv)
2173{
2174 float_T f = 0.0;
2175
2176 rettv->v_type = VAR_FLOAT;
2177 if (get_float_arg(argvars, &f) == OK)
2178 rettv->vval.v_float = exp(f);
2179 else
2180 rettv->vval.v_float = 0.0;
2181}
2182#endif
2183
2184/*
2185 * "expand()" function
2186 */
2187 static void
2188f_expand(typval_T *argvars, typval_T *rettv)
2189{
2190 char_u *s;
2191 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002192 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002193 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2194 expand_T xpc;
2195 int error = FALSE;
2196 char_u *result;
2197
2198 rettv->v_type = VAR_STRING;
2199 if (argvars[1].v_type != VAR_UNKNOWN
2200 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002201 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002202 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002203 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002205 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002206 if (*s == '%' || *s == '#' || *s == '<')
2207 {
2208 ++emsg_off;
2209 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2210 --emsg_off;
2211 if (rettv->v_type == VAR_LIST)
2212 {
2213 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2214 list_append_string(rettv->vval.v_list, result, -1);
2215 else
2216 vim_free(result);
2217 }
2218 else
2219 rettv->vval.v_string = result;
2220 }
2221 else
2222 {
2223 /* When the optional second argument is non-zero, don't remove matches
2224 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2225 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002226 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002227 options |= WILD_KEEP_ALL;
2228 if (!error)
2229 {
2230 ExpandInit(&xpc);
2231 xpc.xp_context = EXPAND_FILES;
2232 if (p_wic)
2233 options += WILD_ICASE;
2234 if (rettv->v_type == VAR_STRING)
2235 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2236 options, WILD_ALL);
2237 else if (rettv_list_alloc(rettv) != FAIL)
2238 {
2239 int i;
2240
2241 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2242 for (i = 0; i < xpc.xp_numfiles; i++)
2243 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2244 ExpandCleanup(&xpc);
2245 }
2246 }
2247 else
2248 rettv->vval.v_string = NULL;
2249 }
2250}
2251
2252/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002253 * "expandcmd()" function
2254 * Expand all the special characters in a command string.
2255 */
2256 static void
2257f_expandcmd(typval_T *argvars, typval_T *rettv)
2258{
2259 exarg_T eap;
2260 char_u *cmdstr;
2261 char *errormsg = NULL;
2262
2263 rettv->v_type = VAR_STRING;
2264 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2265
2266 memset(&eap, 0, sizeof(eap));
2267 eap.cmd = cmdstr;
2268 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002269 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002270 eap.usefilter = FALSE;
2271 eap.nextcmd = NULL;
2272 eap.cmdidx = CMD_USER;
2273
2274 expand_filename(&eap, &cmdstr, &errormsg);
2275 if (errormsg != NULL && *errormsg != NUL)
2276 emsg(errormsg);
2277
2278 rettv->vval.v_string = cmdstr;
2279}
2280
2281/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 * "feedkeys()" function
2283 */
2284 static void
2285f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2286{
2287 int remap = TRUE;
2288 int insert = FALSE;
2289 char_u *keys, *flags;
2290 char_u nbuf[NUMBUFLEN];
2291 int typed = FALSE;
2292 int execute = FALSE;
2293 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002294 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 char_u *keys_esc;
2296
2297 /* This is not allowed in the sandbox. If the commands would still be
2298 * executed in the sandbox it would be OK, but it probably happens later,
2299 * when "sandbox" is no longer set. */
2300 if (check_secure())
2301 return;
2302
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002303 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002304
2305 if (argvars[1].v_type != VAR_UNKNOWN)
2306 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002307 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 for ( ; *flags != NUL; ++flags)
2309 {
2310 switch (*flags)
2311 {
2312 case 'n': remap = FALSE; break;
2313 case 'm': remap = TRUE; break;
2314 case 't': typed = TRUE; break;
2315 case 'i': insert = TRUE; break;
2316 case 'x': execute = TRUE; break;
2317 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002318 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002319 }
2320 }
2321 }
2322
2323 if (*keys != NUL || execute)
2324 {
2325 /* Need to escape K_SPECIAL and CSI before putting the string in the
2326 * typeahead buffer. */
2327 keys_esc = vim_strsave_escape_csi(keys);
2328 if (keys_esc != NULL)
2329 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002330 if (lowlevel)
2331 {
2332#ifdef USE_INPUT_BUF
2333 add_to_input_buf(keys, (int)STRLEN(keys));
2334#else
2335 emsg(_("E980: lowlevel input not supported"));
2336#endif
2337 }
2338 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002339 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002340 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002341 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002342 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002343#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002344 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002345#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002346 )
2347 typebuf_was_filled = TRUE;
2348 }
2349 vim_free(keys_esc);
2350
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002351 if (execute)
2352 {
2353 int save_msg_scroll = msg_scroll;
2354
2355 /* Avoid a 1 second delay when the keys start Insert mode. */
2356 msg_scroll = FALSE;
2357
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002358 if (!dangerous)
2359 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002360 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002361 if (!dangerous)
2362 --ex_normal_busy;
2363
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 msg_scroll |= save_msg_scroll;
2365 }
2366 }
2367 }
2368}
2369
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370#ifdef FEAT_FLOAT
2371/*
2372 * "float2nr({float})" function
2373 */
2374 static void
2375f_float2nr(typval_T *argvars, typval_T *rettv)
2376{
2377 float_T f = 0.0;
2378
2379 if (get_float_arg(argvars, &f) == OK)
2380 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002381 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002382 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002383 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002384 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002385 else
2386 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002387 }
2388}
2389
2390/*
2391 * "floor({float})" function
2392 */
2393 static void
2394f_floor(typval_T *argvars, typval_T *rettv)
2395{
2396 float_T f = 0.0;
2397
2398 rettv->v_type = VAR_FLOAT;
2399 if (get_float_arg(argvars, &f) == OK)
2400 rettv->vval.v_float = floor(f);
2401 else
2402 rettv->vval.v_float = 0.0;
2403}
2404
2405/*
2406 * "fmod()" function
2407 */
2408 static void
2409f_fmod(typval_T *argvars, typval_T *rettv)
2410{
2411 float_T fx = 0.0, fy = 0.0;
2412
2413 rettv->v_type = VAR_FLOAT;
2414 if (get_float_arg(argvars, &fx) == OK
2415 && get_float_arg(&argvars[1], &fy) == OK)
2416 rettv->vval.v_float = fmod(fx, fy);
2417 else
2418 rettv->vval.v_float = 0.0;
2419}
2420#endif
2421
2422/*
2423 * "fnameescape({string})" function
2424 */
2425 static void
2426f_fnameescape(typval_T *argvars, typval_T *rettv)
2427{
2428 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002429 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002430 rettv->v_type = VAR_STRING;
2431}
2432
2433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 * "foreground()" function
2435 */
2436 static void
2437f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2438{
2439#ifdef FEAT_GUI
2440 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002441 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002443 return;
2444 }
2445#endif
2446#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448#endif
2449}
2450
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002452common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002453{
2454 char_u *s;
2455 char_u *name;
2456 int use_string = FALSE;
2457 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002458 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459
2460 if (argvars[0].v_type == VAR_FUNC)
2461 {
2462 /* function(MyFunc, [arg], dict) */
2463 s = argvars[0].vval.v_string;
2464 }
2465 else if (argvars[0].v_type == VAR_PARTIAL
2466 && argvars[0].vval.v_partial != NULL)
2467 {
2468 /* function(dict.MyFunc, [arg]) */
2469 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002470 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002471 }
2472 else
2473 {
2474 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002475 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476 use_string = TRUE;
2477 }
2478
Bram Moolenaar843b8842016-08-21 14:36:15 +02002479 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002480 {
2481 name = s;
2482 trans_name = trans_function_name(&name, FALSE,
2483 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2484 if (*name != NUL)
2485 s = NULL;
2486 }
2487
Bram Moolenaar843b8842016-08-21 14:36:15 +02002488 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2489 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002490 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002491 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002492 else if (trans_name != NULL && (is_funcref
2493 ? find_func(trans_name) == NULL
2494 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002495 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496 else
2497 {
2498 int dict_idx = 0;
2499 int arg_idx = 0;
2500 list_T *list = NULL;
2501
2502 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2503 {
2504 char sid_buf[25];
2505 int off = *s == 's' ? 2 : 5;
2506
2507 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2508 * also be called from another script. Using trans_function_name()
2509 * would also work, but some plugins depend on the name being
2510 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002511 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002512 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002513 if (name != NULL)
2514 {
2515 STRCPY(name, sid_buf);
2516 STRCAT(name, s + off);
2517 }
2518 }
2519 else
2520 name = vim_strsave(s);
2521
2522 if (argvars[1].v_type != VAR_UNKNOWN)
2523 {
2524 if (argvars[2].v_type != VAR_UNKNOWN)
2525 {
2526 /* function(name, [args], dict) */
2527 arg_idx = 1;
2528 dict_idx = 2;
2529 }
2530 else if (argvars[1].v_type == VAR_DICT)
2531 /* function(name, dict) */
2532 dict_idx = 1;
2533 else
2534 /* function(name, [args]) */
2535 arg_idx = 1;
2536 if (dict_idx > 0)
2537 {
2538 if (argvars[dict_idx].v_type != VAR_DICT)
2539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002540 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002542 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 }
2544 if (argvars[dict_idx].vval.v_dict == NULL)
2545 dict_idx = 0;
2546 }
2547 if (arg_idx > 0)
2548 {
2549 if (argvars[arg_idx].v_type != VAR_LIST)
2550 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002551 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002553 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 }
2555 list = argvars[arg_idx].vval.v_list;
2556 if (list == NULL || list->lv_len == 0)
2557 arg_idx = 0;
2558 }
2559 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002560 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002562 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563
2564 /* result is a VAR_PARTIAL */
2565 if (pt == NULL)
2566 vim_free(name);
2567 else
2568 {
2569 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2570 {
2571 listitem_T *li;
2572 int i = 0;
2573 int arg_len = 0;
2574 int lv_len = 0;
2575
2576 if (arg_pt != NULL)
2577 arg_len = arg_pt->pt_argc;
2578 if (list != NULL)
2579 lv_len = list->lv_len;
2580 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002581 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 if (pt->pt_argv == NULL)
2583 {
2584 vim_free(pt);
2585 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002586 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002588 for (i = 0; i < arg_len; i++)
2589 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2590 if (lv_len > 0)
2591 for (li = list->lv_first; li != NULL;
2592 li = li->li_next)
2593 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 }
2595
2596 /* For "function(dict.func, [], dict)" and "func" is a partial
2597 * use "dict". That is backwards compatible. */
2598 if (dict_idx > 0)
2599 {
2600 /* The dict is bound explicitly, pt_auto is FALSE. */
2601 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2602 ++pt->pt_dict->dv_refcount;
2603 }
2604 else if (arg_pt != NULL)
2605 {
2606 /* If the dict was bound automatically the result is also
2607 * bound automatically. */
2608 pt->pt_dict = arg_pt->pt_dict;
2609 pt->pt_auto = arg_pt->pt_auto;
2610 if (pt->pt_dict != NULL)
2611 ++pt->pt_dict->dv_refcount;
2612 }
2613
2614 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002615 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2616 {
2617 pt->pt_func = arg_pt->pt_func;
2618 func_ptr_ref(pt->pt_func);
2619 vim_free(name);
2620 }
2621 else if (is_funcref)
2622 {
2623 pt->pt_func = find_func(trans_name);
2624 func_ptr_ref(pt->pt_func);
2625 vim_free(name);
2626 }
2627 else
2628 {
2629 pt->pt_name = name;
2630 func_ref(name);
2631 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632 }
2633 rettv->v_type = VAR_PARTIAL;
2634 rettv->vval.v_partial = pt;
2635 }
2636 else
2637 {
2638 /* result is a VAR_FUNC */
2639 rettv->v_type = VAR_FUNC;
2640 rettv->vval.v_string = name;
2641 func_ref(name);
2642 }
2643 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644theend:
2645 vim_free(trans_name);
2646}
2647
2648/*
2649 * "funcref()" function
2650 */
2651 static void
2652f_funcref(typval_T *argvars, typval_T *rettv)
2653{
2654 common_function(argvars, rettv, TRUE);
2655}
2656
2657/*
2658 * "function()" function
2659 */
2660 static void
2661f_function(typval_T *argvars, typval_T *rettv)
2662{
2663 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002664}
2665
2666/*
2667 * "garbagecollect()" function
2668 */
2669 static void
2670f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2671{
2672 /* This is postponed until we are back at the toplevel, because we may be
2673 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2674 want_garbage_collect = TRUE;
2675
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002676 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 garbage_collect_at_exit = TRUE;
2678}
2679
2680/*
2681 * "get()" function
2682 */
2683 static void
2684f_get(typval_T *argvars, typval_T *rettv)
2685{
2686 listitem_T *li;
2687 list_T *l;
2688 dictitem_T *di;
2689 dict_T *d;
2690 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002691 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002692
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002693 if (argvars[0].v_type == VAR_BLOB)
2694 {
2695 int error = FALSE;
2696 int idx = tv_get_number_chk(&argvars[1], &error);
2697
2698 if (!error)
2699 {
2700 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002701 if (idx < 0)
2702 idx = blob_len(argvars[0].vval.v_blob) + idx;
2703 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2704 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002705 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002706 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002707 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002708 tv = rettv;
2709 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002710 }
2711 }
2712 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 {
2714 if ((l = argvars[0].vval.v_list) != NULL)
2715 {
2716 int error = FALSE;
2717
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002718 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 if (!error && li != NULL)
2720 tv = &li->li_tv;
2721 }
2722 }
2723 else if (argvars[0].v_type == VAR_DICT)
2724 {
2725 if ((d = argvars[0].vval.v_dict) != NULL)
2726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002727 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 if (di != NULL)
2729 tv = &di->di_tv;
2730 }
2731 }
2732 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2733 {
2734 partial_T *pt;
2735 partial_T fref_pt;
2736
2737 if (argvars[0].v_type == VAR_PARTIAL)
2738 pt = argvars[0].vval.v_partial;
2739 else
2740 {
2741 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2742 fref_pt.pt_name = argvars[0].vval.v_string;
2743 pt = &fref_pt;
2744 }
2745
2746 if (pt != NULL)
2747 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002748 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002749 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002750
2751 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2752 {
2753 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002754 n = partial_name(pt);
2755 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 rettv->vval.v_string = NULL;
2757 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002758 {
2759 rettv->vval.v_string = vim_strsave(n);
2760 if (rettv->v_type == VAR_FUNC)
2761 func_ref(rettv->vval.v_string);
2762 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 }
2764 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002765 {
2766 what_is_dict = TRUE;
2767 if (pt->pt_dict != NULL)
2768 rettv_dict_set(rettv, pt->pt_dict);
2769 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 else if (STRCMP(what, "args") == 0)
2771 {
2772 rettv->v_type = VAR_LIST;
2773 if (rettv_list_alloc(rettv) == OK)
2774 {
2775 int i;
2776
2777 for (i = 0; i < pt->pt_argc; ++i)
2778 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2779 }
2780 }
2781 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002782 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002783
2784 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2785 // third argument
2786 if (!what_is_dict)
2787 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002788 }
2789 }
2790 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002791 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792
2793 if (tv == NULL)
2794 {
2795 if (argvars[2].v_type != VAR_UNKNOWN)
2796 copy_tv(&argvars[2], rettv);
2797 }
2798 else
2799 copy_tv(tv, rettv);
2800}
2801
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002802/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002803 * "getchangelist()" function
2804 */
2805 static void
2806f_getchangelist(typval_T *argvars, typval_T *rettv)
2807{
2808#ifdef FEAT_JUMPLIST
2809 buf_T *buf;
2810 int i;
2811 list_T *l;
2812 dict_T *d;
2813#endif
2814
2815 if (rettv_list_alloc(rettv) != OK)
2816 return;
2817
2818#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002819 if (argvars[0].v_type == VAR_UNKNOWN)
2820 buf = curbuf;
2821 else
2822 {
2823 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2824 ++emsg_off;
2825 buf = tv_get_buf(&argvars[0], FALSE);
2826 --emsg_off;
2827 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002828 if (buf == NULL)
2829 return;
2830
2831 l = list_alloc();
2832 if (l == NULL)
2833 return;
2834
2835 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2836 return;
2837 /*
2838 * The current window change list index tracks only the position in the
2839 * current buffer change list. For other buffers, use the change list
2840 * length as the current index.
2841 */
2842 list_append_number(rettv->vval.v_list,
2843 (varnumber_T)((buf == curwin->w_buffer)
2844 ? curwin->w_changelistidx : buf->b_changelistlen));
2845
2846 for (i = 0; i < buf->b_changelistlen; ++i)
2847 {
2848 if (buf->b_changelist[i].lnum == 0)
2849 continue;
2850 if ((d = dict_alloc()) == NULL)
2851 return;
2852 if (list_append_dict(l, d) == FAIL)
2853 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002854 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2855 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002856 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002857 }
2858#endif
2859}
2860/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002861 * "getchar()" function
2862 */
2863 static void
2864f_getchar(typval_T *argvars, typval_T *rettv)
2865{
2866 varnumber_T n;
2867 int error = FALSE;
2868
Bram Moolenaar84d93902018-09-11 20:10:20 +02002869#ifdef MESSAGE_QUEUE
2870 // vpeekc() used to check for messages, but that caused problems, invoking
2871 // a callback where it was not expected. Some plugins use getchar(1) in a
2872 // loop to await a message, therefore make sure we check for messages here.
2873 parse_queued_messages();
2874#endif
2875
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876 /* Position the cursor. Needed after a message that ends in a space. */
2877 windgoto(msg_row, msg_col);
2878
2879 ++no_mapping;
2880 ++allow_keys;
2881 for (;;)
2882 {
2883 if (argvars[0].v_type == VAR_UNKNOWN)
2884 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01002885 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002886 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002887 /* getchar(1): only check if char avail */
2888 n = vpeekc_any();
2889 else if (error || vpeekc_any() == NUL)
2890 /* illegal argument or getchar(0) and no char avail: return zero */
2891 n = 0;
2892 else
2893 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01002894 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002895
2896 if (n == K_IGNORE)
2897 continue;
2898 break;
2899 }
2900 --no_mapping;
2901 --allow_keys;
2902
2903 set_vim_var_nr(VV_MOUSE_WIN, 0);
2904 set_vim_var_nr(VV_MOUSE_WINID, 0);
2905 set_vim_var_nr(VV_MOUSE_LNUM, 0);
2906 set_vim_var_nr(VV_MOUSE_COL, 0);
2907
2908 rettv->vval.v_number = n;
2909 if (IS_SPECIAL(n) || mod_mask != 0)
2910 {
2911 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
2912 int i = 0;
2913
2914 /* Turn a special key into three bytes, plus modifier. */
2915 if (mod_mask != 0)
2916 {
2917 temp[i++] = K_SPECIAL;
2918 temp[i++] = KS_MODIFIER;
2919 temp[i++] = mod_mask;
2920 }
2921 if (IS_SPECIAL(n))
2922 {
2923 temp[i++] = K_SPECIAL;
2924 temp[i++] = K_SECOND(n);
2925 temp[i++] = K_THIRD(n);
2926 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002927 else if (has_mbyte)
2928 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002929 else
2930 temp[i++] = n;
2931 temp[i++] = NUL;
2932 rettv->v_type = VAR_STRING;
2933 rettv->vval.v_string = vim_strsave(temp);
2934
2935#ifdef FEAT_MOUSE
2936 if (is_mouse_key(n))
2937 {
2938 int row = mouse_row;
2939 int col = mouse_col;
2940 win_T *win;
2941 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002942 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002943 int winnr = 1;
2944
2945 if (row >= 0 && col >= 0)
2946 {
2947 /* Find the window at the mouse coordinates and compute the
2948 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002949 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02002950 if (win == NULL)
2951 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02002952 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002953# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02002954 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02002955 winnr = 0;
2956 else
2957# endif
2958 for (wp = firstwin; wp != win && wp != NULL;
2959 wp = wp->w_next)
2960 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002961 set_vim_var_nr(VV_MOUSE_WIN, winnr);
2962 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
2963 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
2964 set_vim_var_nr(VV_MOUSE_COL, col + 1);
2965 }
2966 }
2967#endif
2968 }
2969}
2970
2971/*
2972 * "getcharmod()" function
2973 */
2974 static void
2975f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
2976{
2977 rettv->vval.v_number = mod_mask;
2978}
2979
2980/*
2981 * "getcharsearch()" function
2982 */
2983 static void
2984f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2985{
2986 if (rettv_dict_alloc(rettv) != FAIL)
2987 {
2988 dict_T *dict = rettv->vval.v_dict;
2989
Bram Moolenaare0be1672018-07-08 16:50:37 +02002990 dict_add_string(dict, "char", last_csearch());
2991 dict_add_number(dict, "forward", last_csearch_forward());
2992 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002993 }
2994}
2995
2996/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002997 * "getcmdwintype()" function
2998 */
2999 static void
3000f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
3001{
3002 rettv->v_type = VAR_STRING;
3003 rettv->vval.v_string = NULL;
3004#ifdef FEAT_CMDWIN
3005 rettv->vval.v_string = alloc(2);
3006 if (rettv->vval.v_string != NULL)
3007 {
3008 rettv->vval.v_string[0] = cmdwin_type;
3009 rettv->vval.v_string[1] = NUL;
3010 }
3011#endif
3012}
3013
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003014/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003015 * "getenv()" function
3016 */
3017 static void
3018f_getenv(typval_T *argvars, typval_T *rettv)
3019{
3020 int mustfree = FALSE;
3021 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3022
3023 if (p == NULL)
3024 {
3025 rettv->v_type = VAR_SPECIAL;
3026 rettv->vval.v_number = VVAL_NULL;
3027 return;
3028 }
3029 if (!mustfree)
3030 p = vim_strsave(p);
3031 rettv->vval.v_string = p;
3032 rettv->v_type = VAR_STRING;
3033}
3034
3035/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 * "getfontname()" function
3037 */
3038 static void
3039f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3040{
3041 rettv->v_type = VAR_STRING;
3042 rettv->vval.v_string = NULL;
3043#ifdef FEAT_GUI
3044 if (gui.in_use)
3045 {
3046 GuiFont font;
3047 char_u *name = NULL;
3048
3049 if (argvars[0].v_type == VAR_UNKNOWN)
3050 {
3051 /* Get the "Normal" font. Either the name saved by
3052 * hl_set_font_name() or from the font ID. */
3053 font = gui.norm_font;
3054 name = hl_get_font_name();
3055 }
3056 else
3057 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003058 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059 if (STRCMP(name, "*") == 0) /* don't use font dialog */
3060 return;
3061 font = gui_mch_get_font(name, FALSE);
3062 if (font == NOFONT)
3063 return; /* Invalid font name, return empty string. */
3064 }
3065 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3066 if (argvars[0].v_type != VAR_UNKNOWN)
3067 gui_mch_free_font(font);
3068 }
3069#endif
3070}
3071
3072/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003073 * "getjumplist()" function
3074 */
3075 static void
3076f_getjumplist(typval_T *argvars, typval_T *rettv)
3077{
3078#ifdef FEAT_JUMPLIST
3079 win_T *wp;
3080 int i;
3081 list_T *l;
3082 dict_T *d;
3083#endif
3084
3085 if (rettv_list_alloc(rettv) != OK)
3086 return;
3087
3088#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003089 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003090 if (wp == NULL)
3091 return;
3092
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003093 cleanup_jumplist(wp, TRUE);
3094
Bram Moolenaar4f505882018-02-10 21:06:32 +01003095 l = list_alloc();
3096 if (l == NULL)
3097 return;
3098
3099 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3100 return;
3101 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3102
3103 for (i = 0; i < wp->w_jumplistlen; ++i)
3104 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003105 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3106 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003107 if ((d = dict_alloc()) == NULL)
3108 return;
3109 if (list_append_dict(l, d) == FAIL)
3110 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003111 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3112 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003113 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003114 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003115 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003116 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003117 }
3118#endif
3119}
3120
3121/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003122 * "getpid()" function
3123 */
3124 static void
3125f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3126{
3127 rettv->vval.v_number = mch_get_pid();
3128}
3129
3130 static void
3131getpos_both(
3132 typval_T *argvars,
3133 typval_T *rettv,
3134 int getcurpos)
3135{
3136 pos_T *fp;
3137 list_T *l;
3138 int fnum = -1;
3139
3140 if (rettv_list_alloc(rettv) == OK)
3141 {
3142 l = rettv->vval.v_list;
3143 if (getcurpos)
3144 fp = &curwin->w_cursor;
3145 else
3146 fp = var2fpos(&argvars[0], TRUE, &fnum);
3147 if (fnum != -1)
3148 list_append_number(l, (varnumber_T)fnum);
3149 else
3150 list_append_number(l, (varnumber_T)0);
3151 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3152 : (varnumber_T)0);
3153 list_append_number(l, (fp != NULL)
3154 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3155 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003156 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003157 (varnumber_T)0);
3158 if (getcurpos)
3159 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003160 int save_set_curswant = curwin->w_set_curswant;
3161 colnr_T save_curswant = curwin->w_curswant;
3162 colnr_T save_virtcol = curwin->w_virtcol;
3163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003164 update_curswant();
3165 list_append_number(l, curwin->w_curswant == MAXCOL ?
3166 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003167
3168 // Do not change "curswant", as it is unexpected that a get
3169 // function has a side effect.
3170 if (save_set_curswant)
3171 {
3172 curwin->w_set_curswant = save_set_curswant;
3173 curwin->w_curswant = save_curswant;
3174 curwin->w_virtcol = save_virtcol;
3175 curwin->w_valid &= ~VALID_VIRTCOL;
3176 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003177 }
3178 }
3179 else
3180 rettv->vval.v_number = FALSE;
3181}
3182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003183/*
3184 * "getcurpos()" function
3185 */
3186 static void
3187f_getcurpos(typval_T *argvars, typval_T *rettv)
3188{
3189 getpos_both(argvars, rettv, TRUE);
3190}
3191
3192/*
3193 * "getpos(string)" function
3194 */
3195 static void
3196f_getpos(typval_T *argvars, typval_T *rettv)
3197{
3198 getpos_both(argvars, rettv, FALSE);
3199}
3200
3201/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003202 * "getreg()" function
3203 */
3204 static void
3205f_getreg(typval_T *argvars, typval_T *rettv)
3206{
3207 char_u *strregname;
3208 int regname;
3209 int arg2 = FALSE;
3210 int return_list = FALSE;
3211 int error = FALSE;
3212
3213 if (argvars[0].v_type != VAR_UNKNOWN)
3214 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003215 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216 error = strregname == NULL;
3217 if (argvars[1].v_type != VAR_UNKNOWN)
3218 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003219 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003220 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003221 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003222 }
3223 }
3224 else
3225 strregname = get_vim_var_str(VV_REG);
3226
3227 if (error)
3228 return;
3229
3230 regname = (strregname == NULL ? '"' : *strregname);
3231 if (regname == 0)
3232 regname = '"';
3233
3234 if (return_list)
3235 {
3236 rettv->v_type = VAR_LIST;
3237 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3238 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3239 if (rettv->vval.v_list == NULL)
3240 (void)rettv_list_alloc(rettv);
3241 else
3242 ++rettv->vval.v_list->lv_refcount;
3243 }
3244 else
3245 {
3246 rettv->v_type = VAR_STRING;
3247 rettv->vval.v_string = get_reg_contents(regname,
3248 arg2 ? GREG_EXPR_SRC : 0);
3249 }
3250}
3251
3252/*
3253 * "getregtype()" function
3254 */
3255 static void
3256f_getregtype(typval_T *argvars, typval_T *rettv)
3257{
3258 char_u *strregname;
3259 int regname;
3260 char_u buf[NUMBUFLEN + 2];
3261 long reglen = 0;
3262
3263 if (argvars[0].v_type != VAR_UNKNOWN)
3264 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003265 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003266 if (strregname == NULL) /* type error; errmsg already given */
3267 {
3268 rettv->v_type = VAR_STRING;
3269 rettv->vval.v_string = NULL;
3270 return;
3271 }
3272 }
3273 else
3274 /* Default to v:register */
3275 strregname = get_vim_var_str(VV_REG);
3276
3277 regname = (strregname == NULL ? '"' : *strregname);
3278 if (regname == 0)
3279 regname = '"';
3280
3281 buf[0] = NUL;
3282 buf[1] = NUL;
3283 switch (get_reg_type(regname, &reglen))
3284 {
3285 case MLINE: buf[0] = 'V'; break;
3286 case MCHAR: buf[0] = 'v'; break;
3287 case MBLOCK:
3288 buf[0] = Ctrl_V;
3289 sprintf((char *)buf + 1, "%ld", reglen + 1);
3290 break;
3291 }
3292 rettv->v_type = VAR_STRING;
3293 rettv->vval.v_string = vim_strsave(buf);
3294}
3295
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003296/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003297 * "gettagstack()" function
3298 */
3299 static void
3300f_gettagstack(typval_T *argvars, typval_T *rettv)
3301{
3302 win_T *wp = curwin; // default is current window
3303
3304 if (rettv_dict_alloc(rettv) != OK)
3305 return;
3306
3307 if (argvars[0].v_type != VAR_UNKNOWN)
3308 {
3309 wp = find_win_by_nr_or_id(&argvars[0]);
3310 if (wp == NULL)
3311 return;
3312 }
3313
3314 get_tagstack(wp, rettv->vval.v_dict);
3315}
3316
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317/* for VIM_VERSION_ defines */
3318#include "version.h"
3319
3320/*
3321 * "has()" function
3322 */
3323 static void
3324f_has(typval_T *argvars, typval_T *rettv)
3325{
3326 int i;
3327 char_u *name;
3328 int n = FALSE;
3329 static char *(has_list[]) =
3330 {
3331#ifdef AMIGA
3332 "amiga",
3333# ifdef FEAT_ARP
3334 "arp",
3335# endif
3336#endif
3337#ifdef __BEOS__
3338 "beos",
3339#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003340#if defined(BSD) && !defined(MACOS_X)
3341 "bsd",
3342#endif
3343#ifdef hpux
3344 "hpux",
3345#endif
3346#ifdef __linux__
3347 "linux",
3348#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003349#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003350 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3351 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003352# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003353 "macunix", /* Mac OS X, with the darwin feature */
3354 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003355# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003356#endif
3357#ifdef __QNX__
3358 "qnx",
3359#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003360#ifdef SUN_SYSTEM
3361 "sun",
3362#else
3363 "moon",
3364#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003365#ifdef UNIX
3366 "unix",
3367#endif
3368#ifdef VMS
3369 "vms",
3370#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003371#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003372 "win32",
3373#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003374#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003375 "win32unix",
3376#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003377#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378 "win64",
3379#endif
3380#ifdef EBCDIC
3381 "ebcdic",
3382#endif
3383#ifndef CASE_INSENSITIVE_FILENAME
3384 "fname_case",
3385#endif
3386#ifdef HAVE_ACL
3387 "acl",
3388#endif
3389#ifdef FEAT_ARABIC
3390 "arabic",
3391#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003393#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003394 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003395#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003396#ifdef FEAT_AUTOSERVERNAME
3397 "autoservername",
3398#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003399#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003401# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003402 "balloon_multiline",
3403# endif
3404#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003405#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003406 "balloon_eval_term",
3407#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003408#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3409 "builtin_terms",
3410# ifdef ALL_BUILTIN_TCAPS
3411 "all_builtin_terms",
3412# endif
3413#endif
3414#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003415 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003416 || defined(FEAT_GUI_MOTIF))
3417 "browsefilter",
3418#endif
3419#ifdef FEAT_BYTEOFF
3420 "byte_offset",
3421#endif
3422#ifdef FEAT_JOB_CHANNEL
3423 "channel",
3424#endif
3425#ifdef FEAT_CINDENT
3426 "cindent",
3427#endif
3428#ifdef FEAT_CLIENTSERVER
3429 "clientserver",
3430#endif
3431#ifdef FEAT_CLIPBOARD
3432 "clipboard",
3433#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436#ifdef FEAT_COMMENTS
3437 "comments",
3438#endif
3439#ifdef FEAT_CONCEAL
3440 "conceal",
3441#endif
3442#ifdef FEAT_CRYPT
3443 "cryptv",
3444 "crypt-blowfish",
3445 "crypt-blowfish2",
3446#endif
3447#ifdef FEAT_CSCOPE
3448 "cscope",
3449#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003450 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003451#ifdef CURSOR_SHAPE
3452 "cursorshape",
3453#endif
3454#ifdef DEBUG
3455 "debug",
3456#endif
3457#ifdef FEAT_CON_DIALOG
3458 "dialog_con",
3459#endif
3460#ifdef FEAT_GUI_DIALOG
3461 "dialog_gui",
3462#endif
3463#ifdef FEAT_DIFF
3464 "diff",
3465#endif
3466#ifdef FEAT_DIGRAPHS
3467 "digraphs",
3468#endif
3469#ifdef FEAT_DIRECTX
3470 "directx",
3471#endif
3472#ifdef FEAT_DND
3473 "dnd",
3474#endif
3475#ifdef FEAT_EMACS_TAGS
3476 "emacs_tags",
3477#endif
3478 "eval", /* always present, of course! */
3479 "ex_extra", /* graduated feature */
3480#ifdef FEAT_SEARCH_EXTRA
3481 "extra_search",
3482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483#ifdef FEAT_SEARCHPATH
3484 "file_in_path",
3485#endif
3486#ifdef FEAT_FILTERPIPE
3487 "filterpipe",
3488#endif
3489#ifdef FEAT_FIND_ID
3490 "find_in_path",
3491#endif
3492#ifdef FEAT_FLOAT
3493 "float",
3494#endif
3495#ifdef FEAT_FOLDING
3496 "folding",
3497#endif
3498#ifdef FEAT_FOOTER
3499 "footer",
3500#endif
3501#if !defined(USE_SYSTEM) && defined(UNIX)
3502 "fork",
3503#endif
3504#ifdef FEAT_GETTEXT
3505 "gettext",
3506#endif
3507#ifdef FEAT_GUI
3508 "gui",
3509#endif
3510#ifdef FEAT_GUI_ATHENA
3511# ifdef FEAT_GUI_NEXTAW
3512 "gui_neXtaw",
3513# else
3514 "gui_athena",
3515# endif
3516#endif
3517#ifdef FEAT_GUI_GTK
3518 "gui_gtk",
3519# ifdef USE_GTK3
3520 "gui_gtk3",
3521# else
3522 "gui_gtk2",
3523# endif
3524#endif
3525#ifdef FEAT_GUI_GNOME
3526 "gui_gnome",
3527#endif
3528#ifdef FEAT_GUI_MAC
3529 "gui_mac",
3530#endif
3531#ifdef FEAT_GUI_MOTIF
3532 "gui_motif",
3533#endif
3534#ifdef FEAT_GUI_PHOTON
3535 "gui_photon",
3536#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003537#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003538 "gui_win32",
3539#endif
3540#ifdef FEAT_HANGULIN
3541 "hangul_input",
3542#endif
3543#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3544 "iconv",
3545#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003547#ifdef FEAT_JOB_CHANNEL
3548 "job",
3549#endif
3550#ifdef FEAT_JUMPLIST
3551 "jumplist",
3552#endif
3553#ifdef FEAT_KEYMAP
3554 "keymap",
3555#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003556 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003557#ifdef FEAT_LANGMAP
3558 "langmap",
3559#endif
3560#ifdef FEAT_LIBCALL
3561 "libcall",
3562#endif
3563#ifdef FEAT_LINEBREAK
3564 "linebreak",
3565#endif
3566#ifdef FEAT_LISP
3567 "lispindent",
3568#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003571#ifdef FEAT_LUA
3572# ifndef DYNAMIC_LUA
3573 "lua",
3574# endif
3575#endif
3576#ifdef FEAT_MENU
3577 "menu",
3578#endif
3579#ifdef FEAT_SESSION
3580 "mksession",
3581#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003583#ifdef FEAT_MOUSE
3584 "mouse",
3585#endif
3586#ifdef FEAT_MOUSESHAPE
3587 "mouseshape",
3588#endif
3589#if defined(UNIX) || defined(VMS)
3590# ifdef FEAT_MOUSE_DEC
3591 "mouse_dec",
3592# endif
3593# ifdef FEAT_MOUSE_GPM
3594 "mouse_gpm",
3595# endif
3596# ifdef FEAT_MOUSE_JSB
3597 "mouse_jsbterm",
3598# endif
3599# ifdef FEAT_MOUSE_NET
3600 "mouse_netterm",
3601# endif
3602# ifdef FEAT_MOUSE_PTERM
3603 "mouse_pterm",
3604# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003605# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003606 "mouse_sgr",
3607# endif
3608# ifdef FEAT_SYSMOUSE
3609 "mouse_sysmouse",
3610# endif
3611# ifdef FEAT_MOUSE_URXVT
3612 "mouse_urxvt",
3613# endif
3614# ifdef FEAT_MOUSE_XTERM
3615 "mouse_xterm",
3616# endif
3617#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003618 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003619#ifdef FEAT_MBYTE_IME
3620 "multi_byte_ime",
3621#endif
3622#ifdef FEAT_MULTI_LANG
3623 "multi_lang",
3624#endif
3625#ifdef FEAT_MZSCHEME
3626#ifndef DYNAMIC_MZSCHEME
3627 "mzscheme",
3628#endif
3629#endif
3630#ifdef FEAT_NUM64
3631 "num64",
3632#endif
3633#ifdef FEAT_OLE
3634 "ole",
3635#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003636#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003638#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003639#ifdef FEAT_PATH_EXTRA
3640 "path_extra",
3641#endif
3642#ifdef FEAT_PERL
3643#ifndef DYNAMIC_PERL
3644 "perl",
3645#endif
3646#endif
3647#ifdef FEAT_PERSISTENT_UNDO
3648 "persistent_undo",
3649#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003650#if defined(FEAT_PYTHON)
3651 "python_compiled",
3652# if defined(DYNAMIC_PYTHON)
3653 "python_dynamic",
3654# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003655 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003656 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003657# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003658#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003659#if defined(FEAT_PYTHON3)
3660 "python3_compiled",
3661# if defined(DYNAMIC_PYTHON3)
3662 "python3_dynamic",
3663# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003664 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003665 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003666# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003667#endif
3668#ifdef FEAT_POSTSCRIPT
3669 "postscript",
3670#endif
3671#ifdef FEAT_PRINTER
3672 "printer",
3673#endif
3674#ifdef FEAT_PROFILE
3675 "profile",
3676#endif
3677#ifdef FEAT_RELTIME
3678 "reltime",
3679#endif
3680#ifdef FEAT_QUICKFIX
3681 "quickfix",
3682#endif
3683#ifdef FEAT_RIGHTLEFT
3684 "rightleft",
3685#endif
3686#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3687 "ruby",
3688#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003689 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003690#ifdef FEAT_CMDL_INFO
3691 "showcmd",
3692 "cmdline_info",
3693#endif
3694#ifdef FEAT_SIGNS
3695 "signs",
3696#endif
3697#ifdef FEAT_SMARTINDENT
3698 "smartindent",
3699#endif
3700#ifdef STARTUPTIME
3701 "startuptime",
3702#endif
3703#ifdef FEAT_STL_OPT
3704 "statusline",
3705#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003706#ifdef FEAT_NETBEANS_INTG
3707 "netbeans_intg",
3708#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003709#ifdef FEAT_SOUND
3710 "sound",
3711#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003712#ifdef FEAT_SPELL
3713 "spell",
3714#endif
3715#ifdef FEAT_SYN_HL
3716 "syntax",
3717#endif
3718#if defined(USE_SYSTEM) || !defined(UNIX)
3719 "system",
3720#endif
3721#ifdef FEAT_TAG_BINS
3722 "tag_binary",
3723#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003724#ifdef FEAT_TCL
3725# ifndef DYNAMIC_TCL
3726 "tcl",
3727# endif
3728#endif
3729#ifdef FEAT_TERMGUICOLORS
3730 "termguicolors",
3731#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003732#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003733 "terminal",
3734#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735#ifdef TERMINFO
3736 "terminfo",
3737#endif
3738#ifdef FEAT_TERMRESPONSE
3739 "termresponse",
3740#endif
3741#ifdef FEAT_TEXTOBJ
3742 "textobjects",
3743#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003744#ifdef FEAT_TEXT_PROP
3745 "textprop",
3746#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747#ifdef HAVE_TGETENT
3748 "tgetent",
3749#endif
3750#ifdef FEAT_TIMERS
3751 "timers",
3752#endif
3753#ifdef FEAT_TITLE
3754 "title",
3755#endif
3756#ifdef FEAT_TOOLBAR
3757 "toolbar",
3758#endif
3759#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3760 "unnamedplus",
3761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003762 "user-commands", /* was accidentally included in 5.4 */
3763 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003764#ifdef FEAT_VARTABS
3765 "vartabs",
3766#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003767 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003768#ifdef FEAT_VIMINFO
3769 "viminfo",
3770#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003771 "vimscript-1",
3772 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003773 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003774 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003776 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003778#ifdef FEAT_VTP
3779 "vtp",
3780#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781#ifdef FEAT_WILDIGN
3782 "wildignore",
3783#endif
3784#ifdef FEAT_WILDMENU
3785 "wildmenu",
3786#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003788#ifdef FEAT_WAK
3789 "winaltkeys",
3790#endif
3791#ifdef FEAT_WRITEBACKUP
3792 "writebackup",
3793#endif
3794#ifdef FEAT_XIM
3795 "xim",
3796#endif
3797#ifdef FEAT_XFONTSET
3798 "xfontset",
3799#endif
3800#ifdef FEAT_XPM_W32
3801 "xpm",
3802 "xpm_w32", /* for backward compatibility */
3803#else
3804# if defined(HAVE_XPM)
3805 "xpm",
3806# endif
3807#endif
3808#ifdef USE_XSMP
3809 "xsmp",
3810#endif
3811#ifdef USE_XSMP_INTERACT
3812 "xsmp_interact",
3813#endif
3814#ifdef FEAT_XCLIPBOARD
3815 "xterm_clipboard",
3816#endif
3817#ifdef FEAT_XTERM_SAVE
3818 "xterm_save",
3819#endif
3820#if defined(UNIX) && defined(FEAT_X11)
3821 "X11",
3822#endif
3823 NULL
3824 };
3825
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003826 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003827 for (i = 0; has_list[i] != NULL; ++i)
3828 if (STRICMP(name, has_list[i]) == 0)
3829 {
3830 n = TRUE;
3831 break;
3832 }
3833
3834 if (n == FALSE)
3835 {
3836 if (STRNICMP(name, "patch", 5) == 0)
3837 {
3838 if (name[5] == '-'
3839 && STRLEN(name) >= 11
3840 && vim_isdigit(name[6])
3841 && vim_isdigit(name[8])
3842 && vim_isdigit(name[10]))
3843 {
3844 int major = atoi((char *)name + 6);
3845 int minor = atoi((char *)name + 8);
3846
3847 /* Expect "patch-9.9.01234". */
3848 n = (major < VIM_VERSION_MAJOR
3849 || (major == VIM_VERSION_MAJOR
3850 && (minor < VIM_VERSION_MINOR
3851 || (minor == VIM_VERSION_MINOR
3852 && has_patch(atoi((char *)name + 10))))));
3853 }
3854 else
3855 n = has_patch(atoi((char *)name + 5));
3856 }
3857 else if (STRICMP(name, "vim_starting") == 0)
3858 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003859 else if (STRICMP(name, "ttyin") == 0)
3860 n = mch_input_isatty();
3861 else if (STRICMP(name, "ttyout") == 0)
3862 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003863 else if (STRICMP(name, "multi_byte_encoding") == 0)
3864 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003865#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003866 else if (STRICMP(name, "balloon_multiline") == 0)
3867 n = multiline_balloon_available();
3868#endif
3869#ifdef DYNAMIC_TCL
3870 else if (STRICMP(name, "tcl") == 0)
3871 n = tcl_enabled(FALSE);
3872#endif
3873#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3874 else if (STRICMP(name, "iconv") == 0)
3875 n = iconv_enabled(FALSE);
3876#endif
3877#ifdef DYNAMIC_LUA
3878 else if (STRICMP(name, "lua") == 0)
3879 n = lua_enabled(FALSE);
3880#endif
3881#ifdef DYNAMIC_MZSCHEME
3882 else if (STRICMP(name, "mzscheme") == 0)
3883 n = mzscheme_enabled(FALSE);
3884#endif
3885#ifdef DYNAMIC_RUBY
3886 else if (STRICMP(name, "ruby") == 0)
3887 n = ruby_enabled(FALSE);
3888#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003889#ifdef DYNAMIC_PYTHON
3890 else if (STRICMP(name, "python") == 0)
3891 n = python_enabled(FALSE);
3892#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003893#ifdef DYNAMIC_PYTHON3
3894 else if (STRICMP(name, "python3") == 0)
3895 n = python3_enabled(FALSE);
3896#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003897#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3898 else if (STRICMP(name, "pythonx") == 0)
3899 {
3900# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3901 if (p_pyx == 0)
3902 n = python3_enabled(FALSE) || python_enabled(FALSE);
3903 else if (p_pyx == 3)
3904 n = python3_enabled(FALSE);
3905 else if (p_pyx == 2)
3906 n = python_enabled(FALSE);
3907# elif defined(DYNAMIC_PYTHON)
3908 n = python_enabled(FALSE);
3909# elif defined(DYNAMIC_PYTHON3)
3910 n = python3_enabled(FALSE);
3911# endif
3912 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003913#endif
3914#ifdef DYNAMIC_PERL
3915 else if (STRICMP(name, "perl") == 0)
3916 n = perl_enabled(FALSE);
3917#endif
3918#ifdef FEAT_GUI
3919 else if (STRICMP(name, "gui_running") == 0)
3920 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921# ifdef FEAT_BROWSE
3922 else if (STRICMP(name, "browse") == 0)
3923 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3924# endif
3925#endif
3926#ifdef FEAT_SYN_HL
3927 else if (STRICMP(name, "syntax_items") == 0)
3928 n = syntax_present(curwin);
3929#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003930#ifdef FEAT_VTP
3931 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003932 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933#endif
3934#ifdef FEAT_NETBEANS_INTG
3935 else if (STRICMP(name, "netbeans_enabled") == 0)
3936 n = netbeans_active();
3937#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003938#ifdef FEAT_MOUSE_GPM
3939 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3940 n = gpm_enabled();
3941#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003942#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003943 else if (STRICMP(name, "terminal") == 0)
3944 n = terminal_enabled();
3945#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003946#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003947 else if (STRICMP(name, "conpty") == 0)
3948 n = use_conpty();
3949#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003950#ifdef FEAT_CLIPBOARD
3951 else if (STRICMP(name, "clipboard_working") == 0)
3952 n = clip_star.available;
3953#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954 }
3955
3956 rettv->vval.v_number = n;
3957}
3958
3959/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003960 * "haslocaldir()" function
3961 */
3962 static void
3963f_haslocaldir(typval_T *argvars, typval_T *rettv)
3964{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003965 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003966 win_T *wp = NULL;
3967
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003968 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3969
3970 // Check for window-local and tab-local directories
3971 if (wp != NULL && wp->w_localdir != NULL)
3972 rettv->vval.v_number = 1;
3973 else if (tp != NULL && tp->tp_localdir != NULL)
3974 rettv->vval.v_number = 2;
3975 else
3976 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003977}
3978
3979/*
3980 * "hasmapto()" function
3981 */
3982 static void
3983f_hasmapto(typval_T *argvars, typval_T *rettv)
3984{
3985 char_u *name;
3986 char_u *mode;
3987 char_u buf[NUMBUFLEN];
3988 int abbr = FALSE;
3989
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003990 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003991 if (argvars[1].v_type == VAR_UNKNOWN)
3992 mode = (char_u *)"nvo";
3993 else
3994 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003995 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003996 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003997 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003998 }
3999
4000 if (map_to_exists(name, mode, abbr))
4001 rettv->vval.v_number = TRUE;
4002 else
4003 rettv->vval.v_number = FALSE;
4004}
4005
4006/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007 * "highlightID(name)" function
4008 */
4009 static void
4010f_hlID(typval_T *argvars, typval_T *rettv)
4011{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004012 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013}
4014
4015/*
4016 * "highlight_exists()" function
4017 */
4018 static void
4019f_hlexists(typval_T *argvars, typval_T *rettv)
4020{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004021 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004022}
4023
4024/*
4025 * "hostname()" function
4026 */
4027 static void
4028f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4029{
4030 char_u hostname[256];
4031
4032 mch_get_host_name(hostname, 256);
4033 rettv->v_type = VAR_STRING;
4034 rettv->vval.v_string = vim_strsave(hostname);
4035}
4036
4037/*
4038 * iconv() function
4039 */
4040 static void
4041f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4042{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004043 char_u buf1[NUMBUFLEN];
4044 char_u buf2[NUMBUFLEN];
4045 char_u *from, *to, *str;
4046 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004047
4048 rettv->v_type = VAR_STRING;
4049 rettv->vval.v_string = NULL;
4050
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004051 str = tv_get_string(&argvars[0]);
4052 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4053 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004054 vimconv.vc_type = CONV_NONE;
4055 convert_setup(&vimconv, from, to);
4056
4057 /* If the encodings are equal, no conversion needed. */
4058 if (vimconv.vc_type == CONV_NONE)
4059 rettv->vval.v_string = vim_strsave(str);
4060 else
4061 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4062
4063 convert_setup(&vimconv, NULL, NULL);
4064 vim_free(from);
4065 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004066}
4067
4068/*
4069 * "indent()" function
4070 */
4071 static void
4072f_indent(typval_T *argvars, typval_T *rettv)
4073{
4074 linenr_T lnum;
4075
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004076 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004077 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4078 rettv->vval.v_number = get_indent_lnum(lnum);
4079 else
4080 rettv->vval.v_number = -1;
4081}
4082
4083/*
4084 * "index()" function
4085 */
4086 static void
4087f_index(typval_T *argvars, typval_T *rettv)
4088{
4089 list_T *l;
4090 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004091 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004092 long idx = 0;
4093 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004094 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004095
4096 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004097 if (argvars[0].v_type == VAR_BLOB)
4098 {
4099 typval_T tv;
4100 int start = 0;
4101
4102 if (argvars[2].v_type != VAR_UNKNOWN)
4103 {
4104 start = tv_get_number_chk(&argvars[2], &error);
4105 if (error)
4106 return;
4107 }
4108 b = argvars[0].vval.v_blob;
4109 if (b == NULL)
4110 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004111 if (start < 0)
4112 {
4113 start = blob_len(b) + start;
4114 if (start < 0)
4115 start = 0;
4116 }
4117
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004118 for (idx = start; idx < blob_len(b); ++idx)
4119 {
4120 tv.v_type = VAR_NUMBER;
4121 tv.vval.v_number = blob_get(b, idx);
4122 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4123 {
4124 rettv->vval.v_number = idx;
4125 return;
4126 }
4127 }
4128 return;
4129 }
4130 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004131 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004132 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004133 return;
4134 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004135
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004136 l = argvars[0].vval.v_list;
4137 if (l != NULL)
4138 {
4139 item = l->lv_first;
4140 if (argvars[2].v_type != VAR_UNKNOWN)
4141 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004142 /* Start at specified item. Use the cached index that list_find()
4143 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004144 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004145 idx = l->lv_idx;
4146 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004147 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 if (error)
4149 item = NULL;
4150 }
4151
4152 for ( ; item != NULL; item = item->li_next, ++idx)
4153 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4154 {
4155 rettv->vval.v_number = idx;
4156 break;
4157 }
4158 }
4159}
4160
4161static int inputsecret_flag = 0;
4162
4163/*
4164 * "input()" function
4165 * Also handles inputsecret() when inputsecret is set.
4166 */
4167 static void
4168f_input(typval_T *argvars, typval_T *rettv)
4169{
4170 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4171}
4172
4173/*
4174 * "inputdialog()" function
4175 */
4176 static void
4177f_inputdialog(typval_T *argvars, typval_T *rettv)
4178{
4179#if defined(FEAT_GUI_TEXTDIALOG)
4180 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4181 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4182 {
4183 char_u *message;
4184 char_u buf[NUMBUFLEN];
4185 char_u *defstr = (char_u *)"";
4186
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004187 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004188 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004189 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004190 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4191 else
4192 IObuff[0] = NUL;
4193 if (message != NULL && defstr != NULL
4194 && do_dialog(VIM_QUESTION, NULL, message,
4195 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4196 rettv->vval.v_string = vim_strsave(IObuff);
4197 else
4198 {
4199 if (message != NULL && defstr != NULL
4200 && argvars[1].v_type != VAR_UNKNOWN
4201 && argvars[2].v_type != VAR_UNKNOWN)
4202 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004203 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004204 else
4205 rettv->vval.v_string = NULL;
4206 }
4207 rettv->v_type = VAR_STRING;
4208 }
4209 else
4210#endif
4211 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4212}
4213
4214/*
4215 * "inputlist()" function
4216 */
4217 static void
4218f_inputlist(typval_T *argvars, typval_T *rettv)
4219{
4220 listitem_T *li;
4221 int selected;
4222 int mouse_used;
4223
4224#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004225 /* While starting up, there is no place to enter text. When running tests
4226 * with --not-a-term we assume feedkeys() will be used. */
4227 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004228 return;
4229#endif
4230 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4231 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004232 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004233 return;
4234 }
4235
4236 msg_start();
4237 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4238 lines_left = Rows; /* avoid more prompt */
4239 msg_scroll = TRUE;
4240 msg_clr_eos();
4241
4242 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4243 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004244 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004245 msg_putchar('\n');
4246 }
4247
4248 /* Ask for choice. */
4249 selected = prompt_for_number(&mouse_used);
4250 if (mouse_used)
4251 selected -= lines_left;
4252
4253 rettv->vval.v_number = selected;
4254}
4255
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004256static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4257
4258/*
4259 * "inputrestore()" function
4260 */
4261 static void
4262f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4263{
4264 if (ga_userinput.ga_len > 0)
4265 {
4266 --ga_userinput.ga_len;
4267 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4268 + ga_userinput.ga_len);
4269 /* default return is zero == OK */
4270 }
4271 else if (p_verbose > 1)
4272 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004273 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004274 rettv->vval.v_number = 1; /* Failed */
4275 }
4276}
4277
4278/*
4279 * "inputsave()" function
4280 */
4281 static void
4282f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4283{
4284 /* Add an entry to the stack of typeahead storage. */
4285 if (ga_grow(&ga_userinput, 1) == OK)
4286 {
4287 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4288 + ga_userinput.ga_len);
4289 ++ga_userinput.ga_len;
4290 /* default return is zero == OK */
4291 }
4292 else
4293 rettv->vval.v_number = 1; /* Failed */
4294}
4295
4296/*
4297 * "inputsecret()" function
4298 */
4299 static void
4300f_inputsecret(typval_T *argvars, typval_T *rettv)
4301{
4302 ++cmdline_star;
4303 ++inputsecret_flag;
4304 f_input(argvars, rettv);
4305 --cmdline_star;
4306 --inputsecret_flag;
4307}
4308
4309/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004310 * "invert(expr)" function
4311 */
4312 static void
4313f_invert(typval_T *argvars, typval_T *rettv)
4314{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004315 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004316}
4317
4318/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004319 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4320 * or it refers to a List or Dictionary that is locked.
4321 */
4322 static int
4323tv_islocked(typval_T *tv)
4324{
4325 return (tv->v_lock & VAR_LOCKED)
4326 || (tv->v_type == VAR_LIST
4327 && tv->vval.v_list != NULL
4328 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4329 || (tv->v_type == VAR_DICT
4330 && tv->vval.v_dict != NULL
4331 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4332}
4333
4334/*
4335 * "islocked()" function
4336 */
4337 static void
4338f_islocked(typval_T *argvars, typval_T *rettv)
4339{
4340 lval_T lv;
4341 char_u *end;
4342 dictitem_T *di;
4343
4344 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004345 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004346 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004347 if (end != NULL && lv.ll_name != NULL)
4348 {
4349 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004350 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004351 else
4352 {
4353 if (lv.ll_tv == NULL)
4354 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004355 di = find_var(lv.ll_name, NULL, TRUE);
4356 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004357 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004358 /* Consider a variable locked when:
4359 * 1. the variable itself is locked
4360 * 2. the value of the variable is locked.
4361 * 3. the List or Dict value is locked.
4362 */
4363 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4364 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004365 }
4366 }
4367 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004368 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004369 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004370 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004371 else if (lv.ll_list != NULL)
4372 /* List item. */
4373 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4374 else
4375 /* Dictionary item. */
4376 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4377 }
4378 }
4379
4380 clear_lval(&lv);
4381}
4382
4383#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4384/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004385 * "isinf()" function
4386 */
4387 static void
4388f_isinf(typval_T *argvars, typval_T *rettv)
4389{
4390 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4391 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4392}
4393
4394/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004395 * "isnan()" function
4396 */
4397 static void
4398f_isnan(typval_T *argvars, typval_T *rettv)
4399{
4400 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4401 && isnan(argvars[0].vval.v_float);
4402}
4403#endif
4404
4405/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004406 * "last_buffer_nr()" function.
4407 */
4408 static void
4409f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4410{
4411 int n = 0;
4412 buf_T *buf;
4413
Bram Moolenaar29323592016-07-24 22:04:11 +02004414 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004415 if (n < buf->b_fnum)
4416 n = buf->b_fnum;
4417
4418 rettv->vval.v_number = n;
4419}
4420
4421/*
4422 * "len()" function
4423 */
4424 static void
4425f_len(typval_T *argvars, typval_T *rettv)
4426{
4427 switch (argvars[0].v_type)
4428 {
4429 case VAR_STRING:
4430 case VAR_NUMBER:
4431 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004432 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004433 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004434 case VAR_BLOB:
4435 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4436 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004437 case VAR_LIST:
4438 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4439 break;
4440 case VAR_DICT:
4441 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4442 break;
4443 case VAR_UNKNOWN:
4444 case VAR_SPECIAL:
4445 case VAR_FLOAT:
4446 case VAR_FUNC:
4447 case VAR_PARTIAL:
4448 case VAR_JOB:
4449 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004450 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004451 break;
4452 }
4453}
4454
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004455 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004456libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457{
4458#ifdef FEAT_LIBCALL
4459 char_u *string_in;
4460 char_u **string_result;
4461 int nr_result;
4462#endif
4463
4464 rettv->v_type = type;
4465 if (type != VAR_NUMBER)
4466 rettv->vval.v_string = NULL;
4467
4468 if (check_restricted() || check_secure())
4469 return;
4470
4471#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004472 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004473 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4474 {
4475 string_in = NULL;
4476 if (argvars[2].v_type == VAR_STRING)
4477 string_in = argvars[2].vval.v_string;
4478 if (type == VAR_NUMBER)
4479 string_result = NULL;
4480 else
4481 string_result = &rettv->vval.v_string;
4482 if (mch_libcall(argvars[0].vval.v_string,
4483 argvars[1].vval.v_string,
4484 string_in,
4485 argvars[2].vval.v_number,
4486 string_result,
4487 &nr_result) == OK
4488 && type == VAR_NUMBER)
4489 rettv->vval.v_number = nr_result;
4490 }
4491#endif
4492}
4493
4494/*
4495 * "libcall()" function
4496 */
4497 static void
4498f_libcall(typval_T *argvars, typval_T *rettv)
4499{
4500 libcall_common(argvars, rettv, VAR_STRING);
4501}
4502
4503/*
4504 * "libcallnr()" function
4505 */
4506 static void
4507f_libcallnr(typval_T *argvars, typval_T *rettv)
4508{
4509 libcall_common(argvars, rettv, VAR_NUMBER);
4510}
4511
4512/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004513 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004514 */
4515 static void
4516f_line(typval_T *argvars, typval_T *rettv)
4517{
4518 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004519 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004520 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004521 int id;
4522 tabpage_T *tp;
4523 win_T *wp;
4524 win_T *save_curwin;
4525 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004526
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004527 if (argvars[1].v_type != VAR_UNKNOWN)
4528 {
4529 // use window specified in the second argument
4530 id = (int)tv_get_number(&argvars[1]);
4531 wp = win_id2wp_tp(id, &tp);
4532 if (wp != NULL && tp != NULL)
4533 {
4534 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4535 == OK)
4536 {
4537 check_cursor();
4538 fp = var2fpos(&argvars[0], TRUE, &fnum);
4539 }
4540 restore_win_noblock(save_curwin, save_curtab, TRUE);
4541 }
4542 }
4543 else
4544 // use current window
4545 fp = var2fpos(&argvars[0], TRUE, &fnum);
4546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004547 if (fp != NULL)
4548 lnum = fp->lnum;
4549 rettv->vval.v_number = lnum;
4550}
4551
4552/*
4553 * "line2byte(lnum)" function
4554 */
4555 static void
4556f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4557{
4558#ifndef FEAT_BYTEOFF
4559 rettv->vval.v_number = -1;
4560#else
4561 linenr_T lnum;
4562
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004563 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004564 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4565 rettv->vval.v_number = -1;
4566 else
4567 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4568 if (rettv->vval.v_number >= 0)
4569 ++rettv->vval.v_number;
4570#endif
4571}
4572
4573/*
4574 * "lispindent(lnum)" function
4575 */
4576 static void
4577f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
4578{
4579#ifdef FEAT_LISP
4580 pos_T pos;
4581 linenr_T lnum;
4582
4583 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004584 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004585 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4586 {
4587 curwin->w_cursor.lnum = lnum;
4588 rettv->vval.v_number = get_lisp_indent();
4589 curwin->w_cursor = pos;
4590 }
4591 else
4592#endif
4593 rettv->vval.v_number = -1;
4594}
4595
4596/*
4597 * "localtime()" function
4598 */
4599 static void
4600f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4601{
4602 rettv->vval.v_number = (varnumber_T)time(NULL);
4603}
4604
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004605#ifdef FEAT_FLOAT
4606/*
4607 * "log()" function
4608 */
4609 static void
4610f_log(typval_T *argvars, typval_T *rettv)
4611{
4612 float_T f = 0.0;
4613
4614 rettv->v_type = VAR_FLOAT;
4615 if (get_float_arg(argvars, &f) == OK)
4616 rettv->vval.v_float = log(f);
4617 else
4618 rettv->vval.v_float = 0.0;
4619}
4620
4621/*
4622 * "log10()" function
4623 */
4624 static void
4625f_log10(typval_T *argvars, typval_T *rettv)
4626{
4627 float_T f = 0.0;
4628
4629 rettv->v_type = VAR_FLOAT;
4630 if (get_float_arg(argvars, &f) == OK)
4631 rettv->vval.v_float = log10(f);
4632 else
4633 rettv->vval.v_float = 0.0;
4634}
4635#endif
4636
4637#ifdef FEAT_LUA
4638/*
4639 * "luaeval()" function
4640 */
4641 static void
4642f_luaeval(typval_T *argvars, typval_T *rettv)
4643{
4644 char_u *str;
4645 char_u buf[NUMBUFLEN];
4646
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004647 if (check_restricted() || check_secure())
4648 return;
4649
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004650 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004651 do_luaeval(str, argvars + 1, rettv);
4652}
4653#endif
4654
4655/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004656 * "maparg()" function
4657 */
4658 static void
4659f_maparg(typval_T *argvars, typval_T *rettv)
4660{
4661 get_maparg(argvars, rettv, TRUE);
4662}
4663
4664/*
4665 * "mapcheck()" function
4666 */
4667 static void
4668f_mapcheck(typval_T *argvars, typval_T *rettv)
4669{
4670 get_maparg(argvars, rettv, FALSE);
4671}
4672
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004673typedef enum
4674{
4675 MATCH_END, /* matchend() */
4676 MATCH_MATCH, /* match() */
4677 MATCH_STR, /* matchstr() */
4678 MATCH_LIST, /* matchlist() */
4679 MATCH_POS /* matchstrpos() */
4680} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004681
4682 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004683find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004684{
4685 char_u *str = NULL;
4686 long len = 0;
4687 char_u *expr = NULL;
4688 char_u *pat;
4689 regmatch_T regmatch;
4690 char_u patbuf[NUMBUFLEN];
4691 char_u strbuf[NUMBUFLEN];
4692 char_u *save_cpo;
4693 long start = 0;
4694 long nth = 1;
4695 colnr_T startcol = 0;
4696 int match = 0;
4697 list_T *l = NULL;
4698 listitem_T *li = NULL;
4699 long idx = 0;
4700 char_u *tofree = NULL;
4701
4702 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4703 save_cpo = p_cpo;
4704 p_cpo = (char_u *)"";
4705
4706 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004707 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004708 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004709 /* type MATCH_LIST: return empty list when there are no matches.
4710 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004711 if (rettv_list_alloc(rettv) == FAIL)
4712 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004713 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004714 && (list_append_string(rettv->vval.v_list,
4715 (char_u *)"", 0) == FAIL
4716 || list_append_number(rettv->vval.v_list,
4717 (varnumber_T)-1) == FAIL
4718 || list_append_number(rettv->vval.v_list,
4719 (varnumber_T)-1) == FAIL
4720 || list_append_number(rettv->vval.v_list,
4721 (varnumber_T)-1) == FAIL))
4722 {
4723 list_free(rettv->vval.v_list);
4724 rettv->vval.v_list = NULL;
4725 goto theend;
4726 }
4727 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004728 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 {
4730 rettv->v_type = VAR_STRING;
4731 rettv->vval.v_string = NULL;
4732 }
4733
4734 if (argvars[0].v_type == VAR_LIST)
4735 {
4736 if ((l = argvars[0].vval.v_list) == NULL)
4737 goto theend;
4738 li = l->lv_first;
4739 }
4740 else
4741 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004742 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004743 len = (long)STRLEN(str);
4744 }
4745
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004746 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004747 if (pat == NULL)
4748 goto theend;
4749
4750 if (argvars[2].v_type != VAR_UNKNOWN)
4751 {
4752 int error = FALSE;
4753
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004754 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004755 if (error)
4756 goto theend;
4757 if (l != NULL)
4758 {
4759 li = list_find(l, start);
4760 if (li == NULL)
4761 goto theend;
4762 idx = l->lv_idx; /* use the cached index */
4763 }
4764 else
4765 {
4766 if (start < 0)
4767 start = 0;
4768 if (start > len)
4769 goto theend;
4770 /* When "count" argument is there ignore matches before "start",
4771 * otherwise skip part of the string. Differs when pattern is "^"
4772 * or "\<". */
4773 if (argvars[3].v_type != VAR_UNKNOWN)
4774 startcol = start;
4775 else
4776 {
4777 str += start;
4778 len -= start;
4779 }
4780 }
4781
4782 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004783 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004784 if (error)
4785 goto theend;
4786 }
4787
4788 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4789 if (regmatch.regprog != NULL)
4790 {
4791 regmatch.rm_ic = p_ic;
4792
4793 for (;;)
4794 {
4795 if (l != NULL)
4796 {
4797 if (li == NULL)
4798 {
4799 match = FALSE;
4800 break;
4801 }
4802 vim_free(tofree);
4803 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4804 if (str == NULL)
4805 break;
4806 }
4807
4808 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4809
4810 if (match && --nth <= 0)
4811 break;
4812 if (l == NULL && !match)
4813 break;
4814
4815 /* Advance to just after the match. */
4816 if (l != NULL)
4817 {
4818 li = li->li_next;
4819 ++idx;
4820 }
4821 else
4822 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004823 startcol = (colnr_T)(regmatch.startp[0]
4824 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004825 if (startcol > (colnr_T)len
4826 || str + startcol <= regmatch.startp[0])
4827 {
4828 match = FALSE;
4829 break;
4830 }
4831 }
4832 }
4833
4834 if (match)
4835 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004836 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004837 {
4838 listitem_T *li1 = rettv->vval.v_list->lv_first;
4839 listitem_T *li2 = li1->li_next;
4840 listitem_T *li3 = li2->li_next;
4841 listitem_T *li4 = li3->li_next;
4842
4843 vim_free(li1->li_tv.vval.v_string);
4844 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4845 (int)(regmatch.endp[0] - regmatch.startp[0]));
4846 li3->li_tv.vval.v_number =
4847 (varnumber_T)(regmatch.startp[0] - expr);
4848 li4->li_tv.vval.v_number =
4849 (varnumber_T)(regmatch.endp[0] - expr);
4850 if (l != NULL)
4851 li2->li_tv.vval.v_number = (varnumber_T)idx;
4852 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004853 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004854 {
4855 int i;
4856
4857 /* return list with matched string and submatches */
4858 for (i = 0; i < NSUBEXP; ++i)
4859 {
4860 if (regmatch.endp[i] == NULL)
4861 {
4862 if (list_append_string(rettv->vval.v_list,
4863 (char_u *)"", 0) == FAIL)
4864 break;
4865 }
4866 else if (list_append_string(rettv->vval.v_list,
4867 regmatch.startp[i],
4868 (int)(regmatch.endp[i] - regmatch.startp[i]))
4869 == FAIL)
4870 break;
4871 }
4872 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004873 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004874 {
4875 /* return matched string */
4876 if (l != NULL)
4877 copy_tv(&li->li_tv, rettv);
4878 else
4879 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4880 (int)(regmatch.endp[0] - regmatch.startp[0]));
4881 }
4882 else if (l != NULL)
4883 rettv->vval.v_number = idx;
4884 else
4885 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004886 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004887 rettv->vval.v_number =
4888 (varnumber_T)(regmatch.startp[0] - str);
4889 else
4890 rettv->vval.v_number =
4891 (varnumber_T)(regmatch.endp[0] - str);
4892 rettv->vval.v_number += (varnumber_T)(str - expr);
4893 }
4894 }
4895 vim_regfree(regmatch.regprog);
4896 }
4897
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004898theend:
4899 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004900 /* matchstrpos() without a list: drop the second item. */
4901 listitem_remove(rettv->vval.v_list,
4902 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 vim_free(tofree);
4904 p_cpo = save_cpo;
4905}
4906
4907/*
4908 * "match()" function
4909 */
4910 static void
4911f_match(typval_T *argvars, typval_T *rettv)
4912{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004913 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004914}
4915
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004916/*
4917 * "matchend()" function
4918 */
4919 static void
4920f_matchend(typval_T *argvars, typval_T *rettv)
4921{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004922 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004923}
4924
4925/*
4926 * "matchlist()" function
4927 */
4928 static void
4929f_matchlist(typval_T *argvars, typval_T *rettv)
4930{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004931 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004932}
4933
4934/*
4935 * "matchstr()" function
4936 */
4937 static void
4938f_matchstr(typval_T *argvars, typval_T *rettv)
4939{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004940 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004941}
4942
4943/*
4944 * "matchstrpos()" function
4945 */
4946 static void
4947f_matchstrpos(typval_T *argvars, typval_T *rettv)
4948{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004949 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004950}
4951
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004952 static void
4953max_min(typval_T *argvars, typval_T *rettv, int domax)
4954{
4955 varnumber_T n = 0;
4956 varnumber_T i;
4957 int error = FALSE;
4958
4959 if (argvars[0].v_type == VAR_LIST)
4960 {
4961 list_T *l;
4962 listitem_T *li;
4963
4964 l = argvars[0].vval.v_list;
4965 if (l != NULL)
4966 {
4967 li = l->lv_first;
4968 if (li != NULL)
4969 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004970 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004971 for (;;)
4972 {
4973 li = li->li_next;
4974 if (li == NULL)
4975 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004976 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004977 if (domax ? i > n : i < n)
4978 n = i;
4979 }
4980 }
4981 }
4982 }
4983 else if (argvars[0].v_type == VAR_DICT)
4984 {
4985 dict_T *d;
4986 int first = TRUE;
4987 hashitem_T *hi;
4988 int todo;
4989
4990 d = argvars[0].vval.v_dict;
4991 if (d != NULL)
4992 {
4993 todo = (int)d->dv_hashtab.ht_used;
4994 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4995 {
4996 if (!HASHITEM_EMPTY(hi))
4997 {
4998 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004999 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000 if (first)
5001 {
5002 n = i;
5003 first = FALSE;
5004 }
5005 else if (domax ? i > n : i < n)
5006 n = i;
5007 }
5008 }
5009 }
5010 }
5011 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005012 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005013 rettv->vval.v_number = error ? 0 : n;
5014}
5015
5016/*
5017 * "max()" function
5018 */
5019 static void
5020f_max(typval_T *argvars, typval_T *rettv)
5021{
5022 max_min(argvars, rettv, TRUE);
5023}
5024
5025/*
5026 * "min()" function
5027 */
5028 static void
5029f_min(typval_T *argvars, typval_T *rettv)
5030{
5031 max_min(argvars, rettv, FALSE);
5032}
5033
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035 * "mode()" function
5036 */
5037 static void
5038f_mode(typval_T *argvars, typval_T *rettv)
5039{
Bram Moolenaar612cc382018-07-29 15:34:26 +02005040 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005041
Bram Moolenaar612cc382018-07-29 15:34:26 +02005042 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005043
5044 if (time_for_testing == 93784)
5045 {
5046 /* Testing the two-character code. */
5047 buf[0] = 'x';
5048 buf[1] = '!';
5049 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02005050#ifdef FEAT_TERMINAL
5051 else if (term_use_loop())
5052 buf[0] = 't';
5053#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005054 else if (VIsual_active)
5055 {
5056 if (VIsual_select)
5057 buf[0] = VIsual_mode + 's' - 'v';
5058 else
5059 buf[0] = VIsual_mode;
5060 }
5061 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
5062 || State == CONFIRM)
5063 {
5064 buf[0] = 'r';
5065 if (State == ASKMORE)
5066 buf[1] = 'm';
5067 else if (State == CONFIRM)
5068 buf[1] = '?';
5069 }
5070 else if (State == EXTERNCMD)
5071 buf[0] = '!';
5072 else if (State & INSERT)
5073 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005074 if (State & VREPLACE_FLAG)
5075 {
5076 buf[0] = 'R';
5077 buf[1] = 'v';
5078 }
5079 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01005080 {
5081 if (State & REPLACE_FLAG)
5082 buf[0] = 'R';
5083 else
5084 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005085 if (ins_compl_active())
5086 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01005087 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01005088 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005089 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005090 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01005091 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005092 {
5093 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005094 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005095 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01005096 else if (exmode_active == EXMODE_NORMAL)
5097 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005098 }
5099 else
5100 {
5101 buf[0] = 'n';
5102 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01005103 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01005105 // to be able to detect force-linewise/blockwise/characterwise operations
5106 buf[2] = motion_force;
5107 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02005108 else if (restart_edit == 'I' || restart_edit == 'R'
5109 || restart_edit == 'V')
5110 {
5111 buf[1] = 'i';
5112 buf[2] = restart_edit;
5113 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114 }
5115
5116 /* Clear out the minor mode when the argument is not a non-zero number or
5117 * non-empty string. */
5118 if (!non_zero_arg(&argvars[0]))
5119 buf[1] = NUL;
5120
5121 rettv->vval.v_string = vim_strsave(buf);
5122 rettv->v_type = VAR_STRING;
5123}
5124
5125#if defined(FEAT_MZSCHEME) || defined(PROTO)
5126/*
5127 * "mzeval()" function
5128 */
5129 static void
5130f_mzeval(typval_T *argvars, typval_T *rettv)
5131{
5132 char_u *str;
5133 char_u buf[NUMBUFLEN];
5134
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005135 if (check_restricted() || check_secure())
5136 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005137 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005138 do_mzeval(str, rettv);
5139}
5140
5141 void
5142mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5143{
5144 typval_T argvars[3];
5145
5146 argvars[0].v_type = VAR_STRING;
5147 argvars[0].vval.v_string = name;
5148 copy_tv(args, &argvars[1]);
5149 argvars[2].v_type = VAR_UNKNOWN;
5150 f_call(argvars, rettv);
5151 clear_tv(&argvars[1]);
5152}
5153#endif
5154
5155/*
5156 * "nextnonblank()" function
5157 */
5158 static void
5159f_nextnonblank(typval_T *argvars, typval_T *rettv)
5160{
5161 linenr_T lnum;
5162
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005163 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005164 {
5165 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5166 {
5167 lnum = 0;
5168 break;
5169 }
5170 if (*skipwhite(ml_get(lnum)) != NUL)
5171 break;
5172 }
5173 rettv->vval.v_number = lnum;
5174}
5175
5176/*
5177 * "nr2char()" function
5178 */
5179 static void
5180f_nr2char(typval_T *argvars, typval_T *rettv)
5181{
5182 char_u buf[NUMBUFLEN];
5183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005184 if (has_mbyte)
5185 {
5186 int utf8 = 0;
5187
5188 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005189 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005190 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005191 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005192 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005193 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005194 }
5195 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005196 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005197 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005198 buf[1] = NUL;
5199 }
5200 rettv->v_type = VAR_STRING;
5201 rettv->vval.v_string = vim_strsave(buf);
5202}
5203
5204/*
5205 * "or(expr, expr)" function
5206 */
5207 static void
5208f_or(typval_T *argvars, typval_T *rettv)
5209{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005210 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5211 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005212}
5213
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005214#ifdef FEAT_PERL
5215/*
5216 * "perleval()" function
5217 */
5218 static void
5219f_perleval(typval_T *argvars, typval_T *rettv)
5220{
5221 char_u *str;
5222 char_u buf[NUMBUFLEN];
5223
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005224 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005225 do_perleval(str, rettv);
5226}
5227#endif
5228
5229#ifdef FEAT_FLOAT
5230/*
5231 * "pow()" function
5232 */
5233 static void
5234f_pow(typval_T *argvars, typval_T *rettv)
5235{
5236 float_T fx = 0.0, fy = 0.0;
5237
5238 rettv->v_type = VAR_FLOAT;
5239 if (get_float_arg(argvars, &fx) == OK
5240 && get_float_arg(&argvars[1], &fy) == OK)
5241 rettv->vval.v_float = pow(fx, fy);
5242 else
5243 rettv->vval.v_float = 0.0;
5244}
5245#endif
5246
5247/*
5248 * "prevnonblank()" function
5249 */
5250 static void
5251f_prevnonblank(typval_T *argvars, typval_T *rettv)
5252{
5253 linenr_T lnum;
5254
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005255 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005256 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5257 lnum = 0;
5258 else
5259 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5260 --lnum;
5261 rettv->vval.v_number = lnum;
5262}
5263
5264/* This dummy va_list is here because:
5265 * - passing a NULL pointer doesn't work when va_list isn't a pointer
5266 * - locally in the function results in a "used before set" warning
5267 * - using va_start() to initialize it gives "function with fixed args" error */
5268static va_list ap;
5269
5270/*
5271 * "printf()" function
5272 */
5273 static void
5274f_printf(typval_T *argvars, typval_T *rettv)
5275{
5276 char_u buf[NUMBUFLEN];
5277 int len;
5278 char_u *s;
5279 int saved_did_emsg = did_emsg;
5280 char *fmt;
5281
5282 rettv->v_type = VAR_STRING;
5283 rettv->vval.v_string = NULL;
5284
5285 /* Get the required length, allocate the buffer and do it for real. */
5286 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005287 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005288 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005289 if (!did_emsg)
5290 {
5291 s = alloc(len + 1);
5292 if (s != NULL)
5293 {
5294 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005295 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5296 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005297 }
5298 }
5299 did_emsg |= saved_did_emsg;
5300}
5301
5302/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005303 * "pum_getpos()" function
5304 */
5305 static void
5306f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5307{
5308 if (rettv_dict_alloc(rettv) != OK)
5309 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005310 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005311}
5312
5313/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005314 * "pumvisible()" function
5315 */
5316 static void
5317f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5318{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005319 if (pum_visible())
5320 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005321}
5322
5323#ifdef FEAT_PYTHON3
5324/*
5325 * "py3eval()" function
5326 */
5327 static void
5328f_py3eval(typval_T *argvars, typval_T *rettv)
5329{
5330 char_u *str;
5331 char_u buf[NUMBUFLEN];
5332
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005333 if (check_restricted() || check_secure())
5334 return;
5335
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005336 if (p_pyx == 0)
5337 p_pyx = 3;
5338
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005339 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005340 do_py3eval(str, rettv);
5341}
5342#endif
5343
5344#ifdef FEAT_PYTHON
5345/*
5346 * "pyeval()" function
5347 */
5348 static void
5349f_pyeval(typval_T *argvars, typval_T *rettv)
5350{
5351 char_u *str;
5352 char_u buf[NUMBUFLEN];
5353
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005354 if (check_restricted() || check_secure())
5355 return;
5356
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005357 if (p_pyx == 0)
5358 p_pyx = 2;
5359
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005360 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361 do_pyeval(str, rettv);
5362}
5363#endif
5364
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005365#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5366/*
5367 * "pyxeval()" function
5368 */
5369 static void
5370f_pyxeval(typval_T *argvars, typval_T *rettv)
5371{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005372 if (check_restricted() || check_secure())
5373 return;
5374
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005375# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5376 init_pyxversion();
5377 if (p_pyx == 2)
5378 f_pyeval(argvars, rettv);
5379 else
5380 f_py3eval(argvars, rettv);
5381# elif defined(FEAT_PYTHON)
5382 f_pyeval(argvars, rettv);
5383# elif defined(FEAT_PYTHON3)
5384 f_py3eval(argvars, rettv);
5385# endif
5386}
5387#endif
5388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005389/*
5390 * "range()" function
5391 */
5392 static void
5393f_range(typval_T *argvars, typval_T *rettv)
5394{
5395 varnumber_T start;
5396 varnumber_T end;
5397 varnumber_T stride = 1;
5398 varnumber_T i;
5399 int error = FALSE;
5400
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005401 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005402 if (argvars[1].v_type == VAR_UNKNOWN)
5403 {
5404 end = start - 1;
5405 start = 0;
5406 }
5407 else
5408 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005409 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005410 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005411 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005412 }
5413
5414 if (error)
5415 return; /* type error; errmsg already given */
5416 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005417 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005418 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005419 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005420 else
5421 {
5422 if (rettv_list_alloc(rettv) == OK)
5423 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5424 if (list_append_number(rettv->vval.v_list,
5425 (varnumber_T)i) == FAIL)
5426 break;
5427 }
5428}
5429
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005430 static void
5431return_register(int regname, typval_T *rettv)
5432{
5433 char_u buf[2] = {0, 0};
5434
5435 buf[0] = (char_u)regname;
5436 rettv->v_type = VAR_STRING;
5437 rettv->vval.v_string = vim_strsave(buf);
5438}
5439
5440/*
5441 * "reg_executing()" function
5442 */
5443 static void
5444f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5445{
5446 return_register(reg_executing, rettv);
5447}
5448
5449/*
5450 * "reg_recording()" function
5451 */
5452 static void
5453f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5454{
5455 return_register(reg_recording, rettv);
5456}
5457
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005458#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005459/*
5460 * Convert a List to proftime_T.
5461 * Return FAIL when there is something wrong.
5462 */
5463 static int
5464list2proftime(typval_T *arg, proftime_T *tm)
5465{
5466 long n1, n2;
5467 int error = FALSE;
5468
5469 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5470 || arg->vval.v_list->lv_len != 2)
5471 return FAIL;
5472 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5473 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005474# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005475 tm->HighPart = n1;
5476 tm->LowPart = n2;
5477# else
5478 tm->tv_sec = n1;
5479 tm->tv_usec = n2;
5480# endif
5481 return error ? FAIL : OK;
5482}
5483#endif /* FEAT_RELTIME */
5484
5485/*
5486 * "reltime()" function
5487 */
5488 static void
5489f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5490{
5491#ifdef FEAT_RELTIME
5492 proftime_T res;
5493 proftime_T start;
5494
5495 if (argvars[0].v_type == VAR_UNKNOWN)
5496 {
5497 /* No arguments: get current time. */
5498 profile_start(&res);
5499 }
5500 else if (argvars[1].v_type == VAR_UNKNOWN)
5501 {
5502 if (list2proftime(&argvars[0], &res) == FAIL)
5503 return;
5504 profile_end(&res);
5505 }
5506 else
5507 {
5508 /* Two arguments: compute the difference. */
5509 if (list2proftime(&argvars[0], &start) == FAIL
5510 || list2proftime(&argvars[1], &res) == FAIL)
5511 return;
5512 profile_sub(&res, &start);
5513 }
5514
5515 if (rettv_list_alloc(rettv) == OK)
5516 {
5517 long n1, n2;
5518
Bram Moolenaar4f974752019-02-17 17:44:42 +01005519# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005520 n1 = res.HighPart;
5521 n2 = res.LowPart;
5522# else
5523 n1 = res.tv_sec;
5524 n2 = res.tv_usec;
5525# endif
5526 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5527 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5528 }
5529#endif
5530}
5531
5532#ifdef FEAT_FLOAT
5533/*
5534 * "reltimefloat()" function
5535 */
5536 static void
5537f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5538{
5539# ifdef FEAT_RELTIME
5540 proftime_T tm;
5541# endif
5542
5543 rettv->v_type = VAR_FLOAT;
5544 rettv->vval.v_float = 0;
5545# ifdef FEAT_RELTIME
5546 if (list2proftime(&argvars[0], &tm) == OK)
5547 rettv->vval.v_float = profile_float(&tm);
5548# endif
5549}
5550#endif
5551
5552/*
5553 * "reltimestr()" function
5554 */
5555 static void
5556f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5557{
5558#ifdef FEAT_RELTIME
5559 proftime_T tm;
5560#endif
5561
5562 rettv->v_type = VAR_STRING;
5563 rettv->vval.v_string = NULL;
5564#ifdef FEAT_RELTIME
5565 if (list2proftime(&argvars[0], &tm) == OK)
5566 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5567#endif
5568}
5569
5570#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005571 static void
5572make_connection(void)
5573{
5574 if (X_DISPLAY == NULL
5575# ifdef FEAT_GUI
5576 && !gui.in_use
5577# endif
5578 )
5579 {
5580 x_force_connect = TRUE;
5581 setup_term_clip();
5582 x_force_connect = FALSE;
5583 }
5584}
5585
5586 static int
5587check_connection(void)
5588{
5589 make_connection();
5590 if (X_DISPLAY == NULL)
5591 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005592 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005593 return FAIL;
5594 }
5595 return OK;
5596}
5597#endif
5598
5599#ifdef FEAT_CLIENTSERVER
5600 static void
5601remote_common(typval_T *argvars, typval_T *rettv, int expr)
5602{
5603 char_u *server_name;
5604 char_u *keys;
5605 char_u *r = NULL;
5606 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005607 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005608# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005609 HWND w;
5610# else
5611 Window w;
5612# endif
5613
5614 if (check_restricted() || check_secure())
5615 return;
5616
5617# ifdef FEAT_X11
5618 if (check_connection() == FAIL)
5619 return;
5620# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005621 if (argvars[2].v_type != VAR_UNKNOWN
5622 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005623 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005624
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005625 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005626 if (server_name == NULL)
5627 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005628 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005629# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005630 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005632 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5633 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005634# endif
5635 {
5636 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005637 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005638 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005639 vim_free(r);
5640 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005641 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005642 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005643 return;
5644 }
5645
5646 rettv->vval.v_string = r;
5647
5648 if (argvars[2].v_type != VAR_UNKNOWN)
5649 {
5650 dictitem_T v;
5651 char_u str[30];
5652 char_u *idvar;
5653
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005654 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005655 if (idvar != NULL && *idvar != NUL)
5656 {
5657 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5658 v.di_tv.v_type = VAR_STRING;
5659 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005660 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005661 vim_free(v.di_tv.vval.v_string);
5662 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005663 }
5664}
5665#endif
5666
5667/*
5668 * "remote_expr()" function
5669 */
5670 static void
5671f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5672{
5673 rettv->v_type = VAR_STRING;
5674 rettv->vval.v_string = NULL;
5675#ifdef FEAT_CLIENTSERVER
5676 remote_common(argvars, rettv, TRUE);
5677#endif
5678}
5679
5680/*
5681 * "remote_foreground()" function
5682 */
5683 static void
5684f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5685{
5686#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005687# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005688 /* On Win32 it's done in this application. */
5689 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005690 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691
5692 if (server_name != NULL)
5693 serverForeground(server_name);
5694 }
5695# else
5696 /* Send a foreground() expression to the server. */
5697 argvars[1].v_type = VAR_STRING;
5698 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5699 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005700 rettv->v_type = VAR_STRING;
5701 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005702 remote_common(argvars, rettv, TRUE);
5703 vim_free(argvars[1].vval.v_string);
5704# endif
5705#endif
5706}
5707
5708 static void
5709f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5710{
5711#ifdef FEAT_CLIENTSERVER
5712 dictitem_T v;
5713 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005714# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005715 long_u n = 0;
5716# endif
5717 char_u *serverid;
5718
5719 if (check_restricted() || check_secure())
5720 {
5721 rettv->vval.v_number = -1;
5722 return;
5723 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005724 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005725 if (serverid == NULL)
5726 {
5727 rettv->vval.v_number = -1;
5728 return; /* type error; errmsg already given */
5729 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005730# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005731 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5732 if (n == 0)
5733 rettv->vval.v_number = -1;
5734 else
5735 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005736 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005737 rettv->vval.v_number = (s != NULL);
5738 }
5739# else
5740 if (check_connection() == FAIL)
5741 return;
5742
5743 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5744 serverStrToWin(serverid), &s);
5745# endif
5746
5747 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5748 {
5749 char_u *retvar;
5750
5751 v.di_tv.v_type = VAR_STRING;
5752 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005753 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005754 if (retvar != NULL)
5755 set_var(retvar, &v.di_tv, FALSE);
5756 vim_free(v.di_tv.vval.v_string);
5757 }
5758#else
5759 rettv->vval.v_number = -1;
5760#endif
5761}
5762
5763 static void
5764f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5765{
5766 char_u *r = NULL;
5767
5768#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005769 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005770
5771 if (serverid != NULL && !check_restricted() && !check_secure())
5772 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005773 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005774# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005775 /* The server's HWND is encoded in the 'id' parameter */
5776 long_u n = 0;
5777# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005778
5779 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005780 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005781
Bram Moolenaar4f974752019-02-17 17:44:42 +01005782# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5784 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005785 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005786 if (r == NULL)
5787# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005788 if (check_connection() == FAIL
5789 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5790 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005792 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005793 }
5794#endif
5795 rettv->v_type = VAR_STRING;
5796 rettv->vval.v_string = r;
5797}
5798
5799/*
5800 * "remote_send()" function
5801 */
5802 static void
5803f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5804{
5805 rettv->v_type = VAR_STRING;
5806 rettv->vval.v_string = NULL;
5807#ifdef FEAT_CLIENTSERVER
5808 remote_common(argvars, rettv, FALSE);
5809#endif
5810}
5811
5812/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005813 * "remote_startserver()" function
5814 */
5815 static void
5816f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5817{
5818#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005819 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005820
5821 if (server == NULL)
5822 return; /* type error; errmsg already given */
5823 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005824 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005825 else
5826 {
5827# ifdef FEAT_X11
5828 if (check_connection() == OK)
5829 serverRegisterName(X_DISPLAY, server);
5830# else
5831 serverSetName(server);
5832# endif
5833 }
5834#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005835 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005836#endif
5837}
5838
5839/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005840 * "rename({from}, {to})" function
5841 */
5842 static void
5843f_rename(typval_T *argvars, typval_T *rettv)
5844{
5845 char_u buf[NUMBUFLEN];
5846
5847 if (check_restricted() || check_secure())
5848 rettv->vval.v_number = -1;
5849 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005850 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5851 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005852}
5853
5854/*
5855 * "repeat()" function
5856 */
5857 static void
5858f_repeat(typval_T *argvars, typval_T *rettv)
5859{
5860 char_u *p;
5861 int n;
5862 int slen;
5863 int len;
5864 char_u *r;
5865 int i;
5866
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005867 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 if (argvars[0].v_type == VAR_LIST)
5869 {
5870 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5871 while (n-- > 0)
5872 if (list_extend(rettv->vval.v_list,
5873 argvars[0].vval.v_list, NULL) == FAIL)
5874 break;
5875 }
5876 else
5877 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005878 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005879 rettv->v_type = VAR_STRING;
5880 rettv->vval.v_string = NULL;
5881
5882 slen = (int)STRLEN(p);
5883 len = slen * n;
5884 if (len <= 0)
5885 return;
5886
5887 r = alloc(len + 1);
5888 if (r != NULL)
5889 {
5890 for (i = 0; i < n; i++)
5891 mch_memmove(r + i * slen, p, (size_t)slen);
5892 r[len] = NUL;
5893 }
5894
5895 rettv->vval.v_string = r;
5896 }
5897}
5898
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005899#define SP_NOMOVE 0x01 /* don't move cursor */
5900#define SP_REPEAT 0x02 /* repeat to find outer pair */
5901#define SP_RETCOUNT 0x04 /* return matchcount */
5902#define SP_SETPCMARK 0x08 /* set previous context mark */
5903#define SP_START 0x10 /* accept match at start position */
5904#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5905#define SP_END 0x40 /* leave cursor at end of match */
5906#define SP_COLUMN 0x80 /* start at cursor column */
5907
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005908/*
5909 * Get flags for a search function.
5910 * Possibly sets "p_ws".
5911 * Returns BACKWARD, FORWARD or zero (for an error).
5912 */
5913 static int
5914get_search_arg(typval_T *varp, int *flagsp)
5915{
5916 int dir = FORWARD;
5917 char_u *flags;
5918 char_u nbuf[NUMBUFLEN];
5919 int mask;
5920
5921 if (varp->v_type != VAR_UNKNOWN)
5922 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005923 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005924 if (flags == NULL)
5925 return 0; /* type error; errmsg already given */
5926 while (*flags != NUL)
5927 {
5928 switch (*flags)
5929 {
5930 case 'b': dir = BACKWARD; break;
5931 case 'w': p_ws = TRUE; break;
5932 case 'W': p_ws = FALSE; break;
5933 default: mask = 0;
5934 if (flagsp != NULL)
5935 switch (*flags)
5936 {
5937 case 'c': mask = SP_START; break;
5938 case 'e': mask = SP_END; break;
5939 case 'm': mask = SP_RETCOUNT; break;
5940 case 'n': mask = SP_NOMOVE; break;
5941 case 'p': mask = SP_SUBPAT; break;
5942 case 'r': mask = SP_REPEAT; break;
5943 case 's': mask = SP_SETPCMARK; break;
5944 case 'z': mask = SP_COLUMN; break;
5945 }
5946 if (mask == 0)
5947 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005948 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005949 dir = 0;
5950 }
5951 else
5952 *flagsp |= mask;
5953 }
5954 if (dir == 0)
5955 break;
5956 ++flags;
5957 }
5958 }
5959 return dir;
5960}
5961
5962/*
5963 * Shared by search() and searchpos() functions.
5964 */
5965 static int
5966search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5967{
5968 int flags;
5969 char_u *pat;
5970 pos_T pos;
5971 pos_T save_cursor;
5972 int save_p_ws = p_ws;
5973 int dir;
5974 int retval = 0; /* default: FAIL */
5975 long lnum_stop = 0;
5976 proftime_T tm;
5977#ifdef FEAT_RELTIME
5978 long time_limit = 0;
5979#endif
5980 int options = SEARCH_KEEP;
5981 int subpatnum;
5982
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005983 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005984 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5985 if (dir == 0)
5986 goto theend;
5987 flags = *flagsp;
5988 if (flags & SP_START)
5989 options |= SEARCH_START;
5990 if (flags & SP_END)
5991 options |= SEARCH_END;
5992 if (flags & SP_COLUMN)
5993 options |= SEARCH_COL;
5994
5995 /* Optional arguments: line number to stop searching and timeout. */
5996 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5997 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005998 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005999 if (lnum_stop < 0)
6000 goto theend;
6001#ifdef FEAT_RELTIME
6002 if (argvars[3].v_type != VAR_UNKNOWN)
6003 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006004 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006005 if (time_limit < 0)
6006 goto theend;
6007 }
6008#endif
6009 }
6010
6011#ifdef FEAT_RELTIME
6012 /* Set the time limit, if there is one. */
6013 profile_setlimit(time_limit, &tm);
6014#endif
6015
6016 /*
6017 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6018 * Check to make sure only those flags are set.
6019 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6020 * flags cannot be set. Check for that condition also.
6021 */
6022 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6023 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6024 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006025 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006026 goto theend;
6027 }
6028
6029 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006030 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006031 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006032 if (subpatnum != FAIL)
6033 {
6034 if (flags & SP_SUBPAT)
6035 retval = subpatnum;
6036 else
6037 retval = pos.lnum;
6038 if (flags & SP_SETPCMARK)
6039 setpcmark();
6040 curwin->w_cursor = pos;
6041 if (match_pos != NULL)
6042 {
6043 /* Store the match cursor position */
6044 match_pos->lnum = pos.lnum;
6045 match_pos->col = pos.col + 1;
6046 }
6047 /* "/$" will put the cursor after the end of the line, may need to
6048 * correct that here */
6049 check_cursor();
6050 }
6051
6052 /* If 'n' flag is used: restore cursor position. */
6053 if (flags & SP_NOMOVE)
6054 curwin->w_cursor = save_cursor;
6055 else
6056 curwin->w_set_curswant = TRUE;
6057theend:
6058 p_ws = save_p_ws;
6059
6060 return retval;
6061}
6062
6063#ifdef FEAT_FLOAT
6064
6065/*
6066 * round() is not in C90, use ceil() or floor() instead.
6067 */
6068 float_T
6069vim_round(float_T f)
6070{
6071 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6072}
6073
6074/*
6075 * "round({float})" function
6076 */
6077 static void
6078f_round(typval_T *argvars, typval_T *rettv)
6079{
6080 float_T f = 0.0;
6081
6082 rettv->v_type = VAR_FLOAT;
6083 if (get_float_arg(argvars, &f) == OK)
6084 rettv->vval.v_float = vim_round(f);
6085 else
6086 rettv->vval.v_float = 0.0;
6087}
6088#endif
6089
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006090#ifdef FEAT_RUBY
6091/*
6092 * "rubyeval()" function
6093 */
6094 static void
6095f_rubyeval(typval_T *argvars, typval_T *rettv)
6096{
6097 char_u *str;
6098 char_u buf[NUMBUFLEN];
6099
6100 str = tv_get_string_buf(&argvars[0], buf);
6101 do_rubyeval(str, rettv);
6102}
6103#endif
6104
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006105/*
6106 * "screenattr()" function
6107 */
6108 static void
6109f_screenattr(typval_T *argvars, typval_T *rettv)
6110{
6111 int row;
6112 int col;
6113 int c;
6114
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006115 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6116 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006117 if (row < 0 || row >= screen_Rows
6118 || col < 0 || col >= screen_Columns)
6119 c = -1;
6120 else
6121 c = ScreenAttrs[LineOffset[row] + col];
6122 rettv->vval.v_number = c;
6123}
6124
6125/*
6126 * "screenchar()" function
6127 */
6128 static void
6129f_screenchar(typval_T *argvars, typval_T *rettv)
6130{
6131 int row;
6132 int col;
6133 int off;
6134 int c;
6135
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006136 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6137 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006138 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006139 c = -1;
6140 else
6141 {
6142 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143 if (enc_utf8 && ScreenLinesUC[off] != 0)
6144 c = ScreenLinesUC[off];
6145 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006146 c = ScreenLines[off];
6147 }
6148 rettv->vval.v_number = c;
6149}
6150
6151/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006152 * "screenchars()" function
6153 */
6154 static void
6155f_screenchars(typval_T *argvars, typval_T *rettv)
6156{
6157 int row;
6158 int col;
6159 int off;
6160 int c;
6161 int i;
6162
6163 if (rettv_list_alloc(rettv) == FAIL)
6164 return;
6165 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6166 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6167 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6168 return;
6169
6170 off = LineOffset[row] + col;
6171 if (enc_utf8 && ScreenLinesUC[off] != 0)
6172 c = ScreenLinesUC[off];
6173 else
6174 c = ScreenLines[off];
6175 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6176
6177 if (enc_utf8)
6178
6179 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6180 list_append_number(rettv->vval.v_list,
6181 (varnumber_T)ScreenLinesC[i][off]);
6182}
6183
6184/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 * "screencol()" function
6186 *
6187 * First column is 1 to be consistent with virtcol().
6188 */
6189 static void
6190f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6191{
6192 rettv->vval.v_number = screen_screencol() + 1;
6193}
6194
6195/*
6196 * "screenrow()" function
6197 */
6198 static void
6199f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6200{
6201 rettv->vval.v_number = screen_screenrow() + 1;
6202}
6203
6204/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006205 * "screenstring()" function
6206 */
6207 static void
6208f_screenstring(typval_T *argvars, typval_T *rettv)
6209{
6210 int row;
6211 int col;
6212 int off;
6213 int c;
6214 int i;
6215 char_u buf[MB_MAXBYTES + 1];
6216 int buflen = 0;
6217
6218 rettv->vval.v_string = NULL;
6219 rettv->v_type = VAR_STRING;
6220
6221 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6222 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6223 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6224 return;
6225
6226 off = LineOffset[row] + col;
6227 if (enc_utf8 && ScreenLinesUC[off] != 0)
6228 c = ScreenLinesUC[off];
6229 else
6230 c = ScreenLines[off];
6231 buflen += mb_char2bytes(c, buf);
6232
6233 if (enc_utf8)
6234 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6235 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6236
6237 buf[buflen] = NUL;
6238 rettv->vval.v_string = vim_strsave(buf);
6239}
6240
6241/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006242 * "search()" function
6243 */
6244 static void
6245f_search(typval_T *argvars, typval_T *rettv)
6246{
6247 int flags = 0;
6248
6249 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6250}
6251
6252/*
6253 * "searchdecl()" function
6254 */
6255 static void
6256f_searchdecl(typval_T *argvars, typval_T *rettv)
6257{
6258 int locally = 1;
6259 int thisblock = 0;
6260 int error = FALSE;
6261 char_u *name;
6262
6263 rettv->vval.v_number = 1; /* default: FAIL */
6264
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006265 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006266 if (argvars[1].v_type != VAR_UNKNOWN)
6267 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006268 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006269 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006270 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006271 }
6272 if (!error && name != NULL)
6273 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6274 locally, thisblock, SEARCH_KEEP) == FAIL;
6275}
6276
6277/*
6278 * Used by searchpair() and searchpairpos()
6279 */
6280 static int
6281searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6282{
6283 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006284 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 int save_p_ws = p_ws;
6286 int dir;
6287 int flags = 0;
6288 char_u nbuf1[NUMBUFLEN];
6289 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 int retval = 0; /* default: FAIL */
6291 long lnum_stop = 0;
6292 long time_limit = 0;
6293
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006294 /* Get the three pattern arguments: start, middle, end. Will result in an
6295 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006296 spat = tv_get_string_chk(&argvars[0]);
6297 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6298 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006299 if (spat == NULL || mpat == NULL || epat == NULL)
6300 goto theend; /* type error */
6301
6302 /* Handle the optional fourth argument: flags */
6303 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6304 if (dir == 0)
6305 goto theend;
6306
6307 /* Don't accept SP_END or SP_SUBPAT.
6308 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6309 */
6310 if ((flags & (SP_END | SP_SUBPAT)) != 0
6311 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6312 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006313 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006314 goto theend;
6315 }
6316
6317 /* Using 'r' implies 'W', otherwise it doesn't work. */
6318 if (flags & SP_REPEAT)
6319 p_ws = FALSE;
6320
6321 /* Optional fifth argument: skip expression */
6322 if (argvars[3].v_type == VAR_UNKNOWN
6323 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006324 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325 else
6326 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006327 skip = &argvars[4];
6328 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6329 && skip->v_type != VAR_STRING)
6330 {
6331 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006332 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006333 goto theend;
6334 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335 if (argvars[5].v_type != VAR_UNKNOWN)
6336 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006337 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006338 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006339 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006340 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006342 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343#ifdef FEAT_RELTIME
6344 if (argvars[6].v_type != VAR_UNKNOWN)
6345 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006346 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006347 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006348 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006349 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006350 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006351 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006352 }
6353#endif
6354 }
6355 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006356
6357 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6358 match_pos, lnum_stop, time_limit);
6359
6360theend:
6361 p_ws = save_p_ws;
6362
6363 return retval;
6364}
6365
6366/*
6367 * "searchpair()" function
6368 */
6369 static void
6370f_searchpair(typval_T *argvars, typval_T *rettv)
6371{
6372 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6373}
6374
6375/*
6376 * "searchpairpos()" function
6377 */
6378 static void
6379f_searchpairpos(typval_T *argvars, typval_T *rettv)
6380{
6381 pos_T match_pos;
6382 int lnum = 0;
6383 int col = 0;
6384
6385 if (rettv_list_alloc(rettv) == FAIL)
6386 return;
6387
6388 if (searchpair_cmn(argvars, &match_pos) > 0)
6389 {
6390 lnum = match_pos.lnum;
6391 col = match_pos.col;
6392 }
6393
6394 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6395 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6396}
6397
6398/*
6399 * Search for a start/middle/end thing.
6400 * Used by searchpair(), see its documentation for the details.
6401 * Returns 0 or -1 for no match,
6402 */
6403 long
6404do_searchpair(
6405 char_u *spat, /* start pattern */
6406 char_u *mpat, /* middle pattern */
6407 char_u *epat, /* end pattern */
6408 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006409 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006410 int flags, /* SP_SETPCMARK and other SP_ values */
6411 pos_T *match_pos,
6412 linenr_T lnum_stop, /* stop at this line if not zero */
6413 long time_limit UNUSED) /* stop after this many msec */
6414{
6415 char_u *save_cpo;
6416 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6417 long retval = 0;
6418 pos_T pos;
6419 pos_T firstpos;
6420 pos_T foundpos;
6421 pos_T save_cursor;
6422 pos_T save_pos;
6423 int n;
6424 int r;
6425 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006426 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427 int err;
6428 int options = SEARCH_KEEP;
6429 proftime_T tm;
6430
6431 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6432 save_cpo = p_cpo;
6433 p_cpo = empty_option;
6434
6435#ifdef FEAT_RELTIME
6436 /* Set the time limit, if there is one. */
6437 profile_setlimit(time_limit, &tm);
6438#endif
6439
6440 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6441 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006442 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6443 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006444 if (pat2 == NULL || pat3 == NULL)
6445 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006446 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006447 if (*mpat == NUL)
6448 STRCPY(pat3, pat2);
6449 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006450 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451 spat, epat, mpat);
6452 if (flags & SP_START)
6453 options |= SEARCH_START;
6454
Bram Moolenaar48570482017-10-30 21:48:41 +01006455 if (skip != NULL)
6456 {
6457 /* Empty string means to not use the skip expression. */
6458 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6459 use_skip = skip->vval.v_string != NULL
6460 && *skip->vval.v_string != NUL;
6461 }
6462
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006463 save_cursor = curwin->w_cursor;
6464 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006465 CLEAR_POS(&firstpos);
6466 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006467 pat = pat3;
6468 for (;;)
6469 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006470 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006471 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006472 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473 /* didn't find it or found the first match again: FAIL */
6474 break;
6475
6476 if (firstpos.lnum == 0)
6477 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006478 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006479 {
6480 /* Found the same position again. Can happen with a pattern that
6481 * has "\zs" at the end and searching backwards. Advance one
6482 * character and try again. */
6483 if (dir == BACKWARD)
6484 decl(&pos);
6485 else
6486 incl(&pos);
6487 }
6488 foundpos = pos;
6489
6490 /* clear the start flag to avoid getting stuck here */
6491 options &= ~SEARCH_START;
6492
6493 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006494 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006495 {
6496 save_pos = curwin->w_cursor;
6497 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006498 err = FALSE;
6499 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500 curwin->w_cursor = save_pos;
6501 if (err)
6502 {
6503 /* Evaluating {skip} caused an error, break here. */
6504 curwin->w_cursor = save_cursor;
6505 retval = -1;
6506 break;
6507 }
6508 if (r)
6509 continue;
6510 }
6511
6512 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6513 {
6514 /* Found end when searching backwards or start when searching
6515 * forward: nested pair. */
6516 ++nest;
6517 pat = pat2; /* nested, don't search for middle */
6518 }
6519 else
6520 {
6521 /* Found end when searching forward or start when searching
6522 * backward: end of (nested) pair; or found middle in outer pair. */
6523 if (--nest == 1)
6524 pat = pat3; /* outer level, search for middle */
6525 }
6526
6527 if (nest == 0)
6528 {
6529 /* Found the match: return matchcount or line number. */
6530 if (flags & SP_RETCOUNT)
6531 ++retval;
6532 else
6533 retval = pos.lnum;
6534 if (flags & SP_SETPCMARK)
6535 setpcmark();
6536 curwin->w_cursor = pos;
6537 if (!(flags & SP_REPEAT))
6538 break;
6539 nest = 1; /* search for next unmatched */
6540 }
6541 }
6542
6543 if (match_pos != NULL)
6544 {
6545 /* Store the match cursor position */
6546 match_pos->lnum = curwin->w_cursor.lnum;
6547 match_pos->col = curwin->w_cursor.col + 1;
6548 }
6549
6550 /* If 'n' flag is used or search failed: restore cursor position. */
6551 if ((flags & SP_NOMOVE) || retval == 0)
6552 curwin->w_cursor = save_cursor;
6553
6554theend:
6555 vim_free(pat2);
6556 vim_free(pat3);
6557 if (p_cpo == empty_option)
6558 p_cpo = save_cpo;
6559 else
6560 /* Darn, evaluating the {skip} expression changed the value. */
6561 free_string_option(save_cpo);
6562
6563 return retval;
6564}
6565
6566/*
6567 * "searchpos()" function
6568 */
6569 static void
6570f_searchpos(typval_T *argvars, typval_T *rettv)
6571{
6572 pos_T match_pos;
6573 int lnum = 0;
6574 int col = 0;
6575 int n;
6576 int flags = 0;
6577
6578 if (rettv_list_alloc(rettv) == FAIL)
6579 return;
6580
6581 n = search_cmn(argvars, &match_pos, &flags);
6582 if (n > 0)
6583 {
6584 lnum = match_pos.lnum;
6585 col = match_pos.col;
6586 }
6587
6588 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6589 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6590 if (flags & SP_SUBPAT)
6591 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6592}
6593
6594 static void
6595f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6596{
6597#ifdef FEAT_CLIENTSERVER
6598 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006599 char_u *server = tv_get_string_chk(&argvars[0]);
6600 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006601
6602 rettv->vval.v_number = -1;
6603 if (server == NULL || reply == NULL)
6604 return;
6605 if (check_restricted() || check_secure())
6606 return;
6607# ifdef FEAT_X11
6608 if (check_connection() == FAIL)
6609 return;
6610# endif
6611
6612 if (serverSendReply(server, reply) < 0)
6613 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006614 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006615 return;
6616 }
6617 rettv->vval.v_number = 0;
6618#else
6619 rettv->vval.v_number = -1;
6620#endif
6621}
6622
6623 static void
6624f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6625{
6626 char_u *r = NULL;
6627
6628#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006629# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006630 r = serverGetVimNames();
6631# else
6632 make_connection();
6633 if (X_DISPLAY != NULL)
6634 r = serverGetVimNames(X_DISPLAY);
6635# endif
6636#endif
6637 rettv->v_type = VAR_STRING;
6638 rettv->vval.v_string = r;
6639}
6640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 static void
6642f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6643{
6644 dict_T *d;
6645 dictitem_T *di;
6646 char_u *csearch;
6647
6648 if (argvars[0].v_type != VAR_DICT)
6649 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006650 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651 return;
6652 }
6653
6654 if ((d = argvars[0].vval.v_dict) != NULL)
6655 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006656 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657 if (csearch != NULL)
6658 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006659 if (enc_utf8)
6660 {
6661 int pcc[MAX_MCO];
6662 int c = utfc_ptr2char(csearch, pcc);
6663
6664 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6665 }
6666 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006667 set_last_csearch(PTR2CHAR(csearch),
6668 csearch, MB_PTR2LEN(csearch));
6669 }
6670
6671 di = dict_find(d, (char_u *)"forward", -1);
6672 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006673 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006674 ? FORWARD : BACKWARD);
6675
6676 di = dict_find(d, (char_u *)"until", -1);
6677 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006678 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006679 }
6680}
6681
6682/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006683 * "setenv()" function
6684 */
6685 static void
6686f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6687{
6688 char_u namebuf[NUMBUFLEN];
6689 char_u valbuf[NUMBUFLEN];
6690 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6691
6692 if (argvars[1].v_type == VAR_SPECIAL
6693 && argvars[1].vval.v_number == VVAL_NULL)
6694 vim_unsetenv(name);
6695 else
6696 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6697}
6698
6699/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700 * "setfperm({fname}, {mode})" function
6701 */
6702 static void
6703f_setfperm(typval_T *argvars, typval_T *rettv)
6704{
6705 char_u *fname;
6706 char_u modebuf[NUMBUFLEN];
6707 char_u *mode_str;
6708 int i;
6709 int mask;
6710 int mode = 0;
6711
6712 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006713 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006714 if (fname == NULL)
6715 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006716 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006717 if (mode_str == NULL)
6718 return;
6719 if (STRLEN(mode_str) != 9)
6720 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006721 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006722 return;
6723 }
6724
6725 mask = 1;
6726 for (i = 8; i >= 0; --i)
6727 {
6728 if (mode_str[i] != '-')
6729 mode |= mask;
6730 mask = mask << 1;
6731 }
6732 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6733}
6734
6735/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006736 * "setpos()" function
6737 */
6738 static void
6739f_setpos(typval_T *argvars, typval_T *rettv)
6740{
6741 pos_T pos;
6742 int fnum;
6743 char_u *name;
6744 colnr_T curswant = -1;
6745
6746 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006747 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006748 if (name != NULL)
6749 {
6750 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6751 {
6752 if (--pos.col < 0)
6753 pos.col = 0;
6754 if (name[0] == '.' && name[1] == NUL)
6755 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006756 /* set cursor; "fnum" is ignored */
6757 curwin->w_cursor = pos;
6758 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006760 curwin->w_curswant = curswant - 1;
6761 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006762 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006763 check_cursor();
6764 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006765 }
6766 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6767 {
6768 /* set mark */
6769 if (setmark_pos(name[1], &pos, fnum) == OK)
6770 rettv->vval.v_number = 0;
6771 }
6772 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006773 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774 }
6775 }
6776}
6777
6778/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 * "setreg()" function
6780 */
6781 static void
6782f_setreg(typval_T *argvars, typval_T *rettv)
6783{
6784 int regname;
6785 char_u *strregname;
6786 char_u *stropt;
6787 char_u *strval;
6788 int append;
6789 char_u yank_type;
6790 long block_len;
6791
6792 block_len = -1;
6793 yank_type = MAUTO;
6794 append = FALSE;
6795
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006796 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797 rettv->vval.v_number = 1; /* FAIL is default */
6798
6799 if (strregname == NULL)
6800 return; /* type error; errmsg already given */
6801 regname = *strregname;
6802 if (regname == 0 || regname == '@')
6803 regname = '"';
6804
6805 if (argvars[2].v_type != VAR_UNKNOWN)
6806 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006807 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006808 if (stropt == NULL)
6809 return; /* type error */
6810 for (; *stropt != NUL; ++stropt)
6811 switch (*stropt)
6812 {
6813 case 'a': case 'A': /* append */
6814 append = TRUE;
6815 break;
6816 case 'v': case 'c': /* character-wise selection */
6817 yank_type = MCHAR;
6818 break;
6819 case 'V': case 'l': /* line-wise selection */
6820 yank_type = MLINE;
6821 break;
6822 case 'b': case Ctrl_V: /* block-wise selection */
6823 yank_type = MBLOCK;
6824 if (VIM_ISDIGIT(stropt[1]))
6825 {
6826 ++stropt;
6827 block_len = getdigits(&stropt) - 1;
6828 --stropt;
6829 }
6830 break;
6831 }
6832 }
6833
6834 if (argvars[1].v_type == VAR_LIST)
6835 {
6836 char_u **lstval;
6837 char_u **allocval;
6838 char_u buf[NUMBUFLEN];
6839 char_u **curval;
6840 char_u **curallocval;
6841 list_T *ll = argvars[1].vval.v_list;
6842 listitem_T *li;
6843 int len;
6844
6845 /* If the list is NULL handle like an empty list. */
6846 len = ll == NULL ? 0 : ll->lv_len;
6847
6848 /* First half: use for pointers to result lines; second half: use for
6849 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006850 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 if (lstval == NULL)
6852 return;
6853 curval = lstval;
6854 allocval = lstval + len + 2;
6855 curallocval = allocval;
6856
6857 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6858 li = li->li_next)
6859 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006860 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006861 if (strval == NULL)
6862 goto free_lstval;
6863 if (strval == buf)
6864 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006865 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 * overwrite the string. */
6867 strval = vim_strsave(buf);
6868 if (strval == NULL)
6869 goto free_lstval;
6870 *curallocval++ = strval;
6871 }
6872 *curval++ = strval;
6873 }
6874 *curval++ = NULL;
6875
6876 write_reg_contents_lst(regname, lstval, -1,
6877 append, yank_type, block_len);
6878free_lstval:
6879 while (curallocval > allocval)
6880 vim_free(*--curallocval);
6881 vim_free(lstval);
6882 }
6883 else
6884 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006885 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006886 if (strval == NULL)
6887 return;
6888 write_reg_contents_ex(regname, strval, -1,
6889 append, yank_type, block_len);
6890 }
6891 rettv->vval.v_number = 0;
6892}
6893
6894/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006895 * "settagstack()" function
6896 */
6897 static void
6898f_settagstack(typval_T *argvars, typval_T *rettv)
6899{
6900 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6901 win_T *wp;
6902 dict_T *d;
6903 int action = 'r';
6904
6905 rettv->vval.v_number = -1;
6906
6907 // first argument: window number or id
6908 wp = find_win_by_nr_or_id(&argvars[0]);
6909 if (wp == NULL)
6910 return;
6911
6912 // second argument: dict with items to set in the tag stack
6913 if (argvars[1].v_type != VAR_DICT)
6914 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006915 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006916 return;
6917 }
6918 d = argvars[1].vval.v_dict;
6919 if (d == NULL)
6920 return;
6921
6922 // third argument: action - 'a' for append and 'r' for replace.
6923 // default is to replace the stack.
6924 if (argvars[2].v_type == VAR_UNKNOWN)
6925 action = 'r';
6926 else if (argvars[2].v_type == VAR_STRING)
6927 {
6928 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006929 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006930 if (actstr == NULL)
6931 return;
6932 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6933 action = *actstr;
6934 else
6935 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006936 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006937 return;
6938 }
6939 }
6940 else
6941 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006942 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006943 return;
6944 }
6945
6946 if (set_tagstack(wp, d, action) == OK)
6947 rettv->vval.v_number = 0;
6948}
6949
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950#ifdef FEAT_CRYPT
6951/*
6952 * "sha256({string})" function
6953 */
6954 static void
6955f_sha256(typval_T *argvars, typval_T *rettv)
6956{
6957 char_u *p;
6958
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006959 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960 rettv->vval.v_string = vim_strsave(
6961 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6962 rettv->v_type = VAR_STRING;
6963}
6964#endif /* FEAT_CRYPT */
6965
6966/*
6967 * "shellescape({string})" function
6968 */
6969 static void
6970f_shellescape(typval_T *argvars, typval_T *rettv)
6971{
Bram Moolenaar20615522017-06-05 18:46:26 +02006972 int do_special = non_zero_arg(&argvars[1]);
6973
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006975 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006976 rettv->v_type = VAR_STRING;
6977}
6978
6979/*
6980 * shiftwidth() function
6981 */
6982 static void
6983f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6984{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006985 rettv->vval.v_number = 0;
6986
6987 if (argvars[0].v_type != VAR_UNKNOWN)
6988 {
6989 long col;
6990
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006991 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006992 if (col < 0)
6993 return; // type error; errmsg already given
6994#ifdef FEAT_VARTABS
6995 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6996 return;
6997#endif
6998 }
6999
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007000 rettv->vval.v_number = get_sw_value(curbuf);
7001}
7002
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007003#ifdef FEAT_FLOAT
7004/*
7005 * "sin()" function
7006 */
7007 static void
7008f_sin(typval_T *argvars, typval_T *rettv)
7009{
7010 float_T f = 0.0;
7011
7012 rettv->v_type = VAR_FLOAT;
7013 if (get_float_arg(argvars, &f) == OK)
7014 rettv->vval.v_float = sin(f);
7015 else
7016 rettv->vval.v_float = 0.0;
7017}
7018
7019/*
7020 * "sinh()" function
7021 */
7022 static void
7023f_sinh(typval_T *argvars, typval_T *rettv)
7024{
7025 float_T f = 0.0;
7026
7027 rettv->v_type = VAR_FLOAT;
7028 if (get_float_arg(argvars, &f) == OK)
7029 rettv->vval.v_float = sinh(f);
7030 else
7031 rettv->vval.v_float = 0.0;
7032}
7033#endif
7034
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007035/*
7036 * "soundfold({word})" function
7037 */
7038 static void
7039f_soundfold(typval_T *argvars, typval_T *rettv)
7040{
7041 char_u *s;
7042
7043 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007044 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007045#ifdef FEAT_SPELL
7046 rettv->vval.v_string = eval_soundfold(s);
7047#else
7048 rettv->vval.v_string = vim_strsave(s);
7049#endif
7050}
7051
7052/*
7053 * "spellbadword()" function
7054 */
7055 static void
7056f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7057{
7058 char_u *word = (char_u *)"";
7059 hlf_T attr = HLF_COUNT;
7060 int len = 0;
7061
7062 if (rettv_list_alloc(rettv) == FAIL)
7063 return;
7064
7065#ifdef FEAT_SPELL
7066 if (argvars[0].v_type == VAR_UNKNOWN)
7067 {
7068 /* Find the start and length of the badly spelled word. */
7069 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7070 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007071 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007072 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007073 curwin->w_set_curswant = TRUE;
7074 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 }
7076 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7077 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007078 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007079 int capcol = -1;
7080
7081 if (str != NULL)
7082 {
7083 /* Check the argument for spelling. */
7084 while (*str != NUL)
7085 {
7086 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7087 if (attr != HLF_COUNT)
7088 {
7089 word = str;
7090 break;
7091 }
7092 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007093 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007094 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007095 }
7096 }
7097 }
7098#endif
7099
7100 list_append_string(rettv->vval.v_list, word, len);
7101 list_append_string(rettv->vval.v_list, (char_u *)(
7102 attr == HLF_SPB ? "bad" :
7103 attr == HLF_SPR ? "rare" :
7104 attr == HLF_SPL ? "local" :
7105 attr == HLF_SPC ? "caps" :
7106 ""), -1);
7107}
7108
7109/*
7110 * "spellsuggest()" function
7111 */
7112 static void
7113f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7114{
7115#ifdef FEAT_SPELL
7116 char_u *str;
7117 int typeerr = FALSE;
7118 int maxcount;
7119 garray_T ga;
7120 int i;
7121 listitem_T *li;
7122 int need_capital = FALSE;
7123#endif
7124
7125 if (rettv_list_alloc(rettv) == FAIL)
7126 return;
7127
7128#ifdef FEAT_SPELL
7129 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7130 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007131 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007132 if (argvars[1].v_type != VAR_UNKNOWN)
7133 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007134 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 if (maxcount <= 0)
7136 return;
7137 if (argvars[2].v_type != VAR_UNKNOWN)
7138 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007139 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007140 if (typeerr)
7141 return;
7142 }
7143 }
7144 else
7145 maxcount = 25;
7146
7147 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7148
7149 for (i = 0; i < ga.ga_len; ++i)
7150 {
7151 str = ((char_u **)ga.ga_data)[i];
7152
7153 li = listitem_alloc();
7154 if (li == NULL)
7155 vim_free(str);
7156 else
7157 {
7158 li->li_tv.v_type = VAR_STRING;
7159 li->li_tv.v_lock = 0;
7160 li->li_tv.vval.v_string = str;
7161 list_append(rettv->vval.v_list, li);
7162 }
7163 }
7164 ga_clear(&ga);
7165 }
7166#endif
7167}
7168
7169 static void
7170f_split(typval_T *argvars, typval_T *rettv)
7171{
7172 char_u *str;
7173 char_u *end;
7174 char_u *pat = NULL;
7175 regmatch_T regmatch;
7176 char_u patbuf[NUMBUFLEN];
7177 char_u *save_cpo;
7178 int match;
7179 colnr_T col = 0;
7180 int keepempty = FALSE;
7181 int typeerr = FALSE;
7182
7183 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7184 save_cpo = p_cpo;
7185 p_cpo = (char_u *)"";
7186
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007187 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188 if (argvars[1].v_type != VAR_UNKNOWN)
7189 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007190 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007191 if (pat == NULL)
7192 typeerr = TRUE;
7193 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007194 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007195 }
7196 if (pat == NULL || *pat == NUL)
7197 pat = (char_u *)"[\\x01- ]\\+";
7198
7199 if (rettv_list_alloc(rettv) == FAIL)
7200 return;
7201 if (typeerr)
7202 return;
7203
7204 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7205 if (regmatch.regprog != NULL)
7206 {
7207 regmatch.rm_ic = FALSE;
7208 while (*str != NUL || keepempty)
7209 {
7210 if (*str == NUL)
7211 match = FALSE; /* empty item at the end */
7212 else
7213 match = vim_regexec_nl(&regmatch, str, col);
7214 if (match)
7215 end = regmatch.startp[0];
7216 else
7217 end = str + STRLEN(str);
7218 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7219 && *str != NUL && match && end < regmatch.endp[0]))
7220 {
7221 if (list_append_string(rettv->vval.v_list, str,
7222 (int)(end - str)) == FAIL)
7223 break;
7224 }
7225 if (!match)
7226 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007227 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 if (regmatch.endp[0] > str)
7229 col = 0;
7230 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007231 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007232 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 str = regmatch.endp[0];
7234 }
7235
7236 vim_regfree(regmatch.regprog);
7237 }
7238
7239 p_cpo = save_cpo;
7240}
7241
7242#ifdef FEAT_FLOAT
7243/*
7244 * "sqrt()" function
7245 */
7246 static void
7247f_sqrt(typval_T *argvars, typval_T *rettv)
7248{
7249 float_T f = 0.0;
7250
7251 rettv->v_type = VAR_FLOAT;
7252 if (get_float_arg(argvars, &f) == OK)
7253 rettv->vval.v_float = sqrt(f);
7254 else
7255 rettv->vval.v_float = 0.0;
7256}
7257
7258/*
7259 * "str2float()" function
7260 */
7261 static void
7262f_str2float(typval_T *argvars, typval_T *rettv)
7263{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007264 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007265 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266
Bram Moolenaar08243d22017-01-10 16:12:29 +01007267 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007268 p = skipwhite(p + 1);
7269 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007270 if (isneg)
7271 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007272 rettv->v_type = VAR_FLOAT;
7273}
7274#endif
7275
7276/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007277 * "str2list()" function
7278 */
7279 static void
7280f_str2list(typval_T *argvars, typval_T *rettv)
7281{
7282 char_u *p;
7283 int utf8 = FALSE;
7284
7285 if (rettv_list_alloc(rettv) == FAIL)
7286 return;
7287
7288 if (argvars[1].v_type != VAR_UNKNOWN)
7289 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7290
7291 p = tv_get_string(&argvars[0]);
7292
7293 if (has_mbyte || utf8)
7294 {
7295 int (*ptr2len)(char_u *);
7296 int (*ptr2char)(char_u *);
7297
7298 if (utf8 || enc_utf8)
7299 {
7300 ptr2len = utf_ptr2len;
7301 ptr2char = utf_ptr2char;
7302 }
7303 else
7304 {
7305 ptr2len = mb_ptr2len;
7306 ptr2char = mb_ptr2char;
7307 }
7308
7309 for ( ; *p != NUL; p += (*ptr2len)(p))
7310 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7311 }
7312 else
7313 for ( ; *p != NUL; ++p)
7314 list_append_number(rettv->vval.v_list, *p);
7315}
7316
7317/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007318 * "str2nr()" function
7319 */
7320 static void
7321f_str2nr(typval_T *argvars, typval_T *rettv)
7322{
7323 int base = 10;
7324 char_u *p;
7325 varnumber_T n;
7326 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007327 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007328
7329 if (argvars[1].v_type != VAR_UNKNOWN)
7330 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007331 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007332 if (base != 2 && base != 8 && base != 10 && base != 16)
7333 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007334 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007335 return;
7336 }
7337 }
7338
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007339 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007340 isneg = (*p == '-');
7341 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342 p = skipwhite(p + 1);
7343 switch (base)
7344 {
7345 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
7346 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
7347 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
7348 default: what = 0;
7349 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007350 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7351 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007352 if (isneg)
7353 rettv->vval.v_number = -n;
7354 else
7355 rettv->vval.v_number = n;
7356
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007357}
7358
7359#ifdef HAVE_STRFTIME
7360/*
7361 * "strftime({format}[, {time}])" function
7362 */
7363 static void
7364f_strftime(typval_T *argvars, typval_T *rettv)
7365{
7366 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007367 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368 struct tm *curtime;
7369 time_t seconds;
7370 char_u *p;
7371
7372 rettv->v_type = VAR_STRING;
7373
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007374 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007375 if (argvars[1].v_type == VAR_UNKNOWN)
7376 seconds = time(NULL);
7377 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007378 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007379 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007380 /* MSVC returns NULL for an invalid value of seconds. */
7381 if (curtime == NULL)
7382 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7383 else
7384 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007385 vimconv_T conv;
7386 char_u *enc;
7387
7388 conv.vc_type = CONV_NONE;
7389 enc = enc_locale();
7390 convert_setup(&conv, p_enc, enc);
7391 if (conv.vc_type != CONV_NONE)
7392 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007393 if (p != NULL)
7394 (void)strftime((char *)result_buf, sizeof(result_buf),
7395 (char *)p, curtime);
7396 else
7397 result_buf[0] = NUL;
7398
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007399 if (conv.vc_type != CONV_NONE)
7400 vim_free(p);
7401 convert_setup(&conv, enc, p_enc);
7402 if (conv.vc_type != CONV_NONE)
7403 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7404 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 rettv->vval.v_string = vim_strsave(result_buf);
7406
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 /* Release conversion descriptors */
7408 convert_setup(&conv, NULL, NULL);
7409 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410 }
7411}
7412#endif
7413
7414/*
7415 * "strgetchar()" function
7416 */
7417 static void
7418f_strgetchar(typval_T *argvars, typval_T *rettv)
7419{
7420 char_u *str;
7421 int len;
7422 int error = FALSE;
7423 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007424 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007425
7426 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007427 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 if (str == NULL)
7429 return;
7430 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007431 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432 if (error)
7433 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434
Bram Moolenaar13505972019-01-24 15:04:48 +01007435 while (charidx >= 0 && byteidx < len)
7436 {
7437 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007438 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007439 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7440 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007442 --charidx;
7443 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007444 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007445}
7446
7447/*
7448 * "stridx()" function
7449 */
7450 static void
7451f_stridx(typval_T *argvars, typval_T *rettv)
7452{
7453 char_u buf[NUMBUFLEN];
7454 char_u *needle;
7455 char_u *haystack;
7456 char_u *save_haystack;
7457 char_u *pos;
7458 int start_idx;
7459
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007460 needle = tv_get_string_chk(&argvars[1]);
7461 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007462 rettv->vval.v_number = -1;
7463 if (needle == NULL || haystack == NULL)
7464 return; /* type error; errmsg already given */
7465
7466 if (argvars[2].v_type != VAR_UNKNOWN)
7467 {
7468 int error = FALSE;
7469
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007470 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 if (error || start_idx >= (int)STRLEN(haystack))
7472 return;
7473 if (start_idx >= 0)
7474 haystack += start_idx;
7475 }
7476
7477 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7478 if (pos != NULL)
7479 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7480}
7481
7482/*
7483 * "string()" function
7484 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007485 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007486f_string(typval_T *argvars, typval_T *rettv)
7487{
7488 char_u *tofree;
7489 char_u numbuf[NUMBUFLEN];
7490
7491 rettv->v_type = VAR_STRING;
7492 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7493 get_copyID());
7494 /* Make a copy if we have a value but it's not in allocated memory. */
7495 if (rettv->vval.v_string != NULL && tofree == NULL)
7496 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7497}
7498
7499/*
7500 * "strlen()" function
7501 */
7502 static void
7503f_strlen(typval_T *argvars, typval_T *rettv)
7504{
7505 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007506 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507}
7508
7509/*
7510 * "strchars()" function
7511 */
7512 static void
7513f_strchars(typval_T *argvars, typval_T *rettv)
7514{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007515 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 varnumber_T len = 0;
7518 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519
7520 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007521 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007523 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524 else
7525 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7527 while (*s != NUL)
7528 {
7529 func_mb_ptr2char_adv(&s);
7530 ++len;
7531 }
7532 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007533 }
7534}
7535
7536/*
7537 * "strdisplaywidth()" function
7538 */
7539 static void
7540f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7541{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007542 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007543 int col = 0;
7544
7545 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007546 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007547
7548 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7549}
7550
7551/*
7552 * "strwidth()" function
7553 */
7554 static void
7555f_strwidth(typval_T *argvars, typval_T *rettv)
7556{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007557 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558
Bram Moolenaar13505972019-01-24 15:04:48 +01007559 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007560}
7561
7562/*
7563 * "strcharpart()" function
7564 */
7565 static void
7566f_strcharpart(typval_T *argvars, typval_T *rettv)
7567{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007568 char_u *p;
7569 int nchar;
7570 int nbyte = 0;
7571 int charlen;
7572 int len = 0;
7573 int slen;
7574 int error = FALSE;
7575
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 slen = (int)STRLEN(p);
7578
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007579 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007580 if (!error)
7581 {
7582 if (nchar > 0)
7583 while (nchar > 0 && nbyte < slen)
7584 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007585 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007586 --nchar;
7587 }
7588 else
7589 nbyte = nchar;
7590 if (argvars[2].v_type != VAR_UNKNOWN)
7591 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007592 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007593 while (charlen > 0 && nbyte + len < slen)
7594 {
7595 int off = nbyte + len;
7596
7597 if (off < 0)
7598 len += 1;
7599 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007600 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007601 --charlen;
7602 }
7603 }
7604 else
7605 len = slen - nbyte; /* default: all bytes that are available. */
7606 }
7607
7608 /*
7609 * Only return the overlap between the specified part and the actual
7610 * string.
7611 */
7612 if (nbyte < 0)
7613 {
7614 len += nbyte;
7615 nbyte = 0;
7616 }
7617 else if (nbyte > slen)
7618 nbyte = slen;
7619 if (len < 0)
7620 len = 0;
7621 else if (nbyte + len > slen)
7622 len = slen - nbyte;
7623
7624 rettv->v_type = VAR_STRING;
7625 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626}
7627
7628/*
7629 * "strpart()" function
7630 */
7631 static void
7632f_strpart(typval_T *argvars, typval_T *rettv)
7633{
7634 char_u *p;
7635 int n;
7636 int len;
7637 int slen;
7638 int error = FALSE;
7639
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007640 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007641 slen = (int)STRLEN(p);
7642
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007643 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007644 if (error)
7645 len = 0;
7646 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007647 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 else
7649 len = slen - n; /* default len: all bytes that are available. */
7650
7651 /*
7652 * Only return the overlap between the specified part and the actual
7653 * string.
7654 */
7655 if (n < 0)
7656 {
7657 len += n;
7658 n = 0;
7659 }
7660 else if (n > slen)
7661 n = slen;
7662 if (len < 0)
7663 len = 0;
7664 else if (n + len > slen)
7665 len = slen - n;
7666
7667 rettv->v_type = VAR_STRING;
7668 rettv->vval.v_string = vim_strnsave(p + n, len);
7669}
7670
7671/*
7672 * "strridx()" function
7673 */
7674 static void
7675f_strridx(typval_T *argvars, typval_T *rettv)
7676{
7677 char_u buf[NUMBUFLEN];
7678 char_u *needle;
7679 char_u *haystack;
7680 char_u *rest;
7681 char_u *lastmatch = NULL;
7682 int haystack_len, end_idx;
7683
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007684 needle = tv_get_string_chk(&argvars[1]);
7685 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007686
7687 rettv->vval.v_number = -1;
7688 if (needle == NULL || haystack == NULL)
7689 return; /* type error; errmsg already given */
7690
7691 haystack_len = (int)STRLEN(haystack);
7692 if (argvars[2].v_type != VAR_UNKNOWN)
7693 {
7694 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007695 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007696 if (end_idx < 0)
7697 return; /* can never find a match */
7698 }
7699 else
7700 end_idx = haystack_len;
7701
7702 if (*needle == NUL)
7703 {
7704 /* Empty string matches past the end. */
7705 lastmatch = haystack + end_idx;
7706 }
7707 else
7708 {
7709 for (rest = haystack; *rest != '\0'; ++rest)
7710 {
7711 rest = (char_u *)strstr((char *)rest, (char *)needle);
7712 if (rest == NULL || rest > haystack + end_idx)
7713 break;
7714 lastmatch = rest;
7715 }
7716 }
7717
7718 if (lastmatch == NULL)
7719 rettv->vval.v_number = -1;
7720 else
7721 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7722}
7723
7724/*
7725 * "strtrans()" function
7726 */
7727 static void
7728f_strtrans(typval_T *argvars, typval_T *rettv)
7729{
7730 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007731 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007732}
7733
7734/*
7735 * "submatch()" function
7736 */
7737 static void
7738f_submatch(typval_T *argvars, typval_T *rettv)
7739{
7740 int error = FALSE;
7741 int no;
7742 int retList = 0;
7743
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007744 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007745 if (error)
7746 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007747 if (no < 0 || no >= NSUBEXP)
7748 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007749 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007750 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007751 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007752 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007753 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007754 if (error)
7755 return;
7756
7757 if (retList == 0)
7758 {
7759 rettv->v_type = VAR_STRING;
7760 rettv->vval.v_string = reg_submatch(no);
7761 }
7762 else
7763 {
7764 rettv->v_type = VAR_LIST;
7765 rettv->vval.v_list = reg_submatch_list(no);
7766 }
7767}
7768
7769/*
7770 * "substitute()" function
7771 */
7772 static void
7773f_substitute(typval_T *argvars, typval_T *rettv)
7774{
7775 char_u patbuf[NUMBUFLEN];
7776 char_u subbuf[NUMBUFLEN];
7777 char_u flagsbuf[NUMBUFLEN];
7778
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007779 char_u *str = tv_get_string_chk(&argvars[0]);
7780 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007781 char_u *sub = NULL;
7782 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007783 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007784
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007785 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7786 expr = &argvars[2];
7787 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007788 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007789
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007790 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007791 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7792 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007793 rettv->vval.v_string = NULL;
7794 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007795 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007796}
7797
7798/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007799 * "swapinfo(swap_filename)" function
7800 */
7801 static void
7802f_swapinfo(typval_T *argvars, typval_T *rettv)
7803{
7804 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007805 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007806}
7807
7808/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007809 * "swapname(expr)" function
7810 */
7811 static void
7812f_swapname(typval_T *argvars, typval_T *rettv)
7813{
7814 buf_T *buf;
7815
7816 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007817 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007818 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7819 || buf->b_ml.ml_mfp->mf_fname == NULL)
7820 rettv->vval.v_string = NULL;
7821 else
7822 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7823}
7824
7825/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 * "synID(lnum, col, trans)" function
7827 */
7828 static void
7829f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7830{
7831 int id = 0;
7832#ifdef FEAT_SYN_HL
7833 linenr_T lnum;
7834 colnr_T col;
7835 int trans;
7836 int transerr = FALSE;
7837
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007838 lnum = tv_get_lnum(argvars); /* -1 on type error */
7839 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7840 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841
7842 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7843 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7844 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7845#endif
7846
7847 rettv->vval.v_number = id;
7848}
7849
7850/*
7851 * "synIDattr(id, what [, mode])" function
7852 */
7853 static void
7854f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7855{
7856 char_u *p = NULL;
7857#ifdef FEAT_SYN_HL
7858 int id;
7859 char_u *what;
7860 char_u *mode;
7861 char_u modebuf[NUMBUFLEN];
7862 int modec;
7863
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007864 id = (int)tv_get_number(&argvars[0]);
7865 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 if (argvars[2].v_type != VAR_UNKNOWN)
7867 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007868 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007869 modec = TOLOWER_ASC(mode[0]);
7870 if (modec != 't' && modec != 'c' && modec != 'g')
7871 modec = 0; /* replace invalid with current */
7872 }
7873 else
7874 {
7875#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7876 if (USE_24BIT)
7877 modec = 'g';
7878 else
7879#endif
7880 if (t_colors > 1)
7881 modec = 'c';
7882 else
7883 modec = 't';
7884 }
7885
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007886 switch (TOLOWER_ASC(what[0]))
7887 {
7888 case 'b':
7889 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7890 p = highlight_color(id, what, modec);
7891 else /* bold */
7892 p = highlight_has_attr(id, HL_BOLD, modec);
7893 break;
7894
7895 case 'f': /* fg[#] or font */
7896 p = highlight_color(id, what, modec);
7897 break;
7898
7899 case 'i':
7900 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7901 p = highlight_has_attr(id, HL_INVERSE, modec);
7902 else /* italic */
7903 p = highlight_has_attr(id, HL_ITALIC, modec);
7904 break;
7905
7906 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007907 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908 break;
7909
7910 case 'r': /* reverse */
7911 p = highlight_has_attr(id, HL_INVERSE, modec);
7912 break;
7913
7914 case 's':
7915 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7916 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007917 /* strikeout */
7918 else if (TOLOWER_ASC(what[1]) == 't' &&
7919 TOLOWER_ASC(what[2]) == 'r')
7920 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 else /* standout */
7922 p = highlight_has_attr(id, HL_STANDOUT, modec);
7923 break;
7924
7925 case 'u':
7926 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7927 /* underline */
7928 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7929 else
7930 /* undercurl */
7931 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7932 break;
7933 }
7934
7935 if (p != NULL)
7936 p = vim_strsave(p);
7937#endif
7938 rettv->v_type = VAR_STRING;
7939 rettv->vval.v_string = p;
7940}
7941
7942/*
7943 * "synIDtrans(id)" function
7944 */
7945 static void
7946f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7947{
7948 int id;
7949
7950#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007951 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007952
7953 if (id > 0)
7954 id = syn_get_final_id(id);
7955 else
7956#endif
7957 id = 0;
7958
7959 rettv->vval.v_number = id;
7960}
7961
7962/*
7963 * "synconcealed(lnum, col)" function
7964 */
7965 static void
7966f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7967{
7968#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7969 linenr_T lnum;
7970 colnr_T col;
7971 int syntax_flags = 0;
7972 int cchar;
7973 int matchid = 0;
7974 char_u str[NUMBUFLEN];
7975#endif
7976
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007977 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007978
7979#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007980 lnum = tv_get_lnum(argvars); /* -1 on type error */
7981 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007982
7983 vim_memset(str, NUL, sizeof(str));
7984
7985 if (rettv_list_alloc(rettv) != FAIL)
7986 {
7987 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7988 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7989 && curwin->w_p_cole > 0)
7990 {
7991 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7992 syntax_flags = get_syntax_info(&matchid);
7993
7994 /* get the conceal character */
7995 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7996 {
7997 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007998 if (cchar == NUL && curwin->w_p_cole == 1)
7999 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008000 if (cchar != NUL)
8001 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002 if (has_mbyte)
8003 (*mb_char2bytes)(cchar, str);
8004 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008005 str[0] = cchar;
8006 }
8007 }
8008 }
8009
8010 list_append_number(rettv->vval.v_list,
8011 (syntax_flags & HL_CONCEAL) != 0);
8012 /* -1 to auto-determine strlen */
8013 list_append_string(rettv->vval.v_list, str, -1);
8014 list_append_number(rettv->vval.v_list, matchid);
8015 }
8016#endif
8017}
8018
8019/*
8020 * "synstack(lnum, col)" function
8021 */
8022 static void
8023f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8024{
8025#ifdef FEAT_SYN_HL
8026 linenr_T lnum;
8027 colnr_T col;
8028 int i;
8029 int id;
8030#endif
8031
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008032 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033
8034#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008035 lnum = tv_get_lnum(argvars); /* -1 on type error */
8036 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008037
8038 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8039 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8040 && rettv_list_alloc(rettv) != FAIL)
8041 {
8042 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8043 for (i = 0; ; ++i)
8044 {
8045 id = syn_get_stack_item(i);
8046 if (id < 0)
8047 break;
8048 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8049 break;
8050 }
8051 }
8052#endif
8053}
8054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008055/*
8056 * "tabpagebuflist()" function
8057 */
8058 static void
8059f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8060{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008061 tabpage_T *tp;
8062 win_T *wp = NULL;
8063
8064 if (argvars[0].v_type == VAR_UNKNOWN)
8065 wp = firstwin;
8066 else
8067 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008068 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069 if (tp != NULL)
8070 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8071 }
8072 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8073 {
8074 for (; wp != NULL; wp = wp->w_next)
8075 if (list_append_number(rettv->vval.v_list,
8076 wp->w_buffer->b_fnum) == FAIL)
8077 break;
8078 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079}
8080
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 * "tagfiles()" function
8083 */
8084 static void
8085f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8086{
8087 char_u *fname;
8088 tagname_T tn;
8089 int first;
8090
8091 if (rettv_list_alloc(rettv) == FAIL)
8092 return;
8093 fname = alloc(MAXPATHL);
8094 if (fname == NULL)
8095 return;
8096
8097 for (first = TRUE; ; first = FALSE)
8098 if (get_tagfname(&tn, first, fname) == FAIL
8099 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8100 break;
8101 tagname_free(&tn);
8102 vim_free(fname);
8103}
8104
8105/*
8106 * "taglist()" function
8107 */
8108 static void
8109f_taglist(typval_T *argvars, typval_T *rettv)
8110{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008111 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008112 char_u *tag_pattern;
8113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008114 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008115
8116 rettv->vval.v_number = FALSE;
8117 if (*tag_pattern == NUL)
8118 return;
8119
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008120 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008121 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008123 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008124}
8125
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008126#ifdef FEAT_FLOAT
8127/*
8128 * "tan()" function
8129 */
8130 static void
8131f_tan(typval_T *argvars, typval_T *rettv)
8132{
8133 float_T f = 0.0;
8134
8135 rettv->v_type = VAR_FLOAT;
8136 if (get_float_arg(argvars, &f) == OK)
8137 rettv->vval.v_float = tan(f);
8138 else
8139 rettv->vval.v_float = 0.0;
8140}
8141
8142/*
8143 * "tanh()" function
8144 */
8145 static void
8146f_tanh(typval_T *argvars, typval_T *rettv)
8147{
8148 float_T f = 0.0;
8149
8150 rettv->v_type = VAR_FLOAT;
8151 if (get_float_arg(argvars, &f) == OK)
8152 rettv->vval.v_float = tanh(f);
8153 else
8154 rettv->vval.v_float = 0.0;
8155}
8156#endif
8157
8158/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 * "tolower(string)" function
8160 */
8161 static void
8162f_tolower(typval_T *argvars, typval_T *rettv)
8163{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008165 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008166}
8167
8168/*
8169 * "toupper(string)" function
8170 */
8171 static void
8172f_toupper(typval_T *argvars, typval_T *rettv)
8173{
8174 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008175 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176}
8177
8178/*
8179 * "tr(string, fromstr, tostr)" function
8180 */
8181 static void
8182f_tr(typval_T *argvars, typval_T *rettv)
8183{
8184 char_u *in_str;
8185 char_u *fromstr;
8186 char_u *tostr;
8187 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 int inlen;
8189 int fromlen;
8190 int tolen;
8191 int idx;
8192 char_u *cpstr;
8193 int cplen;
8194 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 char_u buf[NUMBUFLEN];
8196 char_u buf2[NUMBUFLEN];
8197 garray_T ga;
8198
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008199 in_str = tv_get_string(&argvars[0]);
8200 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8201 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008202
8203 /* Default return value: empty string. */
8204 rettv->v_type = VAR_STRING;
8205 rettv->vval.v_string = NULL;
8206 if (fromstr == NULL || tostr == NULL)
8207 return; /* type error; errmsg already given */
8208 ga_init2(&ga, (int)sizeof(char), 80);
8209
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008210 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 /* not multi-byte: fromstr and tostr must be the same length */
8212 if (STRLEN(fromstr) != STRLEN(tostr))
8213 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008214error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008215 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008216 ga_clear(&ga);
8217 return;
8218 }
8219
8220 /* fromstr and tostr have to contain the same number of chars */
8221 while (*in_str != NUL)
8222 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223 if (has_mbyte)
8224 {
8225 inlen = (*mb_ptr2len)(in_str);
8226 cpstr = in_str;
8227 cplen = inlen;
8228 idx = 0;
8229 for (p = fromstr; *p != NUL; p += fromlen)
8230 {
8231 fromlen = (*mb_ptr2len)(p);
8232 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8233 {
8234 for (p = tostr; *p != NUL; p += tolen)
8235 {
8236 tolen = (*mb_ptr2len)(p);
8237 if (idx-- == 0)
8238 {
8239 cplen = tolen;
8240 cpstr = p;
8241 break;
8242 }
8243 }
8244 if (*p == NUL) /* tostr is shorter than fromstr */
8245 goto error;
8246 break;
8247 }
8248 ++idx;
8249 }
8250
8251 if (first && cpstr == in_str)
8252 {
8253 /* Check that fromstr and tostr have the same number of
8254 * (multi-byte) characters. Done only once when a character
8255 * of in_str doesn't appear in fromstr. */
8256 first = FALSE;
8257 for (p = tostr; *p != NUL; p += tolen)
8258 {
8259 tolen = (*mb_ptr2len)(p);
8260 --idx;
8261 }
8262 if (idx != 0)
8263 goto error;
8264 }
8265
8266 (void)ga_grow(&ga, cplen);
8267 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8268 ga.ga_len += cplen;
8269
8270 in_str += inlen;
8271 }
8272 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008273 {
8274 /* When not using multi-byte chars we can do it faster. */
8275 p = vim_strchr(fromstr, *in_str);
8276 if (p != NULL)
8277 ga_append(&ga, tostr[p - fromstr]);
8278 else
8279 ga_append(&ga, *in_str);
8280 ++in_str;
8281 }
8282 }
8283
8284 /* add a terminating NUL */
8285 (void)ga_grow(&ga, 1);
8286 ga_append(&ga, NUL);
8287
8288 rettv->vval.v_string = ga.ga_data;
8289}
8290
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008291/*
8292 * "trim({expr})" function
8293 */
8294 static void
8295f_trim(typval_T *argvars, typval_T *rettv)
8296{
8297 char_u buf1[NUMBUFLEN];
8298 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008299 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008300 char_u *mask = NULL;
8301 char_u *tail;
8302 char_u *prev;
8303 char_u *p;
8304 int c1;
8305
8306 rettv->v_type = VAR_STRING;
8307 if (head == NULL)
8308 {
8309 rettv->vval.v_string = NULL;
8310 return;
8311 }
8312
8313 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008314 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008315
8316 while (*head != NUL)
8317 {
8318 c1 = PTR2CHAR(head);
8319 if (mask == NULL)
8320 {
8321 if (c1 > ' ' && c1 != 0xa0)
8322 break;
8323 }
8324 else
8325 {
8326 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8327 if (c1 == PTR2CHAR(p))
8328 break;
8329 if (*p == NUL)
8330 break;
8331 }
8332 MB_PTR_ADV(head);
8333 }
8334
8335 for (tail = head + STRLEN(head); tail > head; tail = prev)
8336 {
8337 prev = tail;
8338 MB_PTR_BACK(head, prev);
8339 c1 = PTR2CHAR(prev);
8340 if (mask == NULL)
8341 {
8342 if (c1 > ' ' && c1 != 0xa0)
8343 break;
8344 }
8345 else
8346 {
8347 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8348 if (c1 == PTR2CHAR(p))
8349 break;
8350 if (*p == NUL)
8351 break;
8352 }
8353 }
8354 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8355}
8356
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008357#ifdef FEAT_FLOAT
8358/*
8359 * "trunc({float})" function
8360 */
8361 static void
8362f_trunc(typval_T *argvars, typval_T *rettv)
8363{
8364 float_T f = 0.0;
8365
8366 rettv->v_type = VAR_FLOAT;
8367 if (get_float_arg(argvars, &f) == OK)
8368 /* trunc() is not in C90, use floor() or ceil() instead. */
8369 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8370 else
8371 rettv->vval.v_float = 0.0;
8372}
8373#endif
8374
8375/*
8376 * "type(expr)" function
8377 */
8378 static void
8379f_type(typval_T *argvars, typval_T *rettv)
8380{
8381 int n = -1;
8382
8383 switch (argvars[0].v_type)
8384 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008385 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8386 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008387 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008388 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8389 case VAR_LIST: n = VAR_TYPE_LIST; break;
8390 case VAR_DICT: n = VAR_TYPE_DICT; break;
8391 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008392 case VAR_SPECIAL:
8393 if (argvars[0].vval.v_number == VVAL_FALSE
8394 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008395 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008396 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008397 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008399 case VAR_JOB: n = VAR_TYPE_JOB; break;
8400 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008401 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008403 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 n = -1;
8405 break;
8406 }
8407 rettv->vval.v_number = n;
8408}
8409
8410/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008411 * "virtcol(string)" function
8412 */
8413 static void
8414f_virtcol(typval_T *argvars, typval_T *rettv)
8415{
8416 colnr_T vcol = 0;
8417 pos_T *fp;
8418 int fnum = curbuf->b_fnum;
8419
8420 fp = var2fpos(&argvars[0], FALSE, &fnum);
8421 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8422 && fnum == curbuf->b_fnum)
8423 {
8424 getvvcol(curwin, fp, NULL, NULL, &vcol);
8425 ++vcol;
8426 }
8427
8428 rettv->vval.v_number = vcol;
8429}
8430
8431/*
8432 * "visualmode()" function
8433 */
8434 static void
8435f_visualmode(typval_T *argvars, typval_T *rettv)
8436{
8437 char_u str[2];
8438
8439 rettv->v_type = VAR_STRING;
8440 str[0] = curbuf->b_visual_mode_eval;
8441 str[1] = NUL;
8442 rettv->vval.v_string = vim_strsave(str);
8443
8444 /* A non-zero number or non-empty string argument: reset mode. */
8445 if (non_zero_arg(&argvars[0]))
8446 curbuf->b_visual_mode_eval = NUL;
8447}
8448
8449/*
8450 * "wildmenumode()" function
8451 */
8452 static void
8453f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8454{
8455#ifdef FEAT_WILDMENU
8456 if (wild_menu_showing)
8457 rettv->vval.v_number = 1;
8458#endif
8459}
8460
8461/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008462 * "wordcount()" function
8463 */
8464 static void
8465f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8466{
8467 if (rettv_dict_alloc(rettv) == FAIL)
8468 return;
8469 cursor_pos_info(rettv->vval.v_dict);
8470}
8471
8472/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008473 * "xor(expr, expr)" function
8474 */
8475 static void
8476f_xor(typval_T *argvars, typval_T *rettv)
8477{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008478 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8479 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480}
8481
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008482#endif /* FEAT_EVAL */