blob: 9a6187b20af237177d68daaafac73018bcb2f924 [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 Moolenaar73dad1e2016-07-17 22:13:49 +020023#ifdef FEAT_FLOAT
24static void f_abs(typval_T *argvars, typval_T *rettv);
25static void f_acos(typval_T *argvars, typval_T *rettv);
26#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028#ifdef FEAT_FLOAT
29static void f_asin(typval_T *argvars, typval_T *rettv);
30static void f_atan(typval_T *argvars, typval_T *rettv);
31static void f_atan2(typval_T *argvars, typval_T *rettv);
32#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010033#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020034static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010035static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010036# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010037static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010038# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020040static void f_byte2line(typval_T *argvars, typval_T *rettv);
41static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
42static void f_byteidx(typval_T *argvars, typval_T *rettv);
43static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
44static void f_call(typval_T *argvars, typval_T *rettv);
45#ifdef FEAT_FLOAT
46static void f_ceil(typval_T *argvars, typval_T *rettv);
47#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_changenr(typval_T *argvars, typval_T *rettv);
49static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_confirm(typval_T *argvars, typval_T *rettv);
52static void f_copy(typval_T *argvars, typval_T *rettv);
53#ifdef FEAT_FLOAT
54static void f_cos(typval_T *argvars, typval_T *rettv);
55static void f_cosh(typval_T *argvars, typval_T *rettv);
56#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010058#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020059static void f_debugbreak(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010063static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020065static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_escape(typval_T *argvars, typval_T *rettv);
67static void f_eval(typval_T *argvars, typval_T *rettv);
68static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_exists(typval_T *argvars, typval_T *rettv);
71#ifdef FEAT_FLOAT
72static void f_exp(typval_T *argvars, typval_T *rettv);
73#endif
74static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020075static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077#ifdef FEAT_FLOAT
78static void f_float2nr(typval_T *argvars, typval_T *rettv);
79static void f_floor(typval_T *argvars, typval_T *rettv);
80static void f_fmod(typval_T *argvars, typval_T *rettv);
81#endif
82static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020084static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_function(typval_T *argvars, typval_T *rettv);
86static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
87static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010088static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020090static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010092static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getpid(typval_T *argvars, typval_T *rettv);
94static void f_getcurpos(typval_T *argvars, typval_T *rettv);
95static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getreg(typval_T *argvars, typval_T *rettv);
97static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010098static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
100static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_hlID(typval_T *argvars, typval_T *rettv);
102static void f_hlexists(typval_T *argvars, typval_T *rettv);
103static void f_hostname(typval_T *argvars, typval_T *rettv);
104static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_index(typval_T *argvars, typval_T *rettv);
106static void f_input(typval_T *argvars, typval_T *rettv);
107static void f_inputdialog(typval_T *argvars, typval_T *rettv);
108static void f_inputlist(typval_T *argvars, typval_T *rettv);
109static void f_inputrestore(typval_T *argvars, typval_T *rettv);
110static void f_inputsave(typval_T *argvars, typval_T *rettv);
111static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100112static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200113static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_islocked(typval_T *argvars, typval_T *rettv);
115#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200116static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_isnan(typval_T *argvars, typval_T *rettv);
118#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
120static void f_len(typval_T *argvars, typval_T *rettv);
121static void f_libcall(typval_T *argvars, typval_T *rettv);
122static void f_libcallnr(typval_T *argvars, typval_T *rettv);
123static void f_line(typval_T *argvars, typval_T *rettv);
124static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125#ifdef FEAT_FLOAT
126static void f_log(typval_T *argvars, typval_T *rettv);
127static void f_log10(typval_T *argvars, typval_T *rettv);
128#endif
129#ifdef FEAT_LUA
130static void f_luaeval(typval_T *argvars, typval_T *rettv);
131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_maparg(typval_T *argvars, typval_T *rettv);
133static void f_mapcheck(typval_T *argvars, typval_T *rettv);
134static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_matchend(typval_T *argvars, typval_T *rettv);
136static void f_matchlist(typval_T *argvars, typval_T *rettv);
137static void f_matchstr(typval_T *argvars, typval_T *rettv);
138static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
139static void f_max(typval_T *argvars, typval_T *rettv);
140static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141#ifdef FEAT_MZSCHEME
142static void f_mzeval(typval_T *argvars, typval_T *rettv);
143#endif
144static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
145static void f_nr2char(typval_T *argvars, typval_T *rettv);
146static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_PERL
148static void f_perleval(typval_T *argvars, typval_T *rettv);
149#endif
150#ifdef FEAT_FLOAT
151static void f_pow(typval_T *argvars, typval_T *rettv);
152#endif
153static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
154static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200155static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_pumvisible(typval_T *argvars, typval_T *rettv);
157#ifdef FEAT_PYTHON3
158static void f_py3eval(typval_T *argvars, typval_T *rettv);
159#endif
160#ifdef FEAT_PYTHON
161static void f_pyeval(typval_T *argvars, typval_T *rettv);
162#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
164static void f_pyxeval(typval_T *argvars, typval_T *rettv);
165#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100166static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100167static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200169static void f_reg_executing(typval_T *argvars, typval_T *rettv);
170static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_remote_expr(typval_T *argvars, typval_T *rettv);
172static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
173static void f_remote_peek(typval_T *argvars, typval_T *rettv);
174static void f_remote_read(typval_T *argvars, typval_T *rettv);
175static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100176static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_rename(typval_T *argvars, typval_T *rettv);
178static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179#ifdef FEAT_FLOAT
180static void f_round(typval_T *argvars, typval_T *rettv);
181#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100182#ifdef FEAT_RUBY
183static void f_rubyeval(typval_T *argvars, typval_T *rettv);
184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_screenattr(typval_T *argvars, typval_T *rettv);
186static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100187static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_screencol(typval_T *argvars, typval_T *rettv);
189static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100190static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_search(typval_T *argvars, typval_T *rettv);
192static void f_searchdecl(typval_T *argvars, typval_T *rettv);
193static void f_searchpair(typval_T *argvars, typval_T *rettv);
194static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
195static void f_searchpos(typval_T *argvars, typval_T *rettv);
196static void f_server2client(typval_T *argvars, typval_T *rettv);
197static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200199static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100203static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204#ifdef FEAT_CRYPT
205static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_shellescape(typval_T *argvars, typval_T *rettv);
208static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209#ifdef FEAT_FLOAT
210static void f_sin(typval_T *argvars, typval_T *rettv);
211static void f_sinh(typval_T *argvars, typval_T *rettv);
212#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_soundfold(typval_T *argvars, typval_T *rettv);
214static void f_spellbadword(typval_T *argvars, typval_T *rettv);
215static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
216static void f_split(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100219#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100220static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100221#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_str2float(typval_T *argvars, typval_T *rettv);
223#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200224static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_str2nr(typval_T *argvars, typval_T *rettv);
226static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200227static void f_strgetchar(typval_T *argvars, typval_T *rettv);
228static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200229static void f_strlen(typval_T *argvars, typval_T *rettv);
230static void f_strcharpart(typval_T *argvars, typval_T *rettv);
231static void f_strpart(typval_T *argvars, typval_T *rettv);
232static void f_strridx(typval_T *argvars, typval_T *rettv);
233static void f_strtrans(typval_T *argvars, typval_T *rettv);
234static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
235static void f_strwidth(typval_T *argvars, typval_T *rettv);
236static void f_submatch(typval_T *argvars, typval_T *rettv);
237static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200238static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200239static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_synID(typval_T *argvars, typval_T *rettv);
241static void f_synIDattr(typval_T *argvars, typval_T *rettv);
242static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
243static void f_synstack(typval_T *argvars, typval_T *rettv);
244static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_taglist(typval_T *argvars, typval_T *rettv);
247static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248#ifdef FEAT_FLOAT
249static void f_tan(typval_T *argvars, typval_T *rettv);
250static void f_tanh(typval_T *argvars, typval_T *rettv);
251#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200252static void f_tolower(typval_T *argvars, typval_T *rettv);
253static void f_toupper(typval_T *argvars, typval_T *rettv);
254static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100255static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256#ifdef FEAT_FLOAT
257static void f_trunc(typval_T *argvars, typval_T *rettv);
258#endif
259static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_virtcol(typval_T *argvars, typval_T *rettv);
261static void f_visualmode(typval_T *argvars, typval_T *rettv);
262static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100263static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_wordcount(typval_T *argvars, typval_T *rettv);
265static void f_xor(typval_T *argvars, typval_T *rettv);
266
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100267
268 static type_T *
269ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
270{
271 return &t_void;
272}
273 static type_T *
274ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
275{
276 return &t_any;
277}
278 static type_T *
279ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
280{
281 return &t_number;
282}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100283#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100284 static type_T *
285ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
286{
287 return &t_float;
288}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100289#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100290 static type_T *
291ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
292{
293 return &t_string;
294}
295 static type_T * ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
296{
297 return &t_list_any;
298}
299 static type_T *
300ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
301{
302 return &t_list_number;
303}
304 static type_T *
305ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
306{
307 return &t_list_string;
308}
309 static type_T *
310ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
311{
312 return &t_list_dict_any;
313}
314 static type_T *
315ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
316{
317 return &t_dict_any;
318}
319 static type_T *
320ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
321{
322 return &t_dict_number;
323}
324 static type_T *
325ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
326{
327 return &t_dict_string;
328}
329 static type_T *
330ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
331{
332 return &t_blob;
333}
334 static type_T *
335ret_partial_void(int argcount UNUSED, type_T **argtypes UNUSED)
336{
337 return &t_partial_void;
338}
339#ifdef FEAT_JOB_CHANNEL
340 static type_T *
341ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
342{
343 return &t_channel;
344}
345 static type_T *
346ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
347{
348 return &t_job;
349}
350#endif
351
352static type_T *ret_f_function(int argcount, type_T **argtypes);
353
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200354/*
355 * Array with names and number of arguments of all internal functions
356 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
357 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200358typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200360 char *f_name; // function name
361 char f_min_argc; // minimal number of arguments
362 char f_max_argc; // maximal number of arguments
363 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100364 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
365 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200367 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200368} funcentry_T;
369
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200370// values for f_argtype; zero means it cannot be used as a method
371#define FEARG_1 1 // base is the first argument
372#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200373#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200374#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200375#define FEARG_LAST 9 // base is the last argument
376
Bram Moolenaarac92e252019-08-03 21:58:38 +0200377static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378{
379#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100380 {"abs", 1, 1, FEARG_1, ret_any, f_abs},
381 {"acos", 1, 1, FEARG_1, ret_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200382#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100383 {"add", 2, 2, FEARG_1, ret_any, f_add},
384 {"and", 2, 2, FEARG_1, ret_number, f_and},
385 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
386 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
387 {"argc", 0, 1, 0, ret_number, f_argc},
388 {"argidx", 0, 0, 0, ret_number, f_argidx},
389 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
390 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100392 {"asin", 1, 1, FEARG_1, ret_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200393#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100394 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
395 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
396 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile},
397 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
398 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
399 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
400 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
401 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
402 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
403 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
404 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
405 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100407 {"atan", 1, 1, FEARG_1, ret_float, f_atan},
408 {"atan2", 2, 2, FEARG_1, ret_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100410#ifdef FEAT_BEVAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100411 {"balloon_gettext", 0, 0, 0, ret_string, f_balloon_gettext},
412 {"balloon_show", 1, 1, FEARG_1, ret_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100413# if defined(FEAT_BEVAL_TERM)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100414 {"balloon_split", 1, 1, FEARG_1, ret_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100415# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100416#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100417 {"browse", 4, 4, 0, ret_string, f_browse},
418 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
419 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
420 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
421 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
422 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
423 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
424 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
425 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
426 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
427 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
428 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
429 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
430 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
431 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
432 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
433 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
434 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100436 {"ceil", 1, 1, FEARG_1, ret_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
438#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100439 {"ch_canread", 1, 1, FEARG_1, ret_number, f_ch_canread},
440 {"ch_close", 1, 1, FEARG_1, ret_void, f_ch_close},
441 {"ch_close_in", 1, 1, FEARG_1, ret_void, f_ch_close_in},
442 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, f_ch_evalexpr},
443 {"ch_evalraw", 2, 3, FEARG_1, ret_any, f_ch_evalraw},
444 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, f_ch_getbufnr},
445 {"ch_getjob", 1, 1, FEARG_1, ret_job, f_ch_getjob},
446 {"ch_info", 1, 1, FEARG_1, ret_dict_any, f_ch_info},
447 {"ch_log", 1, 2, FEARG_1, ret_void, f_ch_log},
448 {"ch_logfile", 1, 2, FEARG_1, ret_void, f_ch_logfile},
449 {"ch_open", 1, 2, FEARG_1, ret_channel, f_ch_open},
450 {"ch_read", 1, 2, FEARG_1, ret_string, f_ch_read},
451 {"ch_readblob", 1, 2, FEARG_1, ret_blob, f_ch_readblob},
452 {"ch_readraw", 1, 2, FEARG_1, ret_string, f_ch_readraw},
453 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, f_ch_sendexpr},
454 {"ch_sendraw", 2, 3, FEARG_1, ret_void, f_ch_sendraw},
455 {"ch_setoptions", 2, 2, FEARG_1, ret_void, f_ch_setoptions},
456 {"ch_status", 1, 2, FEARG_1, ret_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200457#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100458 {"changenr", 0, 0, 0, ret_number, f_changenr},
459 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
460 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
461 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
462 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
463 {"col", 1, 1, FEARG_1, ret_number, f_col},
464 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
465 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
466 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
467 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
468 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
469 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200470#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100471 {"cos", 1, 1, FEARG_1, ret_float, f_cos},
472 {"cosh", 1, 1, FEARG_1, ret_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100474 {"count", 2, 4, FEARG_1, ret_number, f_count},
475 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
476 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100477#ifdef MSWIN
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100478 {"debugbreak", 1, 1, FEARG_1, ret_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200479#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100480 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
481 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
482 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
483 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
484 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
485 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
486 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
487 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
488 {"environ", 0, 0, 0, ret_dict_string, f_environ},
489 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
490 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
491 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
492 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
493 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
494 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
495 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200496#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"exp", 1, 1, FEARG_1, ret_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100499 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
500 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
501 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
502 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
503 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
504 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
505 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
506 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
507 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
508 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100510 {"float2nr", 1, 1, FEARG_1, ret_number, f_float2nr},
511 {"floor", 1, 1, FEARG_1, ret_float, f_floor},
512 {"fmod", 2, 2, FEARG_1, ret_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100514 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
515 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
516 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
517 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
518 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
519 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
520 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
521 {"foreground", 0, 0, 0, ret_void, f_foreground},
522 {"funcref", 1, 3, FEARG_1, ret_partial_void, f_funcref},
523 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
524 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
525 {"get", 2, 3, FEARG_1, ret_any, f_get},
526 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
527 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
528 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
529 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
530 {"getchar", 0, 1, 0, ret_number, f_getchar},
531 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
532 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
533 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
534 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
535 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
536 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
537 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
538 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
539 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
540 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
541 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
542 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
543 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
544 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
545 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
546 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
547 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
548 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
549 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
550 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
551 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
552 {"getpid", 0, 0, 0, ret_number, f_getpid},
553 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
554 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
555 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
556 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
557 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
558 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
559 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
560 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
561 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
562 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
563 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
564 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
565 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
566 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
567 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
568 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
569 {"has", 1, 1, 0, ret_number, f_has},
570 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
571 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
572 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
573 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
574 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
575 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
576 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
577 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
578 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
579 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
580 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
581 {"hostname", 0, 0, 0, ret_string, f_hostname},
582 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
583 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
584 {"index", 2, 4, FEARG_1, ret_number, f_index},
585 {"input", 1, 3, FEARG_1, ret_string, f_input},
586 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
587 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
588 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
589 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
590 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
591 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
592 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
593 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
594 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200595#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100596 {"isinf", 1, 1, FEARG_1, ret_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200597#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100598 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"isnan", 1, 1, FEARG_1, ret_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100602 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100604 {"job_getchannel", 1, 1, FEARG_1, ret_channel, f_job_getchannel},
605 {"job_info", 0, 1, FEARG_1, ret_dict_any, f_job_info},
606 {"job_setoptions", 2, 2, FEARG_1, ret_void, f_job_setoptions},
607 {"job_start", 1, 2, FEARG_1, ret_job, f_job_start},
608 {"job_status", 1, 1, FEARG_1, ret_string, f_job_status},
609 {"job_stop", 1, 2, FEARG_1, ret_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100611 {"join", 1, 2, FEARG_1, ret_string, f_join},
612 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
613 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
614 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
615 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
616 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
617 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
618 {"len", 1, 1, FEARG_1, ret_number, f_len},
619 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
620 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
621 {"line", 1, 2, FEARG_1, ret_number, f_line},
622 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
623 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
624 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
625 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
626 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
627 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
628 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200629#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100630 {"log", 1, 1, FEARG_1, ret_float, f_log},
631 {"log10", 1, 1, FEARG_1, ret_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#endif
633#ifdef FEAT_LUA
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"luaeval", 1, 2, FEARG_1, ret_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100636 {"map", 2, 2, FEARG_1, ret_any, f_map},
637 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
638 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
639 {"match", 2, 4, FEARG_1, ret_any, f_match},
640 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
641 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
642 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
643 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
644 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
645 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
646 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
647 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
648 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100649#ifdef FEAT_MENU
Bram Moolenaar0eabd4d2020-03-15 16:13:53 +0100650 {"menu_info", 1, 2, FEARG_1, ret_dict_any, f_menu_info},
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100651#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100652 {"min", 1, 1, FEARG_1, ret_any, f_min},
653 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
654 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#ifdef FEAT_MZSCHEME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100656 {"mzeval", 1, 1, FEARG_1, ret_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100658 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
659 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
660 {"or", 2, 2, FEARG_1, ret_number, f_or},
661 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662#ifdef FEAT_PERL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100663 {"perleval", 1, 1, FEARG_1, ret_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200664#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100665#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100666 {"popup_atcursor", 2, 2, FEARG_1, ret_number, f_popup_atcursor},
667 {"popup_beval", 2, 2, FEARG_1, ret_number, f_popup_beval},
668 {"popup_clear", 0, 0, 0, ret_void, f_popup_clear},
669 {"popup_close", 1, 2, FEARG_1, ret_void, f_popup_close},
670 {"popup_create", 2, 2, FEARG_1, ret_number, f_popup_create},
671 {"popup_dialog", 2, 2, FEARG_1, ret_number, f_popup_dialog},
672 {"popup_filter_menu", 2, 2, 0, ret_number, f_popup_filter_menu},
673 {"popup_filter_yesno", 2, 2, 0, ret_number, f_popup_filter_yesno},
674 {"popup_findinfo", 0, 0, 0, ret_number, f_popup_findinfo},
675 {"popup_findpreview", 0, 0, 0, ret_number, f_popup_findpreview},
676 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, f_popup_getoptions},
677 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, f_popup_getpos},
678 {"popup_hide", 1, 1, FEARG_1, ret_void, f_popup_hide},
679 {"popup_locate", 2, 2, 0, ret_number, f_popup_locate},
680 {"popup_menu", 2, 2, FEARG_1, ret_number, f_popup_menu},
681 {"popup_move", 2, 2, FEARG_1, ret_void, f_popup_move},
682 {"popup_notification", 2, 2, FEARG_1, ret_number, f_popup_notification},
683 {"popup_setoptions", 2, 2, FEARG_1, ret_void, f_popup_setoptions},
684 {"popup_settext", 2, 2, FEARG_1, ret_void, f_popup_settext},
685 {"popup_show", 1, 1, FEARG_1, ret_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200686#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200687#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100688 {"pow", 2, 2, FEARG_1, ret_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200689#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100690 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
691 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200692#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100693 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, f_prompt_setcallback},
694 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, f_prompt_setinterrupt},
695 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200696#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100697#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100698 {"prop_add", 3, 3, FEARG_1, ret_void, f_prop_add},
699 {"prop_clear", 1, 3, FEARG_1, ret_void, f_prop_clear},
700 {"prop_find", 1, 2, FEARG_1, ret_dict_any, f_prop_find},
701 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, f_prop_list},
702 {"prop_remove", 1, 3, FEARG_1, ret_number, f_prop_remove},
703 {"prop_type_add", 2, 2, FEARG_1, ret_void, f_prop_type_add},
704 {"prop_type_change", 2, 2, FEARG_1, ret_void, f_prop_type_change},
705 {"prop_type_delete", 1, 2, FEARG_1, ret_void, f_prop_type_delete},
706 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, f_prop_type_get},
707 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100708#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100709 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
710 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200711#ifdef FEAT_PYTHON3
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100712 {"py3eval", 1, 1, FEARG_1, ret_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200713#endif
714#ifdef FEAT_PYTHON
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100715 {"pyeval", 1, 1, FEARG_1, ret_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200716#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100717#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100718 {"pyxeval", 1, 1, FEARG_1, ret_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100719#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100720 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
721 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
722 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
723 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
724 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
725 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
726 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100728 {"reltimefloat", 1, 1, FEARG_1, ret_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200729#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100730 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
731 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
732 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
733 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
734 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
735 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
736 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
737 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
738 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
739 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
740 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
741 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200742#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100743 {"round", 1, 1, FEARG_1, ret_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100745#ifdef FEAT_RUBY
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100746 {"rubyeval", 1, 1, FEARG_1, ret_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100747#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100748 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
749 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
750 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
751 {"screencol", 0, 0, 0, ret_number, f_screencol},
752 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
753 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
754 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
755 {"search", 1, 4, FEARG_1, ret_number, f_search},
756 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
757 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
758 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
759 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
760 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
761 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
762 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
763 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
764 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
765 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
766 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
767 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
768 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
769 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
770 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
771 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
772 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
773 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
774 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
775 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
776 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
777 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778#ifdef FEAT_CRYPT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100779 {"sha256", 1, 1, FEARG_1, ret_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200780#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100781 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
782 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100783#ifdef FEAT_SIGNS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100784 {"sign_define", 1, 2, FEARG_1, ret_any, f_sign_define},
785 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, f_sign_getdefined},
786 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, f_sign_getplaced},
787 {"sign_jump", 3, 3, FEARG_1, ret_number, f_sign_jump},
788 {"sign_place", 4, 5, FEARG_1, ret_number, f_sign_place},
789 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, f_sign_placelist},
790 {"sign_undefine", 0, 1, FEARG_1, ret_number, f_sign_undefine},
791 {"sign_unplace", 1, 2, FEARG_1, ret_number, f_sign_unplace},
792 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100793#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100794 {"simplify", 1, 1, 0, ret_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200795#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100796 {"sin", 1, 1, FEARG_1, ret_float, f_sin},
797 {"sinh", 1, 1, FEARG_1, ret_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200798#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100799 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200800#ifdef FEAT_SOUND
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100801 {"sound_clear", 0, 0, 0, ret_void, f_sound_clear},
802 {"sound_playevent", 1, 2, FEARG_1, ret_number, f_sound_playevent},
803 {"sound_playfile", 1, 2, FEARG_1, ret_number, f_sound_playfile},
804 {"sound_stop", 1, 1, FEARG_1, ret_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200805#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100806 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
807 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
808 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
809 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200810#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100811 {"sqrt", 1, 1, FEARG_1, ret_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200812#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100813 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
814 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200815#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100816 {"str2float", 1, 1, FEARG_1, ret_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100818 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
819 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
820 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
821 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
822 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823#ifdef HAVE_STRFTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100824 {"strftime", 1, 2, FEARG_1, ret_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100826 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
827 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
828 {"string", 1, 1, FEARG_1, ret_string, f_string},
829 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
830 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100831#ifdef HAVE_STRPTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100832 {"strptime", 2, 2, FEARG_1, ret_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100833#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100834 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
835 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
836 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
837 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
838 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
839 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
840 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
841 {"synID", 3, 3, 0, ret_number, f_synID},
842 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
843 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
844 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
845 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
846 {"system", 1, 2, FEARG_1, ret_string, f_system},
847 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
848 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
849 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
850 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
851 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
852 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100854 {"tan", 1, 1, FEARG_1, ret_float, f_tan},
855 {"tanh", 1, 1, FEARG_1, ret_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100857 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200858#ifdef FEAT_TERMINAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100859 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, f_term_dumpdiff},
860 {"term_dumpload", 1, 2, FEARG_1, ret_number, f_term_dumpload},
861 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, f_term_dumpwrite},
862 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200863# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100864 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200865# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100866 {"term_getattr", 2, 2, FEARG_1, ret_number, f_term_getattr},
867 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, f_term_getcursor},
868 {"term_getjob", 1, 1, FEARG_1, ret_job, f_term_getjob},
869 {"term_getline", 2, 2, FEARG_1, ret_string, f_term_getline},
870 {"term_getscrolled", 1, 1, FEARG_1, ret_number, f_term_getscrolled},
871 {"term_getsize", 1, 1, FEARG_1, ret_list_number, f_term_getsize},
872 {"term_getstatus", 1, 1, FEARG_1, ret_string, f_term_getstatus},
873 {"term_gettitle", 1, 1, FEARG_1, ret_string, f_term_gettitle},
874 {"term_gettty", 1, 2, FEARG_1, ret_string, f_term_gettty},
875 {"term_list", 0, 0, 0, ret_list_number, f_term_list},
876 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, f_term_scrape},
877 {"term_sendkeys", 2, 2, FEARG_1, ret_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200878# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100879 {"term_setansicolors", 2, 2, FEARG_1, ret_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200880# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100881 {"term_setapi", 2, 2, FEARG_1, ret_void, f_term_setapi},
882 {"term_setkill", 2, 2, FEARG_1, ret_void, f_term_setkill},
883 {"term_setrestore", 2, 2, FEARG_1, ret_void, f_term_setrestore},
884 {"term_setsize", 3, 3, FEARG_1, ret_void, f_term_setsize},
885 {"term_start", 1, 2, FEARG_1, ret_number, f_term_start},
886 {"term_wait", 1, 2, FEARG_1, ret_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200887#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100888 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
889 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
890 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
891 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
892 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
893 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
894 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
895 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200896#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100897 {"test_null_channel", 0, 0, 0, ret_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200898#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100899 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200900#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100901 {"test_null_job", 0, 0, 0, ret_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200902#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100903 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
904 {"test_null_partial", 0, 0, 0, ret_partial_void, f_test_null_partial},
905 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
906 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
907 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
908 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200909#ifdef FEAT_GUI
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100910 {"test_scrollbar", 3, 3, FEARG_2, ret_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200911#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100912 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
913 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
914 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
915 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
916 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917#ifdef FEAT_TIMERS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100918 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, f_timer_info},
919 {"timer_pause", 2, 2, FEARG_1, ret_void, f_timer_pause},
920 {"timer_start", 2, 3, FEARG_1, ret_number, f_timer_start},
921 {"timer_stop", 1, 1, FEARG_1, ret_void, f_timer_stop},
922 {"timer_stopall", 0, 0, 0, ret_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100924 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
925 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
926 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
927 {"trim", 1, 2, FEARG_1, ret_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100929 {"trunc", 1, 1, FEARG_1, ret_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100931 {"type", 1, 1, FEARG_1, ret_number, f_type},
932 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
933 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
934 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
935 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
936 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
937 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
938 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
939 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
940 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
941 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
942 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
943 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
944 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
945 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
946 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
947 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
948 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
949 {"wincol", 0, 0, 0, ret_number, f_wincol},
950 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
951 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
952 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
953 {"winline", 0, 0, 0, ret_number, f_winline},
954 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
955 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
956 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
957 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
958 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
959 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
960 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
961 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200962};
963
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964/*
965 * Function given to ExpandGeneric() to obtain the list of internal
966 * or user defined function names.
967 */
968 char_u *
969get_function_name(expand_T *xp, int idx)
970{
971 static int intidx = -1;
972 char_u *name;
973
974 if (idx == 0)
975 intidx = -1;
976 if (intidx < 0)
977 {
978 name = get_user_func_name(xp, idx);
979 if (name != NULL)
980 return name;
981 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200982 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200983 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200984 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200985 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200986 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200987 STRCAT(IObuff, ")");
988 return IObuff;
989 }
990
991 return NULL;
992}
993
994/*
995 * Function given to ExpandGeneric() to obtain the list of internal or
996 * user defined variable or function names.
997 */
998 char_u *
999get_expr_name(expand_T *xp, int idx)
1000{
1001 static int intidx = -1;
1002 char_u *name;
1003
1004 if (idx == 0)
1005 intidx = -1;
1006 if (intidx < 0)
1007 {
1008 name = get_function_name(xp, idx);
1009 if (name != NULL)
1010 return name;
1011 }
1012 return get_user_var_name(xp, ++intidx);
1013}
1014
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001015/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001016 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001017 * Return index, or -1 if not found
1018 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001019 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001020find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001021{
1022 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001023 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001024 int cmp;
1025 int x;
1026
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001027 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001028
1029 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001030 while (first <= last)
1031 {
1032 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001033 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001034 if (cmp < 0)
1035 last = x - 1;
1036 else if (cmp > 0)
1037 first = x + 1;
1038 else
1039 return x;
1040 }
1041 return -1;
1042}
1043
1044 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001045has_internal_func(char_u *name)
1046{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001047 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001048}
1049
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001050 char *
1051internal_func_name(int idx)
1052{
1053 return global_functions[idx].f_name;
1054}
1055
1056 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001057internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001058{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001059 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001060}
1061
1062/*
1063 * Check the argument count to use for internal function "idx".
1064 * Returns OK or FAIL;
1065 */
1066 int
1067check_internal_func(int idx, int argcount)
1068{
1069 int res;
1070 char *name;
1071
1072 if (argcount < global_functions[idx].f_min_argc)
1073 res = FCERR_TOOFEW;
1074 else if (argcount > global_functions[idx].f_max_argc)
1075 res = FCERR_TOOMANY;
1076 else
1077 return OK;
1078
1079 name = internal_func_name(idx);
1080 if (res == FCERR_TOOMANY)
1081 semsg(_(e_toomanyarg), name);
1082 else
1083 semsg(_(e_toofewarg), name);
1084 return FAIL;
1085}
1086
Bram Moolenaarac92e252019-08-03 21:58:38 +02001087 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001088call_internal_func(
1089 char_u *name,
1090 int argcount,
1091 typval_T *argvars,
1092 typval_T *rettv)
1093{
1094 int i;
1095
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001096 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001097 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001098 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001099 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001100 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001101 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001102 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001103 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001104 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001105 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001106}
1107
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001108 void
1109call_internal_func_by_idx(
1110 int idx,
1111 typval_T *argvars,
1112 typval_T *rettv)
1113{
1114 global_functions[idx].f_func(argvars, rettv);
1115}
1116
Bram Moolenaarac92e252019-08-03 21:58:38 +02001117/*
1118 * Invoke a method for base->method().
1119 */
1120 int
1121call_internal_method(
1122 char_u *name,
1123 int argcount,
1124 typval_T *argvars,
1125 typval_T *rettv,
1126 typval_T *basetv)
1127{
1128 int i;
1129 int fi;
1130 typval_T argv[MAX_FUNC_ARGS + 1];
1131
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001132 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001133 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001134 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001135 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001136 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001137 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001138 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001139 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001140 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001141
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001142 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001143 {
1144 // base value goes last
1145 for (i = 0; i < argcount; ++i)
1146 argv[i] = argvars[i];
1147 argv[argcount] = *basetv;
1148 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001149 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001150 {
1151 // base value goes second
1152 argv[0] = argvars[0];
1153 argv[1] = *basetv;
1154 for (i = 1; i < argcount; ++i)
1155 argv[i + 1] = argvars[i];
1156 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001157 else if (global_functions[fi].f_argtype == FEARG_3)
1158 {
1159 // base value goes third
1160 argv[0] = argvars[0];
1161 argv[1] = argvars[1];
1162 argv[2] = *basetv;
1163 for (i = 2; i < argcount; ++i)
1164 argv[i + 1] = argvars[i];
1165 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001166 else if (global_functions[fi].f_argtype == FEARG_4)
1167 {
1168 // base value goes fourth
1169 argv[0] = argvars[0];
1170 argv[1] = argvars[1];
1171 argv[2] = argvars[2];
1172 argv[3] = *basetv;
1173 for (i = 3; i < argcount; ++i)
1174 argv[i + 1] = argvars[i];
1175 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001176 else
1177 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001178 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001179 argv[0] = *basetv;
1180 for (i = 0; i < argcount; ++i)
1181 argv[i + 1] = argvars[i];
1182 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001183 argv[argcount + 1].v_type = VAR_UNKNOWN;
1184
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001185 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001186 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001187}
1188
1189/*
1190 * Return TRUE for a non-zero Number and a non-empty String.
1191 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001192 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001193non_zero_arg(typval_T *argvars)
1194{
1195 return ((argvars[0].v_type == VAR_NUMBER
1196 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001197 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001198 && argvars[0].vval.v_number == VVAL_TRUE)
1199 || (argvars[0].v_type == VAR_STRING
1200 && argvars[0].vval.v_string != NULL
1201 && *argvars[0].vval.v_string != NUL));
1202}
1203
1204/*
1205 * Get the lnum from the first argument.
1206 * Also accepts ".", "$", etc., but that only works for the current buffer.
1207 * Returns -1 on error.
1208 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001209 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001210tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001211{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001212 linenr_T lnum;
1213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001214 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001215 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001216 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001217 int fnum;
1218 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1219
1220 if (fp != NULL)
1221 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001222 }
1223 return lnum;
1224}
1225
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001226/*
1227 * Get the lnum from the first argument.
1228 * Also accepts "$", then "buf" is used.
1229 * Returns 0 on error.
1230 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001231 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001232tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1233{
1234 if (argvars[0].v_type == VAR_STRING
1235 && argvars[0].vval.v_string != NULL
1236 && argvars[0].vval.v_string[0] == '$'
1237 && buf != NULL)
1238 return buf->b_ml.ml_line_count;
1239 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1240}
1241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001243/*
1244 * Get the float value of "argvars[0]" into "f".
1245 * Returns FAIL when the argument is not a Number or Float.
1246 */
1247 static int
1248get_float_arg(typval_T *argvars, float_T *f)
1249{
1250 if (argvars[0].v_type == VAR_FLOAT)
1251 {
1252 *f = argvars[0].vval.v_float;
1253 return OK;
1254 }
1255 if (argvars[0].v_type == VAR_NUMBER)
1256 {
1257 *f = (float_T)argvars[0].vval.v_number;
1258 return OK;
1259 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001260 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001261 return FAIL;
1262}
1263
1264/*
1265 * "abs(expr)" function
1266 */
1267 static void
1268f_abs(typval_T *argvars, typval_T *rettv)
1269{
1270 if (argvars[0].v_type == VAR_FLOAT)
1271 {
1272 rettv->v_type = VAR_FLOAT;
1273 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1274 }
1275 else
1276 {
1277 varnumber_T n;
1278 int error = FALSE;
1279
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001280 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001281 if (error)
1282 rettv->vval.v_number = -1;
1283 else if (n > 0)
1284 rettv->vval.v_number = n;
1285 else
1286 rettv->vval.v_number = -n;
1287 }
1288}
1289
1290/*
1291 * "acos()" function
1292 */
1293 static void
1294f_acos(typval_T *argvars, typval_T *rettv)
1295{
1296 float_T f = 0.0;
1297
1298 rettv->v_type = VAR_FLOAT;
1299 if (get_float_arg(argvars, &f) == OK)
1300 rettv->vval.v_float = acos(f);
1301 else
1302 rettv->vval.v_float = 0.0;
1303}
1304#endif
1305
1306/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 * "and(expr, expr)" function
1308 */
1309 static void
1310f_and(typval_T *argvars, typval_T *rettv)
1311{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001312 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1313 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001314}
1315
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001316#ifdef FEAT_FLOAT
1317/*
1318 * "asin()" function
1319 */
1320 static void
1321f_asin(typval_T *argvars, typval_T *rettv)
1322{
1323 float_T f = 0.0;
1324
1325 rettv->v_type = VAR_FLOAT;
1326 if (get_float_arg(argvars, &f) == OK)
1327 rettv->vval.v_float = asin(f);
1328 else
1329 rettv->vval.v_float = 0.0;
1330}
1331
1332/*
1333 * "atan()" function
1334 */
1335 static void
1336f_atan(typval_T *argvars, typval_T *rettv)
1337{
1338 float_T f = 0.0;
1339
1340 rettv->v_type = VAR_FLOAT;
1341 if (get_float_arg(argvars, &f) == OK)
1342 rettv->vval.v_float = atan(f);
1343 else
1344 rettv->vval.v_float = 0.0;
1345}
1346
1347/*
1348 * "atan2()" function
1349 */
1350 static void
1351f_atan2(typval_T *argvars, typval_T *rettv)
1352{
1353 float_T fx = 0.0, fy = 0.0;
1354
1355 rettv->v_type = VAR_FLOAT;
1356 if (get_float_arg(argvars, &fx) == OK
1357 && get_float_arg(&argvars[1], &fy) == OK)
1358 rettv->vval.v_float = atan2(fx, fy);
1359 else
1360 rettv->vval.v_float = 0.0;
1361}
1362#endif
1363
1364/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001365 * "balloon_show()" function
1366 */
1367#ifdef FEAT_BEVAL
1368 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001369f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1370{
1371 rettv->v_type = VAR_STRING;
1372 if (balloonEval != NULL)
1373 {
1374 if (balloonEval->msg == NULL)
1375 rettv->vval.v_string = NULL;
1376 else
1377 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1378 }
1379}
1380
1381 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001382f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1383{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001384 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001385 {
1386 if (argvars[0].v_type == VAR_LIST
1387# ifdef FEAT_GUI
1388 && !gui.in_use
1389# endif
1390 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001391 {
1392 list_T *l = argvars[0].vval.v_list;
1393
1394 // empty list removes the balloon
1395 post_balloon(balloonEval, NULL,
1396 l == NULL || l->lv_len == 0 ? NULL : l);
1397 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001398 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001399 {
1400 char_u *mesg = tv_get_string_chk(&argvars[0]);
1401
1402 if (mesg != NULL)
1403 // empty string removes the balloon
1404 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1405 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001406 }
1407}
1408
Bram Moolenaar669a8282017-11-19 20:13:05 +01001409# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001410 static void
1411f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1412{
1413 if (rettv_list_alloc(rettv) == OK)
1414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001415 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001416
1417 if (msg != NULL)
1418 {
1419 pumitem_T *array;
1420 int size = split_message(msg, &array);
1421 int i;
1422
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001423 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001424 for (i = 1; i < size - 1; ++i)
1425 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001426 while (size > 0)
1427 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001428 vim_free(array);
1429 }
1430 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001431}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001432# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001433#endif
1434
1435/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001436 * Get buffer by number or pattern.
1437 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001438 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001439tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001440{
1441 char_u *name = tv->vval.v_string;
1442 buf_T *buf;
1443
1444 if (tv->v_type == VAR_NUMBER)
1445 return buflist_findnr((int)tv->vval.v_number);
1446 if (tv->v_type != VAR_STRING)
1447 return NULL;
1448 if (name == NULL || *name == NUL)
1449 return curbuf;
1450 if (name[0] == '$' && name[1] == NUL)
1451 return lastbuf;
1452
1453 buf = buflist_find_by_name(name, curtab_only);
1454
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001455 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001456 if (buf == NULL)
1457 buf = find_buffer(tv);
1458
1459 return buf;
1460}
1461
1462/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001463 * Get the buffer from "arg" and give an error and return NULL if it is not
1464 * valid.
1465 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001466 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001467get_buf_arg(typval_T *arg)
1468{
1469 buf_T *buf;
1470
1471 ++emsg_off;
1472 buf = tv_get_buf(arg, FALSE);
1473 --emsg_off;
1474 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001475 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001476 return buf;
1477}
1478
1479/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480 * "byte2line(byte)" function
1481 */
1482 static void
1483f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1484{
1485#ifndef FEAT_BYTEOFF
1486 rettv->vval.v_number = -1;
1487#else
1488 long boff = 0;
1489
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001490 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001491 if (boff < 0)
1492 rettv->vval.v_number = -1;
1493 else
1494 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1495 (linenr_T)0, &boff);
1496#endif
1497}
1498
1499 static void
1500byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1501{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001503 char_u *str;
1504 varnumber_T idx;
1505
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001506 str = tv_get_string_chk(&argvars[0]);
1507 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508 rettv->vval.v_number = -1;
1509 if (str == NULL || idx < 0)
1510 return;
1511
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512 t = str;
1513 for ( ; idx > 0; idx--)
1514 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001515 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001516 return;
1517 if (enc_utf8 && comp)
1518 t += utf_ptr2len(t);
1519 else
1520 t += (*mb_ptr2len)(t);
1521 }
1522 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001523}
1524
1525/*
1526 * "byteidx()" function
1527 */
1528 static void
1529f_byteidx(typval_T *argvars, typval_T *rettv)
1530{
1531 byteidx(argvars, rettv, FALSE);
1532}
1533
1534/*
1535 * "byteidxcomp()" function
1536 */
1537 static void
1538f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1539{
1540 byteidx(argvars, rettv, TRUE);
1541}
1542
1543/*
1544 * "call(func, arglist [, dict])" function
1545 */
1546 static void
1547f_call(typval_T *argvars, typval_T *rettv)
1548{
1549 char_u *func;
1550 partial_T *partial = NULL;
1551 dict_T *selfdict = NULL;
1552
1553 if (argvars[1].v_type != VAR_LIST)
1554 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001555 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 return;
1557 }
1558 if (argvars[1].vval.v_list == NULL)
1559 return;
1560
1561 if (argvars[0].v_type == VAR_FUNC)
1562 func = argvars[0].vval.v_string;
1563 else if (argvars[0].v_type == VAR_PARTIAL)
1564 {
1565 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001566 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567 }
1568 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001569 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001571 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572
1573 if (argvars[2].v_type != VAR_UNKNOWN)
1574 {
1575 if (argvars[2].v_type != VAR_DICT)
1576 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001577 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578 return;
1579 }
1580 selfdict = argvars[2].vval.v_dict;
1581 }
1582
1583 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1584}
1585
1586#ifdef FEAT_FLOAT
1587/*
1588 * "ceil({float})" function
1589 */
1590 static void
1591f_ceil(typval_T *argvars, typval_T *rettv)
1592{
1593 float_T f = 0.0;
1594
1595 rettv->v_type = VAR_FLOAT;
1596 if (get_float_arg(argvars, &f) == OK)
1597 rettv->vval.v_float = ceil(f);
1598 else
1599 rettv->vval.v_float = 0.0;
1600}
1601#endif
1602
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603/*
1604 * "changenr()" function
1605 */
1606 static void
1607f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1608{
1609 rettv->vval.v_number = curbuf->b_u_seq_cur;
1610}
1611
1612/*
1613 * "char2nr(string)" function
1614 */
1615 static void
1616f_char2nr(typval_T *argvars, typval_T *rettv)
1617{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001618 if (has_mbyte)
1619 {
1620 int utf8 = 0;
1621
1622 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001623 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624
1625 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001626 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001628 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001629 }
1630 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001631 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001632}
1633
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001634 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001635get_optional_window(typval_T *argvars, int idx)
1636{
1637 win_T *win = curwin;
1638
1639 if (argvars[idx].v_type != VAR_UNKNOWN)
1640 {
1641 win = find_win_by_nr_or_id(&argvars[idx]);
1642 if (win == NULL)
1643 {
1644 emsg(_(e_invalwindow));
1645 return NULL;
1646 }
1647 }
1648 return win;
1649}
1650
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001652 * "col(string)" function
1653 */
1654 static void
1655f_col(typval_T *argvars, typval_T *rettv)
1656{
1657 colnr_T col = 0;
1658 pos_T *fp;
1659 int fnum = curbuf->b_fnum;
1660
1661 fp = var2fpos(&argvars[0], FALSE, &fnum);
1662 if (fp != NULL && fnum == curbuf->b_fnum)
1663 {
1664 if (fp->col == MAXCOL)
1665 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001666 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1668 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1669 else
1670 col = MAXCOL;
1671 }
1672 else
1673 {
1674 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001675 // col(".") when the cursor is on the NUL at the end of the line
1676 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001677 if (virtual_active() && fp == &curwin->w_cursor)
1678 {
1679 char_u *p = ml_get_cursor();
1680
1681 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1682 curwin->w_virtcol - curwin->w_cursor.coladd))
1683 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001684 int l;
1685
1686 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1687 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 }
1689 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001690 }
1691 }
1692 rettv->vval.v_number = col;
1693}
1694
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695/*
1696 * "confirm(message, buttons[, default [, type]])" function
1697 */
1698 static void
1699f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1700{
1701#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1702 char_u *message;
1703 char_u *buttons = NULL;
1704 char_u buf[NUMBUFLEN];
1705 char_u buf2[NUMBUFLEN];
1706 int def = 1;
1707 int type = VIM_GENERIC;
1708 char_u *typestr;
1709 int error = FALSE;
1710
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001711 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 if (message == NULL)
1713 error = TRUE;
1714 if (argvars[1].v_type != VAR_UNKNOWN)
1715 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001716 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001717 if (buttons == NULL)
1718 error = TRUE;
1719 if (argvars[2].v_type != VAR_UNKNOWN)
1720 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001721 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722 if (argvars[3].v_type != VAR_UNKNOWN)
1723 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001724 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 if (typestr == NULL)
1726 error = TRUE;
1727 else
1728 {
1729 switch (TOUPPER_ASC(*typestr))
1730 {
1731 case 'E': type = VIM_ERROR; break;
1732 case 'Q': type = VIM_QUESTION; break;
1733 case 'I': type = VIM_INFO; break;
1734 case 'W': type = VIM_WARNING; break;
1735 case 'G': type = VIM_GENERIC; break;
1736 }
1737 }
1738 }
1739 }
1740 }
1741
1742 if (buttons == NULL || *buttons == NUL)
1743 buttons = (char_u *)_("&Ok");
1744
1745 if (!error)
1746 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1747 def, NULL, FALSE);
1748#endif
1749}
1750
1751/*
1752 * "copy()" function
1753 */
1754 static void
1755f_copy(typval_T *argvars, typval_T *rettv)
1756{
1757 item_copy(&argvars[0], rettv, FALSE, 0);
1758}
1759
1760#ifdef FEAT_FLOAT
1761/*
1762 * "cos()" function
1763 */
1764 static void
1765f_cos(typval_T *argvars, typval_T *rettv)
1766{
1767 float_T f = 0.0;
1768
1769 rettv->v_type = VAR_FLOAT;
1770 if (get_float_arg(argvars, &f) == OK)
1771 rettv->vval.v_float = cos(f);
1772 else
1773 rettv->vval.v_float = 0.0;
1774}
1775
1776/*
1777 * "cosh()" function
1778 */
1779 static void
1780f_cosh(typval_T *argvars, typval_T *rettv)
1781{
1782 float_T f = 0.0;
1783
1784 rettv->v_type = VAR_FLOAT;
1785 if (get_float_arg(argvars, &f) == OK)
1786 rettv->vval.v_float = cosh(f);
1787 else
1788 rettv->vval.v_float = 0.0;
1789}
1790#endif
1791
1792/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001793 * "cursor(lnum, col)" function, or
1794 * "cursor(list)"
1795 *
1796 * Moves the cursor to the specified line and column.
1797 * Returns 0 when the position could be set, -1 otherwise.
1798 */
1799 static void
1800f_cursor(typval_T *argvars, typval_T *rettv)
1801{
1802 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001803 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001804 int set_curswant = TRUE;
1805
1806 rettv->vval.v_number = -1;
1807 if (argvars[1].v_type == VAR_UNKNOWN)
1808 {
1809 pos_T pos;
1810 colnr_T curswant = -1;
1811
1812 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1813 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001814 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001815 return;
1816 }
1817 line = pos.lnum;
1818 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001819 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001820 if (curswant >= 0)
1821 {
1822 curwin->w_curswant = curswant - 1;
1823 set_curswant = FALSE;
1824 }
1825 }
1826 else
1827 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001828 line = tv_get_lnum(argvars);
1829 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001831 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001833 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001834 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835 if (line > 0)
1836 curwin->w_cursor.lnum = line;
1837 if (col > 0)
1838 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001841 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001842 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001843 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844 if (has_mbyte)
1845 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846
1847 curwin->w_set_curswant = set_curswant;
1848 rettv->vval.v_number = 0;
1849}
1850
Bram Moolenaar4f974752019-02-17 17:44:42 +01001851#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001852/*
1853 * "debugbreak()" function
1854 */
1855 static void
1856f_debugbreak(typval_T *argvars, typval_T *rettv)
1857{
1858 int pid;
1859
1860 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001861 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001862 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001863 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001864 else
1865 {
1866 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1867
1868 if (hProcess != NULL)
1869 {
1870 DebugBreakProcess(hProcess);
1871 CloseHandle(hProcess);
1872 rettv->vval.v_number = OK;
1873 }
1874 }
1875}
1876#endif
1877
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001878/*
1879 * "deepcopy()" function
1880 */
1881 static void
1882f_deepcopy(typval_T *argvars, typval_T *rettv)
1883{
1884 int noref = 0;
1885 int copyID;
1886
1887 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001888 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001890 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001891 else
1892 {
1893 copyID = get_copyID();
1894 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1895 }
1896}
1897
1898/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001899 * "did_filetype()" function
1900 */
1901 static void
1902f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1903{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001904 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001905}
1906
1907/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001908 * "echoraw({expr})" function
1909 */
1910 static void
1911f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1912{
1913 char_u *str = tv_get_string_chk(&argvars[0]);
1914
1915 if (str != NULL && *str != NUL)
1916 {
1917 out_str(str);
1918 out_flush();
1919 }
1920}
1921
1922/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923 * "empty({expr})" function
1924 */
1925 static void
1926f_empty(typval_T *argvars, typval_T *rettv)
1927{
1928 int n = FALSE;
1929
1930 switch (argvars[0].v_type)
1931 {
1932 case VAR_STRING:
1933 case VAR_FUNC:
1934 n = argvars[0].vval.v_string == NULL
1935 || *argvars[0].vval.v_string == NUL;
1936 break;
1937 case VAR_PARTIAL:
1938 n = FALSE;
1939 break;
1940 case VAR_NUMBER:
1941 n = argvars[0].vval.v_number == 0;
1942 break;
1943 case VAR_FLOAT:
1944#ifdef FEAT_FLOAT
1945 n = argvars[0].vval.v_float == 0.0;
1946 break;
1947#endif
1948 case VAR_LIST:
1949 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001950 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001951 break;
1952 case VAR_DICT:
1953 n = argvars[0].vval.v_dict == NULL
1954 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1955 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001956 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 case VAR_SPECIAL:
1958 n = argvars[0].vval.v_number != VVAL_TRUE;
1959 break;
1960
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001961 case VAR_BLOB:
1962 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001963 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1964 break;
1965
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001966 case VAR_JOB:
1967#ifdef FEAT_JOB_CHANNEL
1968 n = argvars[0].vval.v_job == NULL
1969 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1970 break;
1971#endif
1972 case VAR_CHANNEL:
1973#ifdef FEAT_JOB_CHANNEL
1974 n = argvars[0].vval.v_channel == NULL
1975 || !channel_is_open(argvars[0].vval.v_channel);
1976 break;
1977#endif
1978 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001979 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001980 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001981 n = TRUE;
1982 break;
1983 }
1984
1985 rettv->vval.v_number = n;
1986}
1987
1988/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001989 * "environ()" function
1990 */
1991 static void
1992f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1993{
1994#if !defined(AMIGA)
1995 int i = 0;
1996 char_u *entry, *value;
1997# ifdef MSWIN
1998 extern wchar_t **_wenviron;
1999# else
2000 extern char **environ;
2001# endif
2002
2003 if (rettv_dict_alloc(rettv) != OK)
2004 return;
2005
2006# ifdef MSWIN
2007 if (*_wenviron == NULL)
2008 return;
2009# else
2010 if (*environ == NULL)
2011 return;
2012# endif
2013
2014 for (i = 0; ; ++i)
2015 {
2016# ifdef MSWIN
2017 short_u *p;
2018
2019 if ((p = (short_u *)_wenviron[i]) == NULL)
2020 return;
2021 entry = utf16_to_enc(p, NULL);
2022# else
2023 if ((entry = (char_u *)environ[i]) == NULL)
2024 return;
2025 entry = vim_strsave(entry);
2026# endif
2027 if (entry == NULL) // out of memory
2028 return;
2029 if ((value = vim_strchr(entry, '=')) == NULL)
2030 {
2031 vim_free(entry);
2032 continue;
2033 }
2034 *value++ = NUL;
2035 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2036 vim_free(entry);
2037 }
2038#endif
2039}
2040
2041/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002042 * "escape({string}, {chars})" function
2043 */
2044 static void
2045f_escape(typval_T *argvars, typval_T *rettv)
2046{
2047 char_u buf[NUMBUFLEN];
2048
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002049 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2050 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002051 rettv->v_type = VAR_STRING;
2052}
2053
2054/*
2055 * "eval()" function
2056 */
2057 static void
2058f_eval(typval_T *argvars, typval_T *rettv)
2059{
2060 char_u *s, *p;
2061
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002062 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 if (s != NULL)
2064 s = skipwhite(s);
2065
2066 p = s;
2067 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2068 {
2069 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002070 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002071 need_clr_eos = FALSE;
2072 rettv->v_type = VAR_NUMBER;
2073 rettv->vval.v_number = 0;
2074 }
2075 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002076 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077}
2078
2079/*
2080 * "eventhandler()" function
2081 */
2082 static void
2083f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2084{
2085 rettv->vval.v_number = vgetc_busy;
2086}
2087
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088static garray_T redir_execute_ga;
2089
2090/*
2091 * Append "value[value_len]" to the execute() output.
2092 */
2093 void
2094execute_redir_str(char_u *value, int value_len)
2095{
2096 int len;
2097
2098 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002099 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002100 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002101 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002102 if (ga_grow(&redir_execute_ga, len) == OK)
2103 {
2104 mch_memmove((char *)redir_execute_ga.ga_data
2105 + redir_execute_ga.ga_len, value, len);
2106 redir_execute_ga.ga_len += len;
2107 }
2108}
2109
2110/*
2111 * Get next line from a list.
2112 * Called by do_cmdline() to get the next line.
2113 * Returns allocated string, or NULL for end of function.
2114 */
2115
2116 static char_u *
2117get_list_line(
2118 int c UNUSED,
2119 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002120 int indent UNUSED,
2121 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122{
2123 listitem_T **p = (listitem_T **)cookie;
2124 listitem_T *item = *p;
2125 char_u buf[NUMBUFLEN];
2126 char_u *s;
2127
2128 if (item == NULL)
2129 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002130 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002131 *p = item->li_next;
2132 return s == NULL ? NULL : vim_strsave(s);
2133}
2134
2135/*
2136 * "execute()" function
2137 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002138 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002139execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002140{
2141 char_u *cmd = NULL;
2142 list_T *list = NULL;
2143 int save_msg_silent = msg_silent;
2144 int save_emsg_silent = emsg_silent;
2145 int save_emsg_noredir = emsg_noredir;
2146 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002147 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002148 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002149 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002150 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002151
2152 rettv->vval.v_string = NULL;
2153 rettv->v_type = VAR_STRING;
2154
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002155 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002156 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002157 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002158 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002159 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002160 return;
2161 ++list->lv_refcount;
2162 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002163 else if (argvars[arg_off].v_type == VAR_JOB
2164 || argvars[arg_off].v_type == VAR_CHANNEL)
2165 {
2166 emsg(_(e_inval_string));
2167 return;
2168 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 else
2170 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002171 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172 if (cmd == NULL)
2173 return;
2174 }
2175
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002176 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 {
2178 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002179 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180
2181 if (s == NULL)
2182 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002183 if (*s == NUL)
2184 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002185 if (STRNCMP(s, "silent", 6) == 0)
2186 ++msg_silent;
2187 if (STRCMP(s, "silent!") == 0)
2188 {
2189 emsg_silent = TRUE;
2190 emsg_noredir = TRUE;
2191 }
2192 }
2193 else
2194 ++msg_silent;
2195
2196 if (redir_execute)
2197 save_ga = redir_execute_ga;
2198 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2199 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002200 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002201 if (!echo_output)
2202 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002203
2204 if (cmd != NULL)
2205 do_cmdline_cmd(cmd);
2206 else
2207 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002208 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002209
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002210 range_list_materialize(list);
2211 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212 do_cmdline(NULL, get_list_line, (void *)&item,
2213 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2214 --list->lv_refcount;
2215 }
2216
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002217 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002218 if (ga_grow(&redir_execute_ga, 1) == OK)
2219 {
2220 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2221 rettv->vval.v_string = redir_execute_ga.ga_data;
2222 }
2223 else
2224 {
2225 ga_clear(&redir_execute_ga);
2226 rettv->vval.v_string = NULL;
2227 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002228 msg_silent = save_msg_silent;
2229 emsg_silent = save_emsg_silent;
2230 emsg_noredir = save_emsg_noredir;
2231
2232 redir_execute = save_redir_execute;
2233 if (redir_execute)
2234 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002235 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002236
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002237 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002238 if (echo_output)
2239 // When not working silently: put it in column zero. A following
2240 // "echon" will overwrite the message, unavoidably.
2241 msg_col = 0;
2242 else
2243 // When working silently: Put it back where it was, since nothing
2244 // should have been written.
2245 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002246}
2247
2248/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002249 * "execute()" function
2250 */
2251 static void
2252f_execute(typval_T *argvars, typval_T *rettv)
2253{
2254 execute_common(argvars, rettv, 0);
2255}
2256
2257/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002258 * "exists()" function
2259 */
2260 static void
2261f_exists(typval_T *argvars, typval_T *rettv)
2262{
2263 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002264 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002265
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002266 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002267 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002269 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002270 if (mch_getenv(p + 1) != NULL)
2271 n = TRUE;
2272 else
2273 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002274 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275 p = expand_env_save(p);
2276 if (p != NULL && *p != '$')
2277 n = TRUE;
2278 vim_free(p);
2279 }
2280 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002281 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 {
2283 n = (get_option_tv(&p, NULL, TRUE) == OK);
2284 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002285 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002286 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002287 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002288 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002289 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290 }
2291 else if (*p == ':')
2292 {
2293 n = cmd_exists(p + 1);
2294 }
2295 else if (*p == '#')
2296 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 if (p[1] == '#')
2298 n = autocmd_supported(p + 2);
2299 else
2300 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002302 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002304 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002305 }
2306
2307 rettv->vval.v_number = n;
2308}
2309
2310#ifdef FEAT_FLOAT
2311/*
2312 * "exp()" function
2313 */
2314 static void
2315f_exp(typval_T *argvars, typval_T *rettv)
2316{
2317 float_T f = 0.0;
2318
2319 rettv->v_type = VAR_FLOAT;
2320 if (get_float_arg(argvars, &f) == OK)
2321 rettv->vval.v_float = exp(f);
2322 else
2323 rettv->vval.v_float = 0.0;
2324}
2325#endif
2326
2327/*
2328 * "expand()" function
2329 */
2330 static void
2331f_expand(typval_T *argvars, typval_T *rettv)
2332{
2333 char_u *s;
2334 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002335 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002336 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2337 expand_T xpc;
2338 int error = FALSE;
2339 char_u *result;
2340
2341 rettv->v_type = VAR_STRING;
2342 if (argvars[1].v_type != VAR_UNKNOWN
2343 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002344 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002346 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002348 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002349 if (*s == '%' || *s == '#' || *s == '<')
2350 {
2351 ++emsg_off;
2352 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2353 --emsg_off;
2354 if (rettv->v_type == VAR_LIST)
2355 {
2356 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2357 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002358 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 }
2360 else
2361 rettv->vval.v_string = result;
2362 }
2363 else
2364 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002365 // When the optional second argument is non-zero, don't remove matches
2366 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002368 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002369 options |= WILD_KEEP_ALL;
2370 if (!error)
2371 {
2372 ExpandInit(&xpc);
2373 xpc.xp_context = EXPAND_FILES;
2374 if (p_wic)
2375 options += WILD_ICASE;
2376 if (rettv->v_type == VAR_STRING)
2377 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2378 options, WILD_ALL);
2379 else if (rettv_list_alloc(rettv) != FAIL)
2380 {
2381 int i;
2382
2383 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2384 for (i = 0; i < xpc.xp_numfiles; i++)
2385 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2386 ExpandCleanup(&xpc);
2387 }
2388 }
2389 else
2390 rettv->vval.v_string = NULL;
2391 }
2392}
2393
2394/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002395 * "expandcmd()" function
2396 * Expand all the special characters in a command string.
2397 */
2398 static void
2399f_expandcmd(typval_T *argvars, typval_T *rettv)
2400{
2401 exarg_T eap;
2402 char_u *cmdstr;
2403 char *errormsg = NULL;
2404
2405 rettv->v_type = VAR_STRING;
2406 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2407
2408 memset(&eap, 0, sizeof(eap));
2409 eap.cmd = cmdstr;
2410 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002411 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002412 eap.usefilter = FALSE;
2413 eap.nextcmd = NULL;
2414 eap.cmdidx = CMD_USER;
2415
2416 expand_filename(&eap, &cmdstr, &errormsg);
2417 if (errormsg != NULL && *errormsg != NUL)
2418 emsg(errormsg);
2419
2420 rettv->vval.v_string = cmdstr;
2421}
2422
2423/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002424 * "feedkeys()" function
2425 */
2426 static void
2427f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2428{
2429 int remap = TRUE;
2430 int insert = FALSE;
2431 char_u *keys, *flags;
2432 char_u nbuf[NUMBUFLEN];
2433 int typed = FALSE;
2434 int execute = FALSE;
2435 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002436 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002437 char_u *keys_esc;
2438
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002439 // This is not allowed in the sandbox. If the commands would still be
2440 // executed in the sandbox it would be OK, but it probably happens later,
2441 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 if (check_secure())
2443 return;
2444
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002445 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446
2447 if (argvars[1].v_type != VAR_UNKNOWN)
2448 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002449 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 for ( ; *flags != NUL; ++flags)
2451 {
2452 switch (*flags)
2453 {
2454 case 'n': remap = FALSE; break;
2455 case 'm': remap = TRUE; break;
2456 case 't': typed = TRUE; break;
2457 case 'i': insert = TRUE; break;
2458 case 'x': execute = TRUE; break;
2459 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002460 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 }
2462 }
2463 }
2464
2465 if (*keys != NUL || execute)
2466 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002467 // Need to escape K_SPECIAL and CSI before putting the string in the
2468 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 keys_esc = vim_strsave_escape_csi(keys);
2470 if (keys_esc != NULL)
2471 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002472 if (lowlevel)
2473 {
2474#ifdef USE_INPUT_BUF
Bram Moolenaar0bdbc102020-03-15 16:51:40 +01002475 add_to_input_buf(keys, (int)STRLEN(keys));
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002476#else
2477 emsg(_("E980: lowlevel input not supported"));
2478#endif
2479 }
2480 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002481 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002482 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002483 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002484 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002485#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002486 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002487#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002488 )
2489 typebuf_was_filled = TRUE;
2490 }
2491 vim_free(keys_esc);
2492
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002493 if (execute)
2494 {
2495 int save_msg_scroll = msg_scroll;
2496
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002497 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002498 msg_scroll = FALSE;
2499
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002500 if (!dangerous)
2501 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002502 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002503 if (!dangerous)
2504 --ex_normal_busy;
2505
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002506 msg_scroll |= save_msg_scroll;
2507 }
2508 }
2509 }
2510}
2511
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512#ifdef FEAT_FLOAT
2513/*
2514 * "float2nr({float})" function
2515 */
2516 static void
2517f_float2nr(typval_T *argvars, typval_T *rettv)
2518{
2519 float_T f = 0.0;
2520
2521 if (get_float_arg(argvars, &f) == OK)
2522 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002523 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002524 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002525 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002526 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002527 else
2528 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002529 }
2530}
2531
2532/*
2533 * "floor({float})" function
2534 */
2535 static void
2536f_floor(typval_T *argvars, typval_T *rettv)
2537{
2538 float_T f = 0.0;
2539
2540 rettv->v_type = VAR_FLOAT;
2541 if (get_float_arg(argvars, &f) == OK)
2542 rettv->vval.v_float = floor(f);
2543 else
2544 rettv->vval.v_float = 0.0;
2545}
2546
2547/*
2548 * "fmod()" function
2549 */
2550 static void
2551f_fmod(typval_T *argvars, typval_T *rettv)
2552{
2553 float_T fx = 0.0, fy = 0.0;
2554
2555 rettv->v_type = VAR_FLOAT;
2556 if (get_float_arg(argvars, &fx) == OK
2557 && get_float_arg(&argvars[1], &fy) == OK)
2558 rettv->vval.v_float = fmod(fx, fy);
2559 else
2560 rettv->vval.v_float = 0.0;
2561}
2562#endif
2563
2564/*
2565 * "fnameescape({string})" function
2566 */
2567 static void
2568f_fnameescape(typval_T *argvars, typval_T *rettv)
2569{
2570 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002571 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002572 rettv->v_type = VAR_STRING;
2573}
2574
2575/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002576 * "foreground()" function
2577 */
2578 static void
2579f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2580{
2581#ifdef FEAT_GUI
2582 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002583 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002584 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002585 return;
2586 }
2587#endif
2588#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002589 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002590#endif
2591}
2592
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002594common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002595{
2596 char_u *s;
2597 char_u *name;
2598 int use_string = FALSE;
2599 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002600 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601
2602 if (argvars[0].v_type == VAR_FUNC)
2603 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002604 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002605 s = argvars[0].vval.v_string;
2606 }
2607 else if (argvars[0].v_type == VAR_PARTIAL
2608 && argvars[0].vval.v_partial != NULL)
2609 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002610 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002611 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002612 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002613 }
2614 else
2615 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002616 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002617 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618 use_string = TRUE;
2619 }
2620
Bram Moolenaar843b8842016-08-21 14:36:15 +02002621 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002622 {
2623 name = s;
2624 trans_name = trans_function_name(&name, FALSE,
2625 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2626 if (*name != NUL)
2627 s = NULL;
2628 }
2629
Bram Moolenaar843b8842016-08-21 14:36:15 +02002630 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2631 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002632 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002633 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002634 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002635 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002636 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002637 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002638 else
2639 {
2640 int dict_idx = 0;
2641 int arg_idx = 0;
2642 list_T *list = NULL;
2643
2644 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2645 {
2646 char sid_buf[25];
2647 int off = *s == 's' ? 2 : 5;
2648
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002649 // Expand s: and <SID> into <SNR>nr_, so that the function can
2650 // also be called from another script. Using trans_function_name()
2651 // would also work, but some plugins depend on the name being
2652 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002653 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002654 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655 if (name != NULL)
2656 {
2657 STRCPY(name, sid_buf);
2658 STRCAT(name, s + off);
2659 }
2660 }
2661 else
2662 name = vim_strsave(s);
2663
2664 if (argvars[1].v_type != VAR_UNKNOWN)
2665 {
2666 if (argvars[2].v_type != VAR_UNKNOWN)
2667 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002668 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002669 arg_idx = 1;
2670 dict_idx = 2;
2671 }
2672 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002673 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002674 dict_idx = 1;
2675 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002676 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 arg_idx = 1;
2678 if (dict_idx > 0)
2679 {
2680 if (argvars[dict_idx].v_type != VAR_DICT)
2681 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002682 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002683 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002684 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002685 }
2686 if (argvars[dict_idx].vval.v_dict == NULL)
2687 dict_idx = 0;
2688 }
2689 if (arg_idx > 0)
2690 {
2691 if (argvars[arg_idx].v_type != VAR_LIST)
2692 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002693 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002695 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002696 }
2697 list = argvars[arg_idx].vval.v_list;
2698 if (list == NULL || list->lv_len == 0)
2699 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002700 else if (list->lv_len > MAX_FUNC_ARGS)
2701 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002702 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002703 vim_free(name);
2704 goto theend;
2705 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706 }
2707 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002708 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002710 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002712 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 if (pt == NULL)
2714 vim_free(name);
2715 else
2716 {
2717 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2718 {
2719 listitem_T *li;
2720 int i = 0;
2721 int arg_len = 0;
2722 int lv_len = 0;
2723
2724 if (arg_pt != NULL)
2725 arg_len = arg_pt->pt_argc;
2726 if (list != NULL)
2727 lv_len = list->lv_len;
2728 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002729 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002730 if (pt->pt_argv == NULL)
2731 {
2732 vim_free(pt);
2733 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002734 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002735 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002736 for (i = 0; i < arg_len; i++)
2737 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2738 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002739 {
2740 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002741 for (li = list->lv_first; li != NULL;
2742 li = li->li_next)
2743 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002744 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002745 }
2746
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002747 // For "function(dict.func, [], dict)" and "func" is a partial
2748 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002749 if (dict_idx > 0)
2750 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002751 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002752 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2753 ++pt->pt_dict->dv_refcount;
2754 }
2755 else if (arg_pt != NULL)
2756 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002757 // If the dict was bound automatically the result is also
2758 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002759 pt->pt_dict = arg_pt->pt_dict;
2760 pt->pt_auto = arg_pt->pt_auto;
2761 if (pt->pt_dict != NULL)
2762 ++pt->pt_dict->dv_refcount;
2763 }
2764
2765 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002766 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2767 {
2768 pt->pt_func = arg_pt->pt_func;
2769 func_ptr_ref(pt->pt_func);
2770 vim_free(name);
2771 }
2772 else if (is_funcref)
2773 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002774 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002775 func_ptr_ref(pt->pt_func);
2776 vim_free(name);
2777 }
2778 else
2779 {
2780 pt->pt_name = name;
2781 func_ref(name);
2782 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783 }
2784 rettv->v_type = VAR_PARTIAL;
2785 rettv->vval.v_partial = pt;
2786 }
2787 else
2788 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002789 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002790 rettv->v_type = VAR_FUNC;
2791 rettv->vval.v_string = name;
2792 func_ref(name);
2793 }
2794 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002795theend:
2796 vim_free(trans_name);
2797}
2798
2799/*
2800 * "funcref()" function
2801 */
2802 static void
2803f_funcref(typval_T *argvars, typval_T *rettv)
2804{
2805 common_function(argvars, rettv, TRUE);
2806}
2807
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002808 static type_T *
2809ret_f_function(int argcount, type_T **argtypes UNUSED)
2810{
2811 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2812 return &t_func_any;
2813 return &t_partial_void;
2814}
2815
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002816/*
2817 * "function()" function
2818 */
2819 static void
2820f_function(typval_T *argvars, typval_T *rettv)
2821{
2822 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002823}
2824
2825/*
2826 * "garbagecollect()" function
2827 */
2828 static void
2829f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2830{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002831 // This is postponed until we are back at the toplevel, because we may be
2832 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002833 want_garbage_collect = TRUE;
2834
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002835 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002836 garbage_collect_at_exit = TRUE;
2837}
2838
2839/*
2840 * "get()" function
2841 */
2842 static void
2843f_get(typval_T *argvars, typval_T *rettv)
2844{
2845 listitem_T *li;
2846 list_T *l;
2847 dictitem_T *di;
2848 dict_T *d;
2849 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002850 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002852 if (argvars[0].v_type == VAR_BLOB)
2853 {
2854 int error = FALSE;
2855 int idx = tv_get_number_chk(&argvars[1], &error);
2856
2857 if (!error)
2858 {
2859 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002860 if (idx < 0)
2861 idx = blob_len(argvars[0].vval.v_blob) + idx;
2862 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2863 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002864 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002865 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002866 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002867 tv = rettv;
2868 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002869 }
2870 }
2871 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002872 {
2873 if ((l = argvars[0].vval.v_list) != NULL)
2874 {
2875 int error = FALSE;
2876
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002877 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878 if (!error && li != NULL)
2879 tv = &li->li_tv;
2880 }
2881 }
2882 else if (argvars[0].v_type == VAR_DICT)
2883 {
2884 if ((d = argvars[0].vval.v_dict) != NULL)
2885 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002886 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002887 if (di != NULL)
2888 tv = &di->di_tv;
2889 }
2890 }
2891 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2892 {
2893 partial_T *pt;
2894 partial_T fref_pt;
2895
2896 if (argvars[0].v_type == VAR_PARTIAL)
2897 pt = argvars[0].vval.v_partial;
2898 else
2899 {
2900 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2901 fref_pt.pt_name = argvars[0].vval.v_string;
2902 pt = &fref_pt;
2903 }
2904
2905 if (pt != NULL)
2906 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002907 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002908 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002909
2910 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2911 {
2912 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002913 n = partial_name(pt);
2914 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002915 rettv->vval.v_string = NULL;
2916 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002917 {
2918 rettv->vval.v_string = vim_strsave(n);
2919 if (rettv->v_type == VAR_FUNC)
2920 func_ref(rettv->vval.v_string);
2921 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922 }
2923 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002924 {
2925 what_is_dict = TRUE;
2926 if (pt->pt_dict != NULL)
2927 rettv_dict_set(rettv, pt->pt_dict);
2928 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002929 else if (STRCMP(what, "args") == 0)
2930 {
2931 rettv->v_type = VAR_LIST;
2932 if (rettv_list_alloc(rettv) == OK)
2933 {
2934 int i;
2935
2936 for (i = 0; i < pt->pt_argc; ++i)
2937 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2938 }
2939 }
2940 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002941 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002942
2943 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2944 // third argument
2945 if (!what_is_dict)
2946 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002947 }
2948 }
2949 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002950 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002951
2952 if (tv == NULL)
2953 {
2954 if (argvars[2].v_type != VAR_UNKNOWN)
2955 copy_tv(&argvars[2], rettv);
2956 }
2957 else
2958 copy_tv(tv, rettv);
2959}
2960
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002961/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002962 * "getchangelist()" function
2963 */
2964 static void
2965f_getchangelist(typval_T *argvars, typval_T *rettv)
2966{
2967#ifdef FEAT_JUMPLIST
2968 buf_T *buf;
2969 int i;
2970 list_T *l;
2971 dict_T *d;
2972#endif
2973
2974 if (rettv_list_alloc(rettv) != OK)
2975 return;
2976
2977#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002978 if (argvars[0].v_type == VAR_UNKNOWN)
2979 buf = curbuf;
2980 else
2981 {
2982 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2983 ++emsg_off;
2984 buf = tv_get_buf(&argvars[0], FALSE);
2985 --emsg_off;
2986 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002987 if (buf == NULL)
2988 return;
2989
2990 l = list_alloc();
2991 if (l == NULL)
2992 return;
2993
2994 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2995 return;
2996 /*
2997 * The current window change list index tracks only the position in the
2998 * current buffer change list. For other buffers, use the change list
2999 * length as the current index.
3000 */
3001 list_append_number(rettv->vval.v_list,
3002 (varnumber_T)((buf == curwin->w_buffer)
3003 ? curwin->w_changelistidx : buf->b_changelistlen));
3004
3005 for (i = 0; i < buf->b_changelistlen; ++i)
3006 {
3007 if (buf->b_changelist[i].lnum == 0)
3008 continue;
3009 if ((d = dict_alloc()) == NULL)
3010 return;
3011 if (list_append_dict(l, d) == FAIL)
3012 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003013 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3014 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003015 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003016 }
3017#endif
3018}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003019
3020/*
3021 * "getcharsearch()" function
3022 */
3023 static void
3024f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3025{
3026 if (rettv_dict_alloc(rettv) != FAIL)
3027 {
3028 dict_T *dict = rettv->vval.v_dict;
3029
Bram Moolenaare0be1672018-07-08 16:50:37 +02003030 dict_add_string(dict, "char", last_csearch());
3031 dict_add_number(dict, "forward", last_csearch_forward());
3032 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003033 }
3034}
3035
3036/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003037 * "getenv()" function
3038 */
3039 static void
3040f_getenv(typval_T *argvars, typval_T *rettv)
3041{
3042 int mustfree = FALSE;
3043 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3044
3045 if (p == NULL)
3046 {
3047 rettv->v_type = VAR_SPECIAL;
3048 rettv->vval.v_number = VVAL_NULL;
3049 return;
3050 }
3051 if (!mustfree)
3052 p = vim_strsave(p);
3053 rettv->vval.v_string = p;
3054 rettv->v_type = VAR_STRING;
3055}
3056
3057/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 * "getfontname()" function
3059 */
3060 static void
3061f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3062{
3063 rettv->v_type = VAR_STRING;
3064 rettv->vval.v_string = NULL;
3065#ifdef FEAT_GUI
3066 if (gui.in_use)
3067 {
3068 GuiFont font;
3069 char_u *name = NULL;
3070
3071 if (argvars[0].v_type == VAR_UNKNOWN)
3072 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003073 // Get the "Normal" font. Either the name saved by
3074 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 font = gui.norm_font;
3076 name = hl_get_font_name();
3077 }
3078 else
3079 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003080 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003081 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003082 return;
3083 font = gui_mch_get_font(name, FALSE);
3084 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003085 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003086 }
3087 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3088 if (argvars[0].v_type != VAR_UNKNOWN)
3089 gui_mch_free_font(font);
3090 }
3091#endif
3092}
3093
3094/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003095 * "getjumplist()" function
3096 */
3097 static void
3098f_getjumplist(typval_T *argvars, typval_T *rettv)
3099{
3100#ifdef FEAT_JUMPLIST
3101 win_T *wp;
3102 int i;
3103 list_T *l;
3104 dict_T *d;
3105#endif
3106
3107 if (rettv_list_alloc(rettv) != OK)
3108 return;
3109
3110#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003111 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003112 if (wp == NULL)
3113 return;
3114
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003115 cleanup_jumplist(wp, TRUE);
3116
Bram Moolenaar4f505882018-02-10 21:06:32 +01003117 l = list_alloc();
3118 if (l == NULL)
3119 return;
3120
3121 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3122 return;
3123 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3124
3125 for (i = 0; i < wp->w_jumplistlen; ++i)
3126 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003127 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3128 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003129 if ((d = dict_alloc()) == NULL)
3130 return;
3131 if (list_append_dict(l, d) == FAIL)
3132 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003133 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3134 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003135 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003136 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003137 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003138 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003139 }
3140#endif
3141}
3142
3143/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003144 * "getpid()" function
3145 */
3146 static void
3147f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3148{
3149 rettv->vval.v_number = mch_get_pid();
3150}
3151
3152 static void
3153getpos_both(
3154 typval_T *argvars,
3155 typval_T *rettv,
3156 int getcurpos)
3157{
3158 pos_T *fp;
3159 list_T *l;
3160 int fnum = -1;
3161
3162 if (rettv_list_alloc(rettv) == OK)
3163 {
3164 l = rettv->vval.v_list;
3165 if (getcurpos)
3166 fp = &curwin->w_cursor;
3167 else
3168 fp = var2fpos(&argvars[0], TRUE, &fnum);
3169 if (fnum != -1)
3170 list_append_number(l, (varnumber_T)fnum);
3171 else
3172 list_append_number(l, (varnumber_T)0);
3173 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3174 : (varnumber_T)0);
3175 list_append_number(l, (fp != NULL)
3176 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3177 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003178 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003179 (varnumber_T)0);
3180 if (getcurpos)
3181 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003182 int save_set_curswant = curwin->w_set_curswant;
3183 colnr_T save_curswant = curwin->w_curswant;
3184 colnr_T save_virtcol = curwin->w_virtcol;
3185
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003186 update_curswant();
3187 list_append_number(l, curwin->w_curswant == MAXCOL ?
3188 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003189
3190 // Do not change "curswant", as it is unexpected that a get
3191 // function has a side effect.
3192 if (save_set_curswant)
3193 {
3194 curwin->w_set_curswant = save_set_curswant;
3195 curwin->w_curswant = save_curswant;
3196 curwin->w_virtcol = save_virtcol;
3197 curwin->w_valid &= ~VALID_VIRTCOL;
3198 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003199 }
3200 }
3201 else
3202 rettv->vval.v_number = FALSE;
3203}
3204
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003205/*
3206 * "getcurpos()" function
3207 */
3208 static void
3209f_getcurpos(typval_T *argvars, typval_T *rettv)
3210{
3211 getpos_both(argvars, rettv, TRUE);
3212}
3213
3214/*
3215 * "getpos(string)" function
3216 */
3217 static void
3218f_getpos(typval_T *argvars, typval_T *rettv)
3219{
3220 getpos_both(argvars, rettv, FALSE);
3221}
3222
3223/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003224 * "getreg()" function
3225 */
3226 static void
3227f_getreg(typval_T *argvars, typval_T *rettv)
3228{
3229 char_u *strregname;
3230 int regname;
3231 int arg2 = FALSE;
3232 int return_list = FALSE;
3233 int error = FALSE;
3234
3235 if (argvars[0].v_type != VAR_UNKNOWN)
3236 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003237 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 error = strregname == NULL;
3239 if (argvars[1].v_type != VAR_UNKNOWN)
3240 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003241 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003242 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003243 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003244 }
3245 }
3246 else
3247 strregname = get_vim_var_str(VV_REG);
3248
3249 if (error)
3250 return;
3251
3252 regname = (strregname == NULL ? '"' : *strregname);
3253 if (regname == 0)
3254 regname = '"';
3255
3256 if (return_list)
3257 {
3258 rettv->v_type = VAR_LIST;
3259 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3260 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3261 if (rettv->vval.v_list == NULL)
3262 (void)rettv_list_alloc(rettv);
3263 else
3264 ++rettv->vval.v_list->lv_refcount;
3265 }
3266 else
3267 {
3268 rettv->v_type = VAR_STRING;
3269 rettv->vval.v_string = get_reg_contents(regname,
3270 arg2 ? GREG_EXPR_SRC : 0);
3271 }
3272}
3273
3274/*
3275 * "getregtype()" function
3276 */
3277 static void
3278f_getregtype(typval_T *argvars, typval_T *rettv)
3279{
3280 char_u *strregname;
3281 int regname;
3282 char_u buf[NUMBUFLEN + 2];
3283 long reglen = 0;
3284
3285 if (argvars[0].v_type != VAR_UNKNOWN)
3286 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003287 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003288 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003289 {
3290 rettv->v_type = VAR_STRING;
3291 rettv->vval.v_string = NULL;
3292 return;
3293 }
3294 }
3295 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003296 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 strregname = get_vim_var_str(VV_REG);
3298
3299 regname = (strregname == NULL ? '"' : *strregname);
3300 if (regname == 0)
3301 regname = '"';
3302
3303 buf[0] = NUL;
3304 buf[1] = NUL;
3305 switch (get_reg_type(regname, &reglen))
3306 {
3307 case MLINE: buf[0] = 'V'; break;
3308 case MCHAR: buf[0] = 'v'; break;
3309 case MBLOCK:
3310 buf[0] = Ctrl_V;
3311 sprintf((char *)buf + 1, "%ld", reglen + 1);
3312 break;
3313 }
3314 rettv->v_type = VAR_STRING;
3315 rettv->vval.v_string = vim_strsave(buf);
3316}
3317
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003318/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003319 * "gettagstack()" function
3320 */
3321 static void
3322f_gettagstack(typval_T *argvars, typval_T *rettv)
3323{
3324 win_T *wp = curwin; // default is current window
3325
3326 if (rettv_dict_alloc(rettv) != OK)
3327 return;
3328
3329 if (argvars[0].v_type != VAR_UNKNOWN)
3330 {
3331 wp = find_win_by_nr_or_id(&argvars[0]);
3332 if (wp == NULL)
3333 return;
3334 }
3335
3336 get_tagstack(wp, rettv->vval.v_dict);
3337}
3338
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003339// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003340#include "version.h"
3341
3342/*
3343 * "has()" function
3344 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003345 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003346f_has(typval_T *argvars, typval_T *rettv)
3347{
3348 int i;
3349 char_u *name;
3350 int n = FALSE;
3351 static char *(has_list[]) =
3352 {
3353#ifdef AMIGA
3354 "amiga",
3355# ifdef FEAT_ARP
3356 "arp",
3357# endif
3358#endif
3359#ifdef __BEOS__
3360 "beos",
3361#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003362#ifdef __HAIKU__
3363 "haiku",
3364#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003365#if defined(BSD) && !defined(MACOS_X)
3366 "bsd",
3367#endif
3368#ifdef hpux
3369 "hpux",
3370#endif
3371#ifdef __linux__
3372 "linux",
3373#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003374#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003375 "mac", // Mac OS X (and, once, Mac OS Classic)
3376 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003377# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003378 "macunix", // Mac OS X, with the darwin feature
3379 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003380# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003381#endif
3382#ifdef __QNX__
3383 "qnx",
3384#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003385#ifdef SUN_SYSTEM
3386 "sun",
3387#else
3388 "moon",
3389#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003390#ifdef UNIX
3391 "unix",
3392#endif
3393#ifdef VMS
3394 "vms",
3395#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003396#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003397 "win32",
3398#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003399#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400 "win32unix",
3401#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003402#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403 "win64",
3404#endif
3405#ifdef EBCDIC
3406 "ebcdic",
3407#endif
3408#ifndef CASE_INSENSITIVE_FILENAME
3409 "fname_case",
3410#endif
3411#ifdef HAVE_ACL
3412 "acl",
3413#endif
3414#ifdef FEAT_ARABIC
3415 "arabic",
3416#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003417 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003418#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003419 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003420#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003421#ifdef FEAT_AUTOSERVERNAME
3422 "autoservername",
3423#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003424#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003426# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 "balloon_multiline",
3428# endif
3429#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003430#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003431 "balloon_eval_term",
3432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003433#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3434 "builtin_terms",
3435# ifdef ALL_BUILTIN_TCAPS
3436 "all_builtin_terms",
3437# endif
3438#endif
3439#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003440 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003441 || defined(FEAT_GUI_MOTIF))
3442 "browsefilter",
3443#endif
3444#ifdef FEAT_BYTEOFF
3445 "byte_offset",
3446#endif
3447#ifdef FEAT_JOB_CHANNEL
3448 "channel",
3449#endif
3450#ifdef FEAT_CINDENT
3451 "cindent",
3452#endif
3453#ifdef FEAT_CLIENTSERVER
3454 "clientserver",
3455#endif
3456#ifdef FEAT_CLIPBOARD
3457 "clipboard",
3458#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003459 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003460 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003461 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003462#ifdef FEAT_CONCEAL
3463 "conceal",
3464#endif
3465#ifdef FEAT_CRYPT
3466 "cryptv",
3467 "crypt-blowfish",
3468 "crypt-blowfish2",
3469#endif
3470#ifdef FEAT_CSCOPE
3471 "cscope",
3472#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003473 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474#ifdef CURSOR_SHAPE
3475 "cursorshape",
3476#endif
3477#ifdef DEBUG
3478 "debug",
3479#endif
3480#ifdef FEAT_CON_DIALOG
3481 "dialog_con",
3482#endif
3483#ifdef FEAT_GUI_DIALOG
3484 "dialog_gui",
3485#endif
3486#ifdef FEAT_DIFF
3487 "diff",
3488#endif
3489#ifdef FEAT_DIGRAPHS
3490 "digraphs",
3491#endif
3492#ifdef FEAT_DIRECTX
3493 "directx",
3494#endif
3495#ifdef FEAT_DND
3496 "dnd",
3497#endif
3498#ifdef FEAT_EMACS_TAGS
3499 "emacs_tags",
3500#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003501 "eval", // always present, of course!
3502 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503#ifdef FEAT_SEARCH_EXTRA
3504 "extra_search",
3505#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506#ifdef FEAT_SEARCHPATH
3507 "file_in_path",
3508#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003509#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003510 "filterpipe",
3511#endif
3512#ifdef FEAT_FIND_ID
3513 "find_in_path",
3514#endif
3515#ifdef FEAT_FLOAT
3516 "float",
3517#endif
3518#ifdef FEAT_FOLDING
3519 "folding",
3520#endif
3521#ifdef FEAT_FOOTER
3522 "footer",
3523#endif
3524#if !defined(USE_SYSTEM) && defined(UNIX)
3525 "fork",
3526#endif
3527#ifdef FEAT_GETTEXT
3528 "gettext",
3529#endif
3530#ifdef FEAT_GUI
3531 "gui",
3532#endif
3533#ifdef FEAT_GUI_ATHENA
3534# ifdef FEAT_GUI_NEXTAW
3535 "gui_neXtaw",
3536# else
3537 "gui_athena",
3538# endif
3539#endif
3540#ifdef FEAT_GUI_GTK
3541 "gui_gtk",
3542# ifdef USE_GTK3
3543 "gui_gtk3",
3544# else
3545 "gui_gtk2",
3546# endif
3547#endif
3548#ifdef FEAT_GUI_GNOME
3549 "gui_gnome",
3550#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003551#ifdef FEAT_GUI_HAIKU
3552 "gui_haiku",
3553#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003554#ifdef FEAT_GUI_MAC
3555 "gui_mac",
3556#endif
3557#ifdef FEAT_GUI_MOTIF
3558 "gui_motif",
3559#endif
3560#ifdef FEAT_GUI_PHOTON
3561 "gui_photon",
3562#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003563#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003564 "gui_win32",
3565#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003566#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3567 "iconv",
3568#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570#ifdef FEAT_JOB_CHANNEL
3571 "job",
3572#endif
3573#ifdef FEAT_JUMPLIST
3574 "jumplist",
3575#endif
3576#ifdef FEAT_KEYMAP
3577 "keymap",
3578#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003579 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003580#ifdef FEAT_LANGMAP
3581 "langmap",
3582#endif
3583#ifdef FEAT_LIBCALL
3584 "libcall",
3585#endif
3586#ifdef FEAT_LINEBREAK
3587 "linebreak",
3588#endif
3589#ifdef FEAT_LISP
3590 "lispindent",
3591#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003592 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003593 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003594#ifdef FEAT_LUA
3595# ifndef DYNAMIC_LUA
3596 "lua",
3597# endif
3598#endif
3599#ifdef FEAT_MENU
3600 "menu",
3601#endif
3602#ifdef FEAT_SESSION
3603 "mksession",
3604#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003606 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607#ifdef FEAT_MOUSESHAPE
3608 "mouseshape",
3609#endif
3610#if defined(UNIX) || defined(VMS)
3611# ifdef FEAT_MOUSE_DEC
3612 "mouse_dec",
3613# endif
3614# ifdef FEAT_MOUSE_GPM
3615 "mouse_gpm",
3616# endif
3617# ifdef FEAT_MOUSE_JSB
3618 "mouse_jsbterm",
3619# endif
3620# ifdef FEAT_MOUSE_NET
3621 "mouse_netterm",
3622# endif
3623# ifdef FEAT_MOUSE_PTERM
3624 "mouse_pterm",
3625# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003626# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003627 "mouse_sgr",
3628# endif
3629# ifdef FEAT_SYSMOUSE
3630 "mouse_sysmouse",
3631# endif
3632# ifdef FEAT_MOUSE_URXVT
3633 "mouse_urxvt",
3634# endif
3635# ifdef FEAT_MOUSE_XTERM
3636 "mouse_xterm",
3637# endif
3638#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003639 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003640#ifdef FEAT_MBYTE_IME
3641 "multi_byte_ime",
3642#endif
3643#ifdef FEAT_MULTI_LANG
3644 "multi_lang",
3645#endif
3646#ifdef FEAT_MZSCHEME
3647#ifndef DYNAMIC_MZSCHEME
3648 "mzscheme",
3649#endif
3650#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651 "num64",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003652#ifdef FEAT_OLE
3653 "ole",
3654#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003655#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003657#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003658#ifdef FEAT_PATH_EXTRA
3659 "path_extra",
3660#endif
3661#ifdef FEAT_PERL
3662#ifndef DYNAMIC_PERL
3663 "perl",
3664#endif
3665#endif
3666#ifdef FEAT_PERSISTENT_UNDO
3667 "persistent_undo",
3668#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003669#if defined(FEAT_PYTHON)
3670 "python_compiled",
3671# if defined(DYNAMIC_PYTHON)
3672 "python_dynamic",
3673# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003674 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003675 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003676# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003678#if defined(FEAT_PYTHON3)
3679 "python3_compiled",
3680# if defined(DYNAMIC_PYTHON3)
3681 "python3_dynamic",
3682# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003683 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003684 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003685# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003686#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003687#ifdef FEAT_PROP_POPUP
3688 "popupwin",
3689#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003690#ifdef FEAT_POSTSCRIPT
3691 "postscript",
3692#endif
3693#ifdef FEAT_PRINTER
3694 "printer",
3695#endif
3696#ifdef FEAT_PROFILE
3697 "profile",
3698#endif
3699#ifdef FEAT_RELTIME
3700 "reltime",
3701#endif
3702#ifdef FEAT_QUICKFIX
3703 "quickfix",
3704#endif
3705#ifdef FEAT_RIGHTLEFT
3706 "rightleft",
3707#endif
3708#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3709 "ruby",
3710#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003711 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003712#ifdef FEAT_CMDL_INFO
3713 "showcmd",
3714 "cmdline_info",
3715#endif
3716#ifdef FEAT_SIGNS
3717 "signs",
3718#endif
3719#ifdef FEAT_SMARTINDENT
3720 "smartindent",
3721#endif
3722#ifdef STARTUPTIME
3723 "startuptime",
3724#endif
3725#ifdef FEAT_STL_OPT
3726 "statusline",
3727#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003728#ifdef FEAT_NETBEANS_INTG
3729 "netbeans_intg",
3730#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003731#ifdef FEAT_SOUND
3732 "sound",
3733#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003734#ifdef FEAT_SPELL
3735 "spell",
3736#endif
3737#ifdef FEAT_SYN_HL
3738 "syntax",
3739#endif
3740#if defined(USE_SYSTEM) || !defined(UNIX)
3741 "system",
3742#endif
3743#ifdef FEAT_TAG_BINS
3744 "tag_binary",
3745#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003746#ifdef FEAT_TCL
3747# ifndef DYNAMIC_TCL
3748 "tcl",
3749# endif
3750#endif
3751#ifdef FEAT_TERMGUICOLORS
3752 "termguicolors",
3753#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003754#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003755 "terminal",
3756#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003757#ifdef TERMINFO
3758 "terminfo",
3759#endif
3760#ifdef FEAT_TERMRESPONSE
3761 "termresponse",
3762#endif
3763#ifdef FEAT_TEXTOBJ
3764 "textobjects",
3765#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003766#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003767 "textprop",
3768#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003769#ifdef HAVE_TGETENT
3770 "tgetent",
3771#endif
3772#ifdef FEAT_TIMERS
3773 "timers",
3774#endif
3775#ifdef FEAT_TITLE
3776 "title",
3777#endif
3778#ifdef FEAT_TOOLBAR
3779 "toolbar",
3780#endif
3781#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3782 "unnamedplus",
3783#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003784 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003785 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003786#ifdef FEAT_VARTABS
3787 "vartabs",
3788#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003789 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003790#ifdef FEAT_VIMINFO
3791 "viminfo",
3792#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003793 "vimscript-1",
3794 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003795 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003796 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003797 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003798 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003799 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003800 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003801#ifdef FEAT_VTP
3802 "vtp",
3803#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003804#ifdef FEAT_WILDIGN
3805 "wildignore",
3806#endif
3807#ifdef FEAT_WILDMENU
3808 "wildmenu",
3809#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003810 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003811#ifdef FEAT_WAK
3812 "winaltkeys",
3813#endif
3814#ifdef FEAT_WRITEBACKUP
3815 "writebackup",
3816#endif
3817#ifdef FEAT_XIM
3818 "xim",
3819#endif
3820#ifdef FEAT_XFONTSET
3821 "xfontset",
3822#endif
3823#ifdef FEAT_XPM_W32
3824 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003825 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826#else
3827# if defined(HAVE_XPM)
3828 "xpm",
3829# endif
3830#endif
3831#ifdef USE_XSMP
3832 "xsmp",
3833#endif
3834#ifdef USE_XSMP_INTERACT
3835 "xsmp_interact",
3836#endif
3837#ifdef FEAT_XCLIPBOARD
3838 "xterm_clipboard",
3839#endif
3840#ifdef FEAT_XTERM_SAVE
3841 "xterm_save",
3842#endif
3843#if defined(UNIX) && defined(FEAT_X11)
3844 "X11",
3845#endif
3846 NULL
3847 };
3848
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003849 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003850 for (i = 0; has_list[i] != NULL; ++i)
3851 if (STRICMP(name, has_list[i]) == 0)
3852 {
3853 n = TRUE;
3854 break;
3855 }
3856
3857 if (n == FALSE)
3858 {
3859 if (STRNICMP(name, "patch", 5) == 0)
3860 {
3861 if (name[5] == '-'
3862 && STRLEN(name) >= 11
3863 && vim_isdigit(name[6])
3864 && vim_isdigit(name[8])
3865 && vim_isdigit(name[10]))
3866 {
3867 int major = atoi((char *)name + 6);
3868 int minor = atoi((char *)name + 8);
3869
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003870 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871 n = (major < VIM_VERSION_MAJOR
3872 || (major == VIM_VERSION_MAJOR
3873 && (minor < VIM_VERSION_MINOR
3874 || (minor == VIM_VERSION_MINOR
3875 && has_patch(atoi((char *)name + 10))))));
3876 }
3877 else
3878 n = has_patch(atoi((char *)name + 5));
3879 }
3880 else if (STRICMP(name, "vim_starting") == 0)
3881 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003882 else if (STRICMP(name, "ttyin") == 0)
3883 n = mch_input_isatty();
3884 else if (STRICMP(name, "ttyout") == 0)
3885 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003886 else if (STRICMP(name, "multi_byte_encoding") == 0)
3887 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003888#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003889 else if (STRICMP(name, "balloon_multiline") == 0)
3890 n = multiline_balloon_available();
3891#endif
3892#ifdef DYNAMIC_TCL
3893 else if (STRICMP(name, "tcl") == 0)
3894 n = tcl_enabled(FALSE);
3895#endif
3896#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3897 else if (STRICMP(name, "iconv") == 0)
3898 n = iconv_enabled(FALSE);
3899#endif
3900#ifdef DYNAMIC_LUA
3901 else if (STRICMP(name, "lua") == 0)
3902 n = lua_enabled(FALSE);
3903#endif
3904#ifdef DYNAMIC_MZSCHEME
3905 else if (STRICMP(name, "mzscheme") == 0)
3906 n = mzscheme_enabled(FALSE);
3907#endif
3908#ifdef DYNAMIC_RUBY
3909 else if (STRICMP(name, "ruby") == 0)
3910 n = ruby_enabled(FALSE);
3911#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003912#ifdef DYNAMIC_PYTHON
3913 else if (STRICMP(name, "python") == 0)
3914 n = python_enabled(FALSE);
3915#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003916#ifdef DYNAMIC_PYTHON3
3917 else if (STRICMP(name, "python3") == 0)
3918 n = python3_enabled(FALSE);
3919#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003920#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3921 else if (STRICMP(name, "pythonx") == 0)
3922 {
3923# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3924 if (p_pyx == 0)
3925 n = python3_enabled(FALSE) || python_enabled(FALSE);
3926 else if (p_pyx == 3)
3927 n = python3_enabled(FALSE);
3928 else if (p_pyx == 2)
3929 n = python_enabled(FALSE);
3930# elif defined(DYNAMIC_PYTHON)
3931 n = python_enabled(FALSE);
3932# elif defined(DYNAMIC_PYTHON3)
3933 n = python3_enabled(FALSE);
3934# endif
3935 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003936#endif
3937#ifdef DYNAMIC_PERL
3938 else if (STRICMP(name, "perl") == 0)
3939 n = perl_enabled(FALSE);
3940#endif
3941#ifdef FEAT_GUI
3942 else if (STRICMP(name, "gui_running") == 0)
3943 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944# ifdef FEAT_BROWSE
3945 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003946 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003947# endif
3948#endif
3949#ifdef FEAT_SYN_HL
3950 else if (STRICMP(name, "syntax_items") == 0)
3951 n = syntax_present(curwin);
3952#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003953#ifdef FEAT_VTP
3954 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003955 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956#endif
3957#ifdef FEAT_NETBEANS_INTG
3958 else if (STRICMP(name, "netbeans_enabled") == 0)
3959 n = netbeans_active();
3960#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003961#ifdef FEAT_MOUSE_GPM
3962 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3963 n = gpm_enabled();
3964#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003965#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003966 else if (STRICMP(name, "terminal") == 0)
3967 n = terminal_enabled();
3968#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003969#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003970 else if (STRICMP(name, "conpty") == 0)
3971 n = use_conpty();
3972#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003973#ifdef FEAT_CLIPBOARD
3974 else if (STRICMP(name, "clipboard_working") == 0)
3975 n = clip_star.available;
3976#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003977#ifdef VIMDLL
3978 else if (STRICMP(name, "filterpipe") == 0)
3979 n = gui.in_use || gui.starting;
3980#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003981 }
3982
3983 rettv->vval.v_number = n;
3984}
3985
3986/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987 * "haslocaldir()" function
3988 */
3989 static void
3990f_haslocaldir(typval_T *argvars, typval_T *rettv)
3991{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003992 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003993 win_T *wp = NULL;
3994
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003995 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3996
3997 // Check for window-local and tab-local directories
3998 if (wp != NULL && wp->w_localdir != NULL)
3999 rettv->vval.v_number = 1;
4000 else if (tp != NULL && tp->tp_localdir != NULL)
4001 rettv->vval.v_number = 2;
4002 else
4003 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004004}
4005
4006/*
4007 * "hasmapto()" function
4008 */
4009 static void
4010f_hasmapto(typval_T *argvars, typval_T *rettv)
4011{
4012 char_u *name;
4013 char_u *mode;
4014 char_u buf[NUMBUFLEN];
4015 int abbr = FALSE;
4016
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004017 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004018 if (argvars[1].v_type == VAR_UNKNOWN)
4019 mode = (char_u *)"nvo";
4020 else
4021 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004022 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004024 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004025 }
4026
4027 if (map_to_exists(name, mode, abbr))
4028 rettv->vval.v_number = TRUE;
4029 else
4030 rettv->vval.v_number = FALSE;
4031}
4032
4033/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034 * "highlightID(name)" function
4035 */
4036 static void
4037f_hlID(typval_T *argvars, typval_T *rettv)
4038{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004039 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004040}
4041
4042/*
4043 * "highlight_exists()" function
4044 */
4045 static void
4046f_hlexists(typval_T *argvars, typval_T *rettv)
4047{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004048 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004049}
4050
4051/*
4052 * "hostname()" function
4053 */
4054 static void
4055f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4056{
4057 char_u hostname[256];
4058
4059 mch_get_host_name(hostname, 256);
4060 rettv->v_type = VAR_STRING;
4061 rettv->vval.v_string = vim_strsave(hostname);
4062}
4063
4064/*
4065 * iconv() function
4066 */
4067 static void
4068f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4069{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 char_u buf1[NUMBUFLEN];
4071 char_u buf2[NUMBUFLEN];
4072 char_u *from, *to, *str;
4073 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004074
4075 rettv->v_type = VAR_STRING;
4076 rettv->vval.v_string = NULL;
4077
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004078 str = tv_get_string(&argvars[0]);
4079 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4080 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004081 vimconv.vc_type = CONV_NONE;
4082 convert_setup(&vimconv, from, to);
4083
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004084 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004085 if (vimconv.vc_type == CONV_NONE)
4086 rettv->vval.v_string = vim_strsave(str);
4087 else
4088 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4089
4090 convert_setup(&vimconv, NULL, NULL);
4091 vim_free(from);
4092 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004093}
4094
4095/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004096 * "index()" function
4097 */
4098 static void
4099f_index(typval_T *argvars, typval_T *rettv)
4100{
4101 list_T *l;
4102 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004103 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004104 long idx = 0;
4105 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004106 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107
4108 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004109 if (argvars[0].v_type == VAR_BLOB)
4110 {
4111 typval_T tv;
4112 int start = 0;
4113
4114 if (argvars[2].v_type != VAR_UNKNOWN)
4115 {
4116 start = tv_get_number_chk(&argvars[2], &error);
4117 if (error)
4118 return;
4119 }
4120 b = argvars[0].vval.v_blob;
4121 if (b == NULL)
4122 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004123 if (start < 0)
4124 {
4125 start = blob_len(b) + start;
4126 if (start < 0)
4127 start = 0;
4128 }
4129
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004130 for (idx = start; idx < blob_len(b); ++idx)
4131 {
4132 tv.v_type = VAR_NUMBER;
4133 tv.vval.v_number = blob_get(b, idx);
4134 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4135 {
4136 rettv->vval.v_number = idx;
4137 return;
4138 }
4139 }
4140 return;
4141 }
4142 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004143 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004144 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004145 return;
4146 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004147
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 l = argvars[0].vval.v_list;
4149 if (l != NULL)
4150 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004151 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004152 item = l->lv_first;
4153 if (argvars[2].v_type != VAR_UNKNOWN)
4154 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004155 // Start at specified item. Use the cached index that list_find()
4156 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004157 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004158 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004159 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004160 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004161 if (error)
4162 item = NULL;
4163 }
4164
4165 for ( ; item != NULL; item = item->li_next, ++idx)
4166 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4167 {
4168 rettv->vval.v_number = idx;
4169 break;
4170 }
4171 }
4172}
4173
4174static int inputsecret_flag = 0;
4175
4176/*
4177 * "input()" function
4178 * Also handles inputsecret() when inputsecret is set.
4179 */
4180 static void
4181f_input(typval_T *argvars, typval_T *rettv)
4182{
4183 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4184}
4185
4186/*
4187 * "inputdialog()" function
4188 */
4189 static void
4190f_inputdialog(typval_T *argvars, typval_T *rettv)
4191{
4192#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004193 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004194 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4195 {
4196 char_u *message;
4197 char_u buf[NUMBUFLEN];
4198 char_u *defstr = (char_u *)"";
4199
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004200 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004201 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004202 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4204 else
4205 IObuff[0] = NUL;
4206 if (message != NULL && defstr != NULL
4207 && do_dialog(VIM_QUESTION, NULL, message,
4208 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4209 rettv->vval.v_string = vim_strsave(IObuff);
4210 else
4211 {
4212 if (message != NULL && defstr != NULL
4213 && argvars[1].v_type != VAR_UNKNOWN
4214 && argvars[2].v_type != VAR_UNKNOWN)
4215 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004216 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004217 else
4218 rettv->vval.v_string = NULL;
4219 }
4220 rettv->v_type = VAR_STRING;
4221 }
4222 else
4223#endif
4224 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4225}
4226
4227/*
4228 * "inputlist()" function
4229 */
4230 static void
4231f_inputlist(typval_T *argvars, typval_T *rettv)
4232{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004233 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004234 listitem_T *li;
4235 int selected;
4236 int mouse_used;
4237
4238#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004239 // While starting up, there is no place to enter text. When running tests
4240 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004241 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004242 return;
4243#endif
4244 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4245 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004246 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247 return;
4248 }
4249
4250 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004251 msg_row = Rows - 1; // for when 'cmdheight' > 1
4252 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004253 msg_scroll = TRUE;
4254 msg_clr_eos();
4255
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004256 l = argvars[0].vval.v_list;
4257 range_list_materialize(l);
4258 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004259 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004260 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004261 msg_putchar('\n');
4262 }
4263
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004264 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004265 selected = prompt_for_number(&mouse_used);
4266 if (mouse_used)
4267 selected -= lines_left;
4268
4269 rettv->vval.v_number = selected;
4270}
4271
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004272static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4273
4274/*
4275 * "inputrestore()" function
4276 */
4277 static void
4278f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4279{
4280 if (ga_userinput.ga_len > 0)
4281 {
4282 --ga_userinput.ga_len;
4283 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4284 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004285 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 }
4287 else if (p_verbose > 1)
4288 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004289 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004290 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004291 }
4292}
4293
4294/*
4295 * "inputsave()" function
4296 */
4297 static void
4298f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4299{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004300 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004301 if (ga_grow(&ga_userinput, 1) == OK)
4302 {
4303 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4304 + ga_userinput.ga_len);
4305 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004306 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307 }
4308 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004309 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004310}
4311
4312/*
4313 * "inputsecret()" function
4314 */
4315 static void
4316f_inputsecret(typval_T *argvars, typval_T *rettv)
4317{
4318 ++cmdline_star;
4319 ++inputsecret_flag;
4320 f_input(argvars, rettv);
4321 --cmdline_star;
4322 --inputsecret_flag;
4323}
4324
4325/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004326 * "interrupt()" function
4327 */
4328 static void
4329f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4330{
4331 got_int = TRUE;
4332}
4333
4334/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004335 * "invert(expr)" function
4336 */
4337 static void
4338f_invert(typval_T *argvars, typval_T *rettv)
4339{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004340 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004341}
4342
4343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004344 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4345 * or it refers to a List or Dictionary that is locked.
4346 */
4347 static int
4348tv_islocked(typval_T *tv)
4349{
4350 return (tv->v_lock & VAR_LOCKED)
4351 || (tv->v_type == VAR_LIST
4352 && tv->vval.v_list != NULL
4353 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4354 || (tv->v_type == VAR_DICT
4355 && tv->vval.v_dict != NULL
4356 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4357}
4358
4359/*
4360 * "islocked()" function
4361 */
4362 static void
4363f_islocked(typval_T *argvars, typval_T *rettv)
4364{
4365 lval_T lv;
4366 char_u *end;
4367 dictitem_T *di;
4368
4369 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004370 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004371 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004372 if (end != NULL && lv.ll_name != NULL)
4373 {
4374 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004375 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004376 else
4377 {
4378 if (lv.ll_tv == NULL)
4379 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004380 di = find_var(lv.ll_name, NULL, TRUE);
4381 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004382 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004383 // Consider a variable locked when:
4384 // 1. the variable itself is locked
4385 // 2. the value of the variable is locked.
4386 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004387 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4388 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004389 }
4390 }
4391 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004392 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004393 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004394 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004395 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004396 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4398 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004399 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004400 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4401 }
4402 }
4403
4404 clear_lval(&lv);
4405}
4406
4407#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4408/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004409 * "isinf()" function
4410 */
4411 static void
4412f_isinf(typval_T *argvars, typval_T *rettv)
4413{
4414 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4415 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4416}
4417
4418/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004419 * "isnan()" function
4420 */
4421 static void
4422f_isnan(typval_T *argvars, typval_T *rettv)
4423{
4424 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4425 && isnan(argvars[0].vval.v_float);
4426}
4427#endif
4428
4429/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004430 * "last_buffer_nr()" function.
4431 */
4432 static void
4433f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4434{
4435 int n = 0;
4436 buf_T *buf;
4437
Bram Moolenaar29323592016-07-24 22:04:11 +02004438 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004439 if (n < buf->b_fnum)
4440 n = buf->b_fnum;
4441
4442 rettv->vval.v_number = n;
4443}
4444
4445/*
4446 * "len()" function
4447 */
4448 static void
4449f_len(typval_T *argvars, typval_T *rettv)
4450{
4451 switch (argvars[0].v_type)
4452 {
4453 case VAR_STRING:
4454 case VAR_NUMBER:
4455 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004456 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004458 case VAR_BLOB:
4459 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4460 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004461 case VAR_LIST:
4462 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4463 break;
4464 case VAR_DICT:
4465 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4466 break;
4467 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004468 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004469 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004470 case VAR_SPECIAL:
4471 case VAR_FLOAT:
4472 case VAR_FUNC:
4473 case VAR_PARTIAL:
4474 case VAR_JOB:
4475 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004476 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004477 break;
4478 }
4479}
4480
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004481 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004482libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004483{
4484#ifdef FEAT_LIBCALL
4485 char_u *string_in;
4486 char_u **string_result;
4487 int nr_result;
4488#endif
4489
4490 rettv->v_type = type;
4491 if (type != VAR_NUMBER)
4492 rettv->vval.v_string = NULL;
4493
4494 if (check_restricted() || check_secure())
4495 return;
4496
4497#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004498 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004499 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4500 {
4501 string_in = NULL;
4502 if (argvars[2].v_type == VAR_STRING)
4503 string_in = argvars[2].vval.v_string;
4504 if (type == VAR_NUMBER)
4505 string_result = NULL;
4506 else
4507 string_result = &rettv->vval.v_string;
4508 if (mch_libcall(argvars[0].vval.v_string,
4509 argvars[1].vval.v_string,
4510 string_in,
4511 argvars[2].vval.v_number,
4512 string_result,
4513 &nr_result) == OK
4514 && type == VAR_NUMBER)
4515 rettv->vval.v_number = nr_result;
4516 }
4517#endif
4518}
4519
4520/*
4521 * "libcall()" function
4522 */
4523 static void
4524f_libcall(typval_T *argvars, typval_T *rettv)
4525{
4526 libcall_common(argvars, rettv, VAR_STRING);
4527}
4528
4529/*
4530 * "libcallnr()" function
4531 */
4532 static void
4533f_libcallnr(typval_T *argvars, typval_T *rettv)
4534{
4535 libcall_common(argvars, rettv, VAR_NUMBER);
4536}
4537
4538/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004539 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004540 */
4541 static void
4542f_line(typval_T *argvars, typval_T *rettv)
4543{
4544 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004545 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004546 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004547 int id;
4548 tabpage_T *tp;
4549 win_T *wp;
4550 win_T *save_curwin;
4551 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004552
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004553 if (argvars[1].v_type != VAR_UNKNOWN)
4554 {
4555 // use window specified in the second argument
4556 id = (int)tv_get_number(&argvars[1]);
4557 wp = win_id2wp_tp(id, &tp);
4558 if (wp != NULL && tp != NULL)
4559 {
4560 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4561 == OK)
4562 {
4563 check_cursor();
4564 fp = var2fpos(&argvars[0], TRUE, &fnum);
4565 }
4566 restore_win_noblock(save_curwin, save_curtab, TRUE);
4567 }
4568 }
4569 else
4570 // use current window
4571 fp = var2fpos(&argvars[0], TRUE, &fnum);
4572
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004573 if (fp != NULL)
4574 lnum = fp->lnum;
4575 rettv->vval.v_number = lnum;
4576}
4577
4578/*
4579 * "line2byte(lnum)" function
4580 */
4581 static void
4582f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4583{
4584#ifndef FEAT_BYTEOFF
4585 rettv->vval.v_number = -1;
4586#else
4587 linenr_T lnum;
4588
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004589 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004590 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4591 rettv->vval.v_number = -1;
4592 else
4593 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4594 if (rettv->vval.v_number >= 0)
4595 ++rettv->vval.v_number;
4596#endif
4597}
4598
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004599#ifdef FEAT_FLOAT
4600/*
4601 * "log()" function
4602 */
4603 static void
4604f_log(typval_T *argvars, typval_T *rettv)
4605{
4606 float_T f = 0.0;
4607
4608 rettv->v_type = VAR_FLOAT;
4609 if (get_float_arg(argvars, &f) == OK)
4610 rettv->vval.v_float = log(f);
4611 else
4612 rettv->vval.v_float = 0.0;
4613}
4614
4615/*
4616 * "log10()" function
4617 */
4618 static void
4619f_log10(typval_T *argvars, typval_T *rettv)
4620{
4621 float_T f = 0.0;
4622
4623 rettv->v_type = VAR_FLOAT;
4624 if (get_float_arg(argvars, &f) == OK)
4625 rettv->vval.v_float = log10(f);
4626 else
4627 rettv->vval.v_float = 0.0;
4628}
4629#endif
4630
4631#ifdef FEAT_LUA
4632/*
4633 * "luaeval()" function
4634 */
4635 static void
4636f_luaeval(typval_T *argvars, typval_T *rettv)
4637{
4638 char_u *str;
4639 char_u buf[NUMBUFLEN];
4640
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004641 if (check_restricted() || check_secure())
4642 return;
4643
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004644 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004645 do_luaeval(str, argvars + 1, rettv);
4646}
4647#endif
4648
4649/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004650 * "maparg()" function
4651 */
4652 static void
4653f_maparg(typval_T *argvars, typval_T *rettv)
4654{
4655 get_maparg(argvars, rettv, TRUE);
4656}
4657
4658/*
4659 * "mapcheck()" function
4660 */
4661 static void
4662f_mapcheck(typval_T *argvars, typval_T *rettv)
4663{
4664 get_maparg(argvars, rettv, FALSE);
4665}
4666
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004667typedef enum
4668{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004669 MATCH_END, // matchend()
4670 MATCH_MATCH, // match()
4671 MATCH_STR, // matchstr()
4672 MATCH_LIST, // matchlist()
4673 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004674} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675
4676 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004677find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004678{
4679 char_u *str = NULL;
4680 long len = 0;
4681 char_u *expr = NULL;
4682 char_u *pat;
4683 regmatch_T regmatch;
4684 char_u patbuf[NUMBUFLEN];
4685 char_u strbuf[NUMBUFLEN];
4686 char_u *save_cpo;
4687 long start = 0;
4688 long nth = 1;
4689 colnr_T startcol = 0;
4690 int match = 0;
4691 list_T *l = NULL;
4692 listitem_T *li = NULL;
4693 long idx = 0;
4694 char_u *tofree = NULL;
4695
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004696 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004697 save_cpo = p_cpo;
4698 p_cpo = (char_u *)"";
4699
4700 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004701 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004703 // type MATCH_LIST: return empty list when there are no matches.
4704 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 if (rettv_list_alloc(rettv) == FAIL)
4706 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004707 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004708 && (list_append_string(rettv->vval.v_list,
4709 (char_u *)"", 0) == FAIL
4710 || list_append_number(rettv->vval.v_list,
4711 (varnumber_T)-1) == FAIL
4712 || list_append_number(rettv->vval.v_list,
4713 (varnumber_T)-1) == FAIL
4714 || list_append_number(rettv->vval.v_list,
4715 (varnumber_T)-1) == FAIL))
4716 {
4717 list_free(rettv->vval.v_list);
4718 rettv->vval.v_list = NULL;
4719 goto theend;
4720 }
4721 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004722 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004723 {
4724 rettv->v_type = VAR_STRING;
4725 rettv->vval.v_string = NULL;
4726 }
4727
4728 if (argvars[0].v_type == VAR_LIST)
4729 {
4730 if ((l = argvars[0].vval.v_list) == NULL)
4731 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004732 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 li = l->lv_first;
4734 }
4735 else
4736 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004737 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004738 len = (long)STRLEN(str);
4739 }
4740
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004741 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004742 if (pat == NULL)
4743 goto theend;
4744
4745 if (argvars[2].v_type != VAR_UNKNOWN)
4746 {
4747 int error = FALSE;
4748
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004749 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004750 if (error)
4751 goto theend;
4752 if (l != NULL)
4753 {
4754 li = list_find(l, start);
4755 if (li == NULL)
4756 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004757 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758 }
4759 else
4760 {
4761 if (start < 0)
4762 start = 0;
4763 if (start > len)
4764 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004765 // When "count" argument is there ignore matches before "start",
4766 // otherwise skip part of the string. Differs when pattern is "^"
4767 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768 if (argvars[3].v_type != VAR_UNKNOWN)
4769 startcol = start;
4770 else
4771 {
4772 str += start;
4773 len -= start;
4774 }
4775 }
4776
4777 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004778 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004779 if (error)
4780 goto theend;
4781 }
4782
4783 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4784 if (regmatch.regprog != NULL)
4785 {
4786 regmatch.rm_ic = p_ic;
4787
4788 for (;;)
4789 {
4790 if (l != NULL)
4791 {
4792 if (li == NULL)
4793 {
4794 match = FALSE;
4795 break;
4796 }
4797 vim_free(tofree);
4798 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4799 if (str == NULL)
4800 break;
4801 }
4802
4803 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4804
4805 if (match && --nth <= 0)
4806 break;
4807 if (l == NULL && !match)
4808 break;
4809
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004810 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004811 if (l != NULL)
4812 {
4813 li = li->li_next;
4814 ++idx;
4815 }
4816 else
4817 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004818 startcol = (colnr_T)(regmatch.startp[0]
4819 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004820 if (startcol > (colnr_T)len
4821 || str + startcol <= regmatch.startp[0])
4822 {
4823 match = FALSE;
4824 break;
4825 }
4826 }
4827 }
4828
4829 if (match)
4830 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004831 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832 {
4833 listitem_T *li1 = rettv->vval.v_list->lv_first;
4834 listitem_T *li2 = li1->li_next;
4835 listitem_T *li3 = li2->li_next;
4836 listitem_T *li4 = li3->li_next;
4837
4838 vim_free(li1->li_tv.vval.v_string);
4839 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4840 (int)(regmatch.endp[0] - regmatch.startp[0]));
4841 li3->li_tv.vval.v_number =
4842 (varnumber_T)(regmatch.startp[0] - expr);
4843 li4->li_tv.vval.v_number =
4844 (varnumber_T)(regmatch.endp[0] - expr);
4845 if (l != NULL)
4846 li2->li_tv.vval.v_number = (varnumber_T)idx;
4847 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004848 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004849 {
4850 int i;
4851
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004852 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853 for (i = 0; i < NSUBEXP; ++i)
4854 {
4855 if (regmatch.endp[i] == NULL)
4856 {
4857 if (list_append_string(rettv->vval.v_list,
4858 (char_u *)"", 0) == FAIL)
4859 break;
4860 }
4861 else if (list_append_string(rettv->vval.v_list,
4862 regmatch.startp[i],
4863 (int)(regmatch.endp[i] - regmatch.startp[i]))
4864 == FAIL)
4865 break;
4866 }
4867 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004868 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004869 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004870 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004871 if (l != NULL)
4872 copy_tv(&li->li_tv, rettv);
4873 else
4874 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4875 (int)(regmatch.endp[0] - regmatch.startp[0]));
4876 }
4877 else if (l != NULL)
4878 rettv->vval.v_number = idx;
4879 else
4880 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004881 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004882 rettv->vval.v_number =
4883 (varnumber_T)(regmatch.startp[0] - str);
4884 else
4885 rettv->vval.v_number =
4886 (varnumber_T)(regmatch.endp[0] - str);
4887 rettv->vval.v_number += (varnumber_T)(str - expr);
4888 }
4889 }
4890 vim_regfree(regmatch.regprog);
4891 }
4892
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004893theend:
4894 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004895 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004896 listitem_remove(rettv->vval.v_list,
4897 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004898 vim_free(tofree);
4899 p_cpo = save_cpo;
4900}
4901
4902/*
4903 * "match()" function
4904 */
4905 static void
4906f_match(typval_T *argvars, typval_T *rettv)
4907{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004908 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909}
4910
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911/*
4912 * "matchend()" function
4913 */
4914 static void
4915f_matchend(typval_T *argvars, typval_T *rettv)
4916{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004917 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004918}
4919
4920/*
4921 * "matchlist()" function
4922 */
4923 static void
4924f_matchlist(typval_T *argvars, typval_T *rettv)
4925{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004926 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004927}
4928
4929/*
4930 * "matchstr()" function
4931 */
4932 static void
4933f_matchstr(typval_T *argvars, typval_T *rettv)
4934{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004935 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004936}
4937
4938/*
4939 * "matchstrpos()" function
4940 */
4941 static void
4942f_matchstrpos(typval_T *argvars, typval_T *rettv)
4943{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004944 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945}
4946
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 static void
4948max_min(typval_T *argvars, typval_T *rettv, int domax)
4949{
4950 varnumber_T n = 0;
4951 varnumber_T i;
4952 int error = FALSE;
4953
4954 if (argvars[0].v_type == VAR_LIST)
4955 {
4956 list_T *l;
4957 listitem_T *li;
4958
4959 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004960 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004962 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004963 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004964 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4965 n = l->lv_u.nonmat.lv_start;
4966 else
4967 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4968 * l->lv_u.nonmat.lv_stride;
4969 }
4970 else
4971 {
4972 li = l->lv_first;
4973 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004974 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004975 n = tv_get_number_chk(&li->li_tv, &error);
4976 for (;;)
4977 {
4978 li = li->li_next;
4979 if (li == NULL)
4980 break;
4981 i = tv_get_number_chk(&li->li_tv, &error);
4982 if (domax ? i > n : i < n)
4983 n = i;
4984 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004985 }
4986 }
4987 }
4988 }
4989 else if (argvars[0].v_type == VAR_DICT)
4990 {
4991 dict_T *d;
4992 int first = TRUE;
4993 hashitem_T *hi;
4994 int todo;
4995
4996 d = argvars[0].vval.v_dict;
4997 if (d != NULL)
4998 {
4999 todo = (int)d->dv_hashtab.ht_used;
5000 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5001 {
5002 if (!HASHITEM_EMPTY(hi))
5003 {
5004 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005005 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005006 if (first)
5007 {
5008 n = i;
5009 first = FALSE;
5010 }
5011 else if (domax ? i > n : i < n)
5012 n = i;
5013 }
5014 }
5015 }
5016 }
5017 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005018 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005019 rettv->vval.v_number = error ? 0 : n;
5020}
5021
5022/*
5023 * "max()" function
5024 */
5025 static void
5026f_max(typval_T *argvars, typval_T *rettv)
5027{
5028 max_min(argvars, rettv, TRUE);
5029}
5030
5031/*
5032 * "min()" function
5033 */
5034 static void
5035f_min(typval_T *argvars, typval_T *rettv)
5036{
5037 max_min(argvars, rettv, FALSE);
5038}
5039
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005040#if defined(FEAT_MZSCHEME) || defined(PROTO)
5041/*
5042 * "mzeval()" function
5043 */
5044 static void
5045f_mzeval(typval_T *argvars, typval_T *rettv)
5046{
5047 char_u *str;
5048 char_u buf[NUMBUFLEN];
5049
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005050 if (check_restricted() || check_secure())
5051 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005052 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053 do_mzeval(str, rettv);
5054}
5055
5056 void
5057mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5058{
5059 typval_T argvars[3];
5060
5061 argvars[0].v_type = VAR_STRING;
5062 argvars[0].vval.v_string = name;
5063 copy_tv(args, &argvars[1]);
5064 argvars[2].v_type = VAR_UNKNOWN;
5065 f_call(argvars, rettv);
5066 clear_tv(&argvars[1]);
5067}
5068#endif
5069
5070/*
5071 * "nextnonblank()" function
5072 */
5073 static void
5074f_nextnonblank(typval_T *argvars, typval_T *rettv)
5075{
5076 linenr_T lnum;
5077
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005078 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005079 {
5080 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5081 {
5082 lnum = 0;
5083 break;
5084 }
5085 if (*skipwhite(ml_get(lnum)) != NUL)
5086 break;
5087 }
5088 rettv->vval.v_number = lnum;
5089}
5090
5091/*
5092 * "nr2char()" function
5093 */
5094 static void
5095f_nr2char(typval_T *argvars, typval_T *rettv)
5096{
5097 char_u buf[NUMBUFLEN];
5098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 if (has_mbyte)
5100 {
5101 int utf8 = 0;
5102
5103 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005104 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005106 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005108 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 }
5110 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005111 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005112 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113 buf[1] = NUL;
5114 }
5115 rettv->v_type = VAR_STRING;
5116 rettv->vval.v_string = vim_strsave(buf);
5117}
5118
5119/*
5120 * "or(expr, expr)" function
5121 */
5122 static void
5123f_or(typval_T *argvars, typval_T *rettv)
5124{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005125 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5126 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127}
5128
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005129#ifdef FEAT_PERL
5130/*
5131 * "perleval()" function
5132 */
5133 static void
5134f_perleval(typval_T *argvars, typval_T *rettv)
5135{
5136 char_u *str;
5137 char_u buf[NUMBUFLEN];
5138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005139 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005140 do_perleval(str, rettv);
5141}
5142#endif
5143
5144#ifdef FEAT_FLOAT
5145/*
5146 * "pow()" function
5147 */
5148 static void
5149f_pow(typval_T *argvars, typval_T *rettv)
5150{
5151 float_T fx = 0.0, fy = 0.0;
5152
5153 rettv->v_type = VAR_FLOAT;
5154 if (get_float_arg(argvars, &fx) == OK
5155 && get_float_arg(&argvars[1], &fy) == OK)
5156 rettv->vval.v_float = pow(fx, fy);
5157 else
5158 rettv->vval.v_float = 0.0;
5159}
5160#endif
5161
5162/*
5163 * "prevnonblank()" function
5164 */
5165 static void
5166f_prevnonblank(typval_T *argvars, typval_T *rettv)
5167{
5168 linenr_T lnum;
5169
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005170 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5172 lnum = 0;
5173 else
5174 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5175 --lnum;
5176 rettv->vval.v_number = lnum;
5177}
5178
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005179// This dummy va_list is here because:
5180// - passing a NULL pointer doesn't work when va_list isn't a pointer
5181// - locally in the function results in a "used before set" warning
5182// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005183static va_list ap;
5184
5185/*
5186 * "printf()" function
5187 */
5188 static void
5189f_printf(typval_T *argvars, typval_T *rettv)
5190{
5191 char_u buf[NUMBUFLEN];
5192 int len;
5193 char_u *s;
5194 int saved_did_emsg = did_emsg;
5195 char *fmt;
5196
5197 rettv->v_type = VAR_STRING;
5198 rettv->vval.v_string = NULL;
5199
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005200 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005202 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005203 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005204 if (!did_emsg)
5205 {
5206 s = alloc(len + 1);
5207 if (s != NULL)
5208 {
5209 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005210 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5211 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005212 }
5213 }
5214 did_emsg |= saved_did_emsg;
5215}
5216
5217/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005218 * "pum_getpos()" function
5219 */
5220 static void
5221f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5222{
5223 if (rettv_dict_alloc(rettv) != OK)
5224 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005225 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005226}
5227
5228/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005229 * "pumvisible()" function
5230 */
5231 static void
5232f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5233{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005234 if (pum_visible())
5235 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005236}
5237
5238#ifdef FEAT_PYTHON3
5239/*
5240 * "py3eval()" function
5241 */
5242 static void
5243f_py3eval(typval_T *argvars, typval_T *rettv)
5244{
5245 char_u *str;
5246 char_u buf[NUMBUFLEN];
5247
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005248 if (check_restricted() || check_secure())
5249 return;
5250
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005251 if (p_pyx == 0)
5252 p_pyx = 3;
5253
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005254 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005255 do_py3eval(str, rettv);
5256}
5257#endif
5258
5259#ifdef FEAT_PYTHON
5260/*
5261 * "pyeval()" function
5262 */
5263 static void
5264f_pyeval(typval_T *argvars, typval_T *rettv)
5265{
5266 char_u *str;
5267 char_u buf[NUMBUFLEN];
5268
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005269 if (check_restricted() || check_secure())
5270 return;
5271
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005272 if (p_pyx == 0)
5273 p_pyx = 2;
5274
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005275 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005276 do_pyeval(str, rettv);
5277}
5278#endif
5279
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005280#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5281/*
5282 * "pyxeval()" function
5283 */
5284 static void
5285f_pyxeval(typval_T *argvars, typval_T *rettv)
5286{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005287 if (check_restricted() || check_secure())
5288 return;
5289
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005290# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5291 init_pyxversion();
5292 if (p_pyx == 2)
5293 f_pyeval(argvars, rettv);
5294 else
5295 f_py3eval(argvars, rettv);
5296# elif defined(FEAT_PYTHON)
5297 f_pyeval(argvars, rettv);
5298# elif defined(FEAT_PYTHON3)
5299 f_py3eval(argvars, rettv);
5300# endif
5301}
5302#endif
5303
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005304static UINT32_T srand_seed_for_testing = 0;
5305static int srand_seed_for_testing_is_used = FALSE;
5306
5307 static void
5308f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5309{
5310 if (argvars[0].v_type == VAR_UNKNOWN)
5311 srand_seed_for_testing_is_used = FALSE;
5312 else
5313 {
5314 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5315 srand_seed_for_testing_is_used = TRUE;
5316 }
5317}
5318
5319 static void
5320init_srand(UINT32_T *x)
5321{
5322#ifndef MSWIN
5323 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5324#endif
5325
5326 if (srand_seed_for_testing_is_used)
5327 {
5328 *x = srand_seed_for_testing;
5329 return;
5330 }
5331#ifndef MSWIN
5332 if (dev_urandom_state != FAIL)
5333 {
5334 int fd = open("/dev/urandom", O_RDONLY);
5335 struct {
5336 union {
5337 UINT32_T number;
5338 char bytes[sizeof(UINT32_T)];
5339 } contents;
5340 } buf;
5341
5342 // Attempt reading /dev/urandom.
5343 if (fd == -1)
5344 dev_urandom_state = FAIL;
5345 else
5346 {
5347 buf.contents.number = 0;
5348 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5349 != sizeof(UINT32_T))
5350 dev_urandom_state = FAIL;
5351 else
5352 {
5353 dev_urandom_state = OK;
5354 *x = buf.contents.number;
5355 }
5356 close(fd);
5357 }
5358 }
5359 if (dev_urandom_state != OK)
5360 // Reading /dev/urandom doesn't work, fall back to time().
5361#endif
5362 *x = vim_time();
5363}
5364
5365#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5366#define SPLITMIX32(x, z) ( \
5367 z = (x += 0x9e3779b9), \
5368 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5369 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5370 z ^ (z >> 16) \
5371 )
5372#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5373 result = ROTL(y * 5, 7) * 9; \
5374 t = y << 9; \
5375 z ^= x; \
5376 w ^= y; \
5377 y ^= z, x ^= w; \
5378 z ^= t; \
5379 w = ROTL(w, 11);
5380
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005381/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005382 * "rand()" function
5383 */
5384 static void
5385f_rand(typval_T *argvars, typval_T *rettv)
5386{
5387 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005388 static UINT32_T gx, gy, gz, gw;
5389 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005390 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005391 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005392
5393 if (argvars[0].v_type == VAR_UNKNOWN)
5394 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005395 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005396 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005397 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005398 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005399 init_srand(&x);
5400
5401 gx = SPLITMIX32(x, z);
5402 gy = SPLITMIX32(x, z);
5403 gz = SPLITMIX32(x, z);
5404 gw = SPLITMIX32(x, z);
5405 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005406 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005407
5408 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005409 }
5410 else if (argvars[0].v_type == VAR_LIST)
5411 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005412 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005413 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005414 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005415
5416 lx = list_find(l, 0L);
5417 ly = list_find(l, 1L);
5418 lz = list_find(l, 2L);
5419 lw = list_find(l, 3L);
5420 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5421 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5422 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5423 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5424 x = (UINT32_T)lx->li_tv.vval.v_number;
5425 y = (UINT32_T)ly->li_tv.vval.v_number;
5426 z = (UINT32_T)lz->li_tv.vval.v_number;
5427 w = (UINT32_T)lw->li_tv.vval.v_number;
5428
5429 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5430
5431 lx->li_tv.vval.v_number = (varnumber_T)x;
5432 ly->li_tv.vval.v_number = (varnumber_T)y;
5433 lz->li_tv.vval.v_number = (varnumber_T)z;
5434 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005435 }
5436 else
5437 goto theend;
5438
5439 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005440 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005441 return;
5442
5443theend:
5444 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005445 rettv->v_type = VAR_NUMBER;
5446 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005447}
5448
5449/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005450 * "srand()" function
5451 */
5452 static void
5453f_srand(typval_T *argvars, typval_T *rettv)
5454{
5455 UINT32_T x = 0, z;
5456
5457 if (rettv_list_alloc(rettv) == FAIL)
5458 return;
5459 if (argvars[0].v_type == VAR_UNKNOWN)
5460 {
5461 init_srand(&x);
5462 }
5463 else
5464 {
5465 int error = FALSE;
5466
5467 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5468 if (error)
5469 return;
5470 }
5471
5472 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5473 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5474 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5475 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5476}
5477
5478#undef ROTL
5479#undef SPLITMIX32
5480#undef SHUFFLE_XOSHIRO128STARSTAR
5481
5482/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005483 * "range()" function
5484 */
5485 static void
5486f_range(typval_T *argvars, typval_T *rettv)
5487{
5488 varnumber_T start;
5489 varnumber_T end;
5490 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491 int error = FALSE;
5492
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005493 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005494 if (argvars[1].v_type == VAR_UNKNOWN)
5495 {
5496 end = start - 1;
5497 start = 0;
5498 }
5499 else
5500 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005501 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005503 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504 }
5505
5506 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005507 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005508 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005509 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005510 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005511 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005512 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005513 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005514 list_T *list = rettv->vval.v_list;
5515
5516 // Create a non-materialized list. This is much more efficient and
5517 // works with ":for". If used otherwise range_list_materialize() must
5518 // be called.
5519 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005520 list->lv_u.nonmat.lv_start = start;
5521 list->lv_u.nonmat.lv_end = end;
5522 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005523 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005524 }
5525}
5526
5527/*
5528 * If "list" is a non-materialized list then materialize it now.
5529 */
5530 void
5531range_list_materialize(list_T *list)
5532{
5533 if (list->lv_first == &range_list_item)
5534 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005535 varnumber_T start = list->lv_u.nonmat.lv_start;
5536 varnumber_T end = list->lv_u.nonmat.lv_end;
5537 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005538 varnumber_T i;
5539
5540 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005541 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005542 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005543 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005544 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5545 if (list_append_number(list, (varnumber_T)i) == FAIL)
5546 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005547 }
5548}
5549
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005550 static void
5551return_register(int regname, typval_T *rettv)
5552{
5553 char_u buf[2] = {0, 0};
5554
5555 buf[0] = (char_u)regname;
5556 rettv->v_type = VAR_STRING;
5557 rettv->vval.v_string = vim_strsave(buf);
5558}
5559
5560/*
5561 * "reg_executing()" function
5562 */
5563 static void
5564f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5565{
5566 return_register(reg_executing, rettv);
5567}
5568
5569/*
5570 * "reg_recording()" function
5571 */
5572 static void
5573f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5574{
5575 return_register(reg_recording, rettv);
5576}
5577
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005578#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005579 static void
5580make_connection(void)
5581{
5582 if (X_DISPLAY == NULL
5583# ifdef FEAT_GUI
5584 && !gui.in_use
5585# endif
5586 )
5587 {
5588 x_force_connect = TRUE;
5589 setup_term_clip();
5590 x_force_connect = FALSE;
5591 }
5592}
5593
5594 static int
5595check_connection(void)
5596{
5597 make_connection();
5598 if (X_DISPLAY == NULL)
5599 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005600 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005601 return FAIL;
5602 }
5603 return OK;
5604}
5605#endif
5606
5607#ifdef FEAT_CLIENTSERVER
5608 static void
5609remote_common(typval_T *argvars, typval_T *rettv, int expr)
5610{
5611 char_u *server_name;
5612 char_u *keys;
5613 char_u *r = NULL;
5614 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005615 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005616# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005617 HWND w;
5618# else
5619 Window w;
5620# endif
5621
5622 if (check_restricted() || check_secure())
5623 return;
5624
5625# ifdef FEAT_X11
5626 if (check_connection() == FAIL)
5627 return;
5628# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005629 if (argvars[2].v_type != VAR_UNKNOWN
5630 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005631 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005632
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005633 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005634 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005635 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005636 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005637# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005638 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005640 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5641 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642# endif
5643 {
5644 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005645 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005646 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005647 vim_free(r);
5648 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005649 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005650 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005651 return;
5652 }
5653
5654 rettv->vval.v_string = r;
5655
5656 if (argvars[2].v_type != VAR_UNKNOWN)
5657 {
5658 dictitem_T v;
5659 char_u str[30];
5660 char_u *idvar;
5661
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005662 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005663 if (idvar != NULL && *idvar != NUL)
5664 {
5665 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5666 v.di_tv.v_type = VAR_STRING;
5667 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005668 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005669 vim_free(v.di_tv.vval.v_string);
5670 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671 }
5672}
5673#endif
5674
5675/*
5676 * "remote_expr()" function
5677 */
5678 static void
5679f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5680{
5681 rettv->v_type = VAR_STRING;
5682 rettv->vval.v_string = NULL;
5683#ifdef FEAT_CLIENTSERVER
5684 remote_common(argvars, rettv, TRUE);
5685#endif
5686}
5687
5688/*
5689 * "remote_foreground()" function
5690 */
5691 static void
5692f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5693{
5694#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005695# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005696 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005697 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005698 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005699
5700 if (server_name != NULL)
5701 serverForeground(server_name);
5702 }
5703# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005704 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005705 argvars[1].v_type = VAR_STRING;
5706 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5707 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005708 rettv->v_type = VAR_STRING;
5709 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005710 remote_common(argvars, rettv, TRUE);
5711 vim_free(argvars[1].vval.v_string);
5712# endif
5713#endif
5714}
5715
5716 static void
5717f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5718{
5719#ifdef FEAT_CLIENTSERVER
5720 dictitem_T v;
5721 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005722# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005723 long_u n = 0;
5724# endif
5725 char_u *serverid;
5726
5727 if (check_restricted() || check_secure())
5728 {
5729 rettv->vval.v_number = -1;
5730 return;
5731 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005732 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005733 if (serverid == NULL)
5734 {
5735 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005736 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005737 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005738# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005739 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5740 if (n == 0)
5741 rettv->vval.v_number = -1;
5742 else
5743 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005744 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005745 rettv->vval.v_number = (s != NULL);
5746 }
5747# else
5748 if (check_connection() == FAIL)
5749 return;
5750
5751 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5752 serverStrToWin(serverid), &s);
5753# endif
5754
5755 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5756 {
5757 char_u *retvar;
5758
5759 v.di_tv.v_type = VAR_STRING;
5760 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005761 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005762 if (retvar != NULL)
5763 set_var(retvar, &v.di_tv, FALSE);
5764 vim_free(v.di_tv.vval.v_string);
5765 }
5766#else
5767 rettv->vval.v_number = -1;
5768#endif
5769}
5770
5771 static void
5772f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5773{
5774 char_u *r = NULL;
5775
5776#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005777 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005778
5779 if (serverid != NULL && !check_restricted() && !check_secure())
5780 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005781 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005782# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005783 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005784 long_u n = 0;
5785# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005786
5787 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005788 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005789
Bram Moolenaar4f974752019-02-17 17:44:42 +01005790# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5792 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005793 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794 if (r == NULL)
5795# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005796 if (check_connection() == FAIL
5797 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5798 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005800 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 }
5802#endif
5803 rettv->v_type = VAR_STRING;
5804 rettv->vval.v_string = r;
5805}
5806
5807/*
5808 * "remote_send()" function
5809 */
5810 static void
5811f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5812{
5813 rettv->v_type = VAR_STRING;
5814 rettv->vval.v_string = NULL;
5815#ifdef FEAT_CLIENTSERVER
5816 remote_common(argvars, rettv, FALSE);
5817#endif
5818}
5819
5820/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005821 * "remote_startserver()" function
5822 */
5823 static void
5824f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5825{
5826#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005827 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005828
5829 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005830 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005831 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005832 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005833 else
5834 {
5835# ifdef FEAT_X11
5836 if (check_connection() == OK)
5837 serverRegisterName(X_DISPLAY, server);
5838# else
5839 serverSetName(server);
5840# endif
5841 }
5842#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005843 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005844#endif
5845}
5846
5847/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005848 * "rename({from}, {to})" function
5849 */
5850 static void
5851f_rename(typval_T *argvars, typval_T *rettv)
5852{
5853 char_u buf[NUMBUFLEN];
5854
5855 if (check_restricted() || check_secure())
5856 rettv->vval.v_number = -1;
5857 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005858 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5859 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005860}
5861
5862/*
5863 * "repeat()" function
5864 */
5865 static void
5866f_repeat(typval_T *argvars, typval_T *rettv)
5867{
5868 char_u *p;
5869 int n;
5870 int slen;
5871 int len;
5872 char_u *r;
5873 int i;
5874
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005875 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005876 if (argvars[0].v_type == VAR_LIST)
5877 {
5878 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5879 while (n-- > 0)
5880 if (list_extend(rettv->vval.v_list,
5881 argvars[0].vval.v_list, NULL) == FAIL)
5882 break;
5883 }
5884 else
5885 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005886 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005887 rettv->v_type = VAR_STRING;
5888 rettv->vval.v_string = NULL;
5889
5890 slen = (int)STRLEN(p);
5891 len = slen * n;
5892 if (len <= 0)
5893 return;
5894
5895 r = alloc(len + 1);
5896 if (r != NULL)
5897 {
5898 for (i = 0; i < n; i++)
5899 mch_memmove(r + i * slen, p, (size_t)slen);
5900 r[len] = NUL;
5901 }
5902
5903 rettv->vval.v_string = r;
5904 }
5905}
5906
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005907#define SP_NOMOVE 0x01 // don't move cursor
5908#define SP_REPEAT 0x02 // repeat to find outer pair
5909#define SP_RETCOUNT 0x04 // return matchcount
5910#define SP_SETPCMARK 0x08 // set previous context mark
5911#define SP_START 0x10 // accept match at start position
5912#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5913#define SP_END 0x40 // leave cursor at end of match
5914#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005915
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005916/*
5917 * Get flags for a search function.
5918 * Possibly sets "p_ws".
5919 * Returns BACKWARD, FORWARD or zero (for an error).
5920 */
5921 static int
5922get_search_arg(typval_T *varp, int *flagsp)
5923{
5924 int dir = FORWARD;
5925 char_u *flags;
5926 char_u nbuf[NUMBUFLEN];
5927 int mask;
5928
5929 if (varp->v_type != VAR_UNKNOWN)
5930 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005931 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005932 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005933 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005934 while (*flags != NUL)
5935 {
5936 switch (*flags)
5937 {
5938 case 'b': dir = BACKWARD; break;
5939 case 'w': p_ws = TRUE; break;
5940 case 'W': p_ws = FALSE; break;
5941 default: mask = 0;
5942 if (flagsp != NULL)
5943 switch (*flags)
5944 {
5945 case 'c': mask = SP_START; break;
5946 case 'e': mask = SP_END; break;
5947 case 'm': mask = SP_RETCOUNT; break;
5948 case 'n': mask = SP_NOMOVE; break;
5949 case 'p': mask = SP_SUBPAT; break;
5950 case 'r': mask = SP_REPEAT; break;
5951 case 's': mask = SP_SETPCMARK; break;
5952 case 'z': mask = SP_COLUMN; break;
5953 }
5954 if (mask == 0)
5955 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005956 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005957 dir = 0;
5958 }
5959 else
5960 *flagsp |= mask;
5961 }
5962 if (dir == 0)
5963 break;
5964 ++flags;
5965 }
5966 }
5967 return dir;
5968}
5969
5970/*
5971 * Shared by search() and searchpos() functions.
5972 */
5973 static int
5974search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5975{
5976 int flags;
5977 char_u *pat;
5978 pos_T pos;
5979 pos_T save_cursor;
5980 int save_p_ws = p_ws;
5981 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005982 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005983 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005984#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005985 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005986 long time_limit = 0;
5987#endif
5988 int options = SEARCH_KEEP;
5989 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005990 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005991
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005992 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005993 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994 if (dir == 0)
5995 goto theend;
5996 flags = *flagsp;
5997 if (flags & SP_START)
5998 options |= SEARCH_START;
5999 if (flags & SP_END)
6000 options |= SEARCH_END;
6001 if (flags & SP_COLUMN)
6002 options |= SEARCH_COL;
6003
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006004 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006005 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6006 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006007 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006008 if (lnum_stop < 0)
6009 goto theend;
6010#ifdef FEAT_RELTIME
6011 if (argvars[3].v_type != VAR_UNKNOWN)
6012 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006013 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006014 if (time_limit < 0)
6015 goto theend;
6016 }
6017#endif
6018 }
6019
6020#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006021 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006022 profile_setlimit(time_limit, &tm);
6023#endif
6024
6025 /*
6026 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6027 * Check to make sure only those flags are set.
6028 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6029 * flags cannot be set. Check for that condition also.
6030 */
6031 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6032 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6033 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006034 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006035 goto theend;
6036 }
6037
6038 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006039 vim_memset(&sia, 0, sizeof(sia));
6040 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6041#ifdef FEAT_RELTIME
6042 sia.sa_tm = &tm;
6043#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006044 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006045 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006046 if (subpatnum != FAIL)
6047 {
6048 if (flags & SP_SUBPAT)
6049 retval = subpatnum;
6050 else
6051 retval = pos.lnum;
6052 if (flags & SP_SETPCMARK)
6053 setpcmark();
6054 curwin->w_cursor = pos;
6055 if (match_pos != NULL)
6056 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006057 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006058 match_pos->lnum = pos.lnum;
6059 match_pos->col = pos.col + 1;
6060 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006061 // "/$" will put the cursor after the end of the line, may need to
6062 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063 check_cursor();
6064 }
6065
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006066 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006067 if (flags & SP_NOMOVE)
6068 curwin->w_cursor = save_cursor;
6069 else
6070 curwin->w_set_curswant = TRUE;
6071theend:
6072 p_ws = save_p_ws;
6073
6074 return retval;
6075}
6076
6077#ifdef FEAT_FLOAT
6078
6079/*
6080 * round() is not in C90, use ceil() or floor() instead.
6081 */
6082 float_T
6083vim_round(float_T f)
6084{
6085 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6086}
6087
6088/*
6089 * "round({float})" function
6090 */
6091 static void
6092f_round(typval_T *argvars, typval_T *rettv)
6093{
6094 float_T f = 0.0;
6095
6096 rettv->v_type = VAR_FLOAT;
6097 if (get_float_arg(argvars, &f) == OK)
6098 rettv->vval.v_float = vim_round(f);
6099 else
6100 rettv->vval.v_float = 0.0;
6101}
6102#endif
6103
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006104#ifdef FEAT_RUBY
6105/*
6106 * "rubyeval()" function
6107 */
6108 static void
6109f_rubyeval(typval_T *argvars, typval_T *rettv)
6110{
6111 char_u *str;
6112 char_u buf[NUMBUFLEN];
6113
6114 str = tv_get_string_buf(&argvars[0], buf);
6115 do_rubyeval(str, rettv);
6116}
6117#endif
6118
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006119/*
6120 * "screenattr()" function
6121 */
6122 static void
6123f_screenattr(typval_T *argvars, typval_T *rettv)
6124{
6125 int row;
6126 int col;
6127 int c;
6128
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006129 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6130 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006131 if (row < 0 || row >= screen_Rows
6132 || col < 0 || col >= screen_Columns)
6133 c = -1;
6134 else
6135 c = ScreenAttrs[LineOffset[row] + col];
6136 rettv->vval.v_number = c;
6137}
6138
6139/*
6140 * "screenchar()" function
6141 */
6142 static void
6143f_screenchar(typval_T *argvars, typval_T *rettv)
6144{
6145 int row;
6146 int col;
6147 int off;
6148 int c;
6149
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006150 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6151 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006152 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006153 c = -1;
6154 else
6155 {
6156 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006157 if (enc_utf8 && ScreenLinesUC[off] != 0)
6158 c = ScreenLinesUC[off];
6159 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160 c = ScreenLines[off];
6161 }
6162 rettv->vval.v_number = c;
6163}
6164
6165/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006166 * "screenchars()" function
6167 */
6168 static void
6169f_screenchars(typval_T *argvars, typval_T *rettv)
6170{
6171 int row;
6172 int col;
6173 int off;
6174 int c;
6175 int i;
6176
6177 if (rettv_list_alloc(rettv) == FAIL)
6178 return;
6179 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6180 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6181 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6182 return;
6183
6184 off = LineOffset[row] + col;
6185 if (enc_utf8 && ScreenLinesUC[off] != 0)
6186 c = ScreenLinesUC[off];
6187 else
6188 c = ScreenLines[off];
6189 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6190
6191 if (enc_utf8)
6192
6193 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6194 list_append_number(rettv->vval.v_list,
6195 (varnumber_T)ScreenLinesC[i][off]);
6196}
6197
6198/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006199 * "screencol()" function
6200 *
6201 * First column is 1 to be consistent with virtcol().
6202 */
6203 static void
6204f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6205{
6206 rettv->vval.v_number = screen_screencol() + 1;
6207}
6208
6209/*
6210 * "screenrow()" function
6211 */
6212 static void
6213f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6214{
6215 rettv->vval.v_number = screen_screenrow() + 1;
6216}
6217
6218/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006219 * "screenstring()" function
6220 */
6221 static void
6222f_screenstring(typval_T *argvars, typval_T *rettv)
6223{
6224 int row;
6225 int col;
6226 int off;
6227 int c;
6228 int i;
6229 char_u buf[MB_MAXBYTES + 1];
6230 int buflen = 0;
6231
6232 rettv->vval.v_string = NULL;
6233 rettv->v_type = VAR_STRING;
6234
6235 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6236 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6237 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6238 return;
6239
6240 off = LineOffset[row] + col;
6241 if (enc_utf8 && ScreenLinesUC[off] != 0)
6242 c = ScreenLinesUC[off];
6243 else
6244 c = ScreenLines[off];
6245 buflen += mb_char2bytes(c, buf);
6246
6247 if (enc_utf8)
6248 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6249 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6250
6251 buf[buflen] = NUL;
6252 rettv->vval.v_string = vim_strsave(buf);
6253}
6254
6255/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006256 * "search()" function
6257 */
6258 static void
6259f_search(typval_T *argvars, typval_T *rettv)
6260{
6261 int flags = 0;
6262
6263 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6264}
6265
6266/*
6267 * "searchdecl()" function
6268 */
6269 static void
6270f_searchdecl(typval_T *argvars, typval_T *rettv)
6271{
6272 int locally = 1;
6273 int thisblock = 0;
6274 int error = FALSE;
6275 char_u *name;
6276
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006277 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006278
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006279 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006280 if (argvars[1].v_type != VAR_UNKNOWN)
6281 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006282 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006284 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 }
6286 if (!error && name != NULL)
6287 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6288 locally, thisblock, SEARCH_KEEP) == FAIL;
6289}
6290
6291/*
6292 * Used by searchpair() and searchpairpos()
6293 */
6294 static int
6295searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6296{
6297 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006298 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006299 int save_p_ws = p_ws;
6300 int dir;
6301 int flags = 0;
6302 char_u nbuf1[NUMBUFLEN];
6303 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006304 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006305 long lnum_stop = 0;
6306 long time_limit = 0;
6307
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006308 // Get the three pattern arguments: start, middle, end. Will result in an
6309 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006310 spat = tv_get_string_chk(&argvars[0]);
6311 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6312 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006314 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006316 // Handle the optional fourth argument: flags
6317 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318 if (dir == 0)
6319 goto theend;
6320
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006321 // Don't accept SP_END or SP_SUBPAT.
6322 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323 if ((flags & (SP_END | SP_SUBPAT)) != 0
6324 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6325 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006326 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006327 goto theend;
6328 }
6329
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006330 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006331 if (flags & SP_REPEAT)
6332 p_ws = FALSE;
6333
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006334 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335 if (argvars[3].v_type == VAR_UNKNOWN
6336 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006337 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006338 else
6339 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006340 skip = &argvars[4];
6341 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6342 && skip->v_type != VAR_STRING)
6343 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006344 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006345 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006346 goto theend;
6347 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006348 if (argvars[5].v_type != VAR_UNKNOWN)
6349 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006350 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006352 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006353 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006354 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006355 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006356#ifdef FEAT_RELTIME
6357 if (argvars[6].v_type != VAR_UNKNOWN)
6358 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006359 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006360 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006361 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006362 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006364 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365 }
6366#endif
6367 }
6368 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006369
6370 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6371 match_pos, lnum_stop, time_limit);
6372
6373theend:
6374 p_ws = save_p_ws;
6375
6376 return retval;
6377}
6378
6379/*
6380 * "searchpair()" function
6381 */
6382 static void
6383f_searchpair(typval_T *argvars, typval_T *rettv)
6384{
6385 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6386}
6387
6388/*
6389 * "searchpairpos()" function
6390 */
6391 static void
6392f_searchpairpos(typval_T *argvars, typval_T *rettv)
6393{
6394 pos_T match_pos;
6395 int lnum = 0;
6396 int col = 0;
6397
6398 if (rettv_list_alloc(rettv) == FAIL)
6399 return;
6400
6401 if (searchpair_cmn(argvars, &match_pos) > 0)
6402 {
6403 lnum = match_pos.lnum;
6404 col = match_pos.col;
6405 }
6406
6407 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6408 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6409}
6410
6411/*
6412 * Search for a start/middle/end thing.
6413 * Used by searchpair(), see its documentation for the details.
6414 * Returns 0 or -1 for no match,
6415 */
6416 long
6417do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006418 char_u *spat, // start pattern
6419 char_u *mpat, // middle pattern
6420 char_u *epat, // end pattern
6421 int dir, // BACKWARD or FORWARD
6422 typval_T *skip, // skip expression
6423 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006424 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006425 linenr_T lnum_stop, // stop at this line if not zero
6426 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427{
6428 char_u *save_cpo;
6429 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6430 long retval = 0;
6431 pos_T pos;
6432 pos_T firstpos;
6433 pos_T foundpos;
6434 pos_T save_cursor;
6435 pos_T save_pos;
6436 int n;
6437 int r;
6438 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006439 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006440 int err;
6441 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006442#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006444#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006446 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006447 save_cpo = p_cpo;
6448 p_cpo = empty_option;
6449
6450#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006451 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006452 profile_setlimit(time_limit, &tm);
6453#endif
6454
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006455 // Make two search patterns: start/end (pat2, for in nested pairs) and
6456 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006457 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6458 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006459 if (pat2 == NULL || pat3 == NULL)
6460 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006461 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 if (*mpat == NUL)
6463 STRCPY(pat3, pat2);
6464 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006465 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466 spat, epat, mpat);
6467 if (flags & SP_START)
6468 options |= SEARCH_START;
6469
Bram Moolenaar48570482017-10-30 21:48:41 +01006470 if (skip != NULL)
6471 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006472 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006473 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6474 use_skip = skip->vval.v_string != NULL
6475 && *skip->vval.v_string != NUL;
6476 }
6477
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478 save_cursor = curwin->w_cursor;
6479 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006480 CLEAR_POS(&firstpos);
6481 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482 pat = pat3;
6483 for (;;)
6484 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006485 searchit_arg_T sia;
6486
6487 vim_memset(&sia, 0, sizeof(sia));
6488 sia.sa_stop_lnum = lnum_stop;
6489#ifdef FEAT_RELTIME
6490 sia.sa_tm = &tm;
6491#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006492 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006493 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006494 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006495 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 break;
6497
6498 if (firstpos.lnum == 0)
6499 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006500 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006502 // Found the same position again. Can happen with a pattern that
6503 // has "\zs" at the end and searching backwards. Advance one
6504 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505 if (dir == BACKWARD)
6506 decl(&pos);
6507 else
6508 incl(&pos);
6509 }
6510 foundpos = pos;
6511
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006512 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006513 options &= ~SEARCH_START;
6514
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006515 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006516 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006517 {
6518 save_pos = curwin->w_cursor;
6519 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006520 err = FALSE;
6521 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006522 curwin->w_cursor = save_pos;
6523 if (err)
6524 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006525 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526 curwin->w_cursor = save_cursor;
6527 retval = -1;
6528 break;
6529 }
6530 if (r)
6531 continue;
6532 }
6533
6534 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6535 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006536 // Found end when searching backwards or start when searching
6537 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006539 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006540 }
6541 else
6542 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006543 // Found end when searching forward or start when searching
6544 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006545 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006546 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006547 }
6548
6549 if (nest == 0)
6550 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006551 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006552 if (flags & SP_RETCOUNT)
6553 ++retval;
6554 else
6555 retval = pos.lnum;
6556 if (flags & SP_SETPCMARK)
6557 setpcmark();
6558 curwin->w_cursor = pos;
6559 if (!(flags & SP_REPEAT))
6560 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006561 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562 }
6563 }
6564
6565 if (match_pos != NULL)
6566 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006567 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568 match_pos->lnum = curwin->w_cursor.lnum;
6569 match_pos->col = curwin->w_cursor.col + 1;
6570 }
6571
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006572 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006573 if ((flags & SP_NOMOVE) || retval == 0)
6574 curwin->w_cursor = save_cursor;
6575
6576theend:
6577 vim_free(pat2);
6578 vim_free(pat3);
6579 if (p_cpo == empty_option)
6580 p_cpo = save_cpo;
6581 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006582 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583 free_string_option(save_cpo);
6584
6585 return retval;
6586}
6587
6588/*
6589 * "searchpos()" function
6590 */
6591 static void
6592f_searchpos(typval_T *argvars, typval_T *rettv)
6593{
6594 pos_T match_pos;
6595 int lnum = 0;
6596 int col = 0;
6597 int n;
6598 int flags = 0;
6599
6600 if (rettv_list_alloc(rettv) == FAIL)
6601 return;
6602
6603 n = search_cmn(argvars, &match_pos, &flags);
6604 if (n > 0)
6605 {
6606 lnum = match_pos.lnum;
6607 col = match_pos.col;
6608 }
6609
6610 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6611 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6612 if (flags & SP_SUBPAT)
6613 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6614}
6615
6616 static void
6617f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6618{
6619#ifdef FEAT_CLIENTSERVER
6620 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006621 char_u *server = tv_get_string_chk(&argvars[0]);
6622 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006623
6624 rettv->vval.v_number = -1;
6625 if (server == NULL || reply == NULL)
6626 return;
6627 if (check_restricted() || check_secure())
6628 return;
6629# ifdef FEAT_X11
6630 if (check_connection() == FAIL)
6631 return;
6632# endif
6633
6634 if (serverSendReply(server, reply) < 0)
6635 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006636 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006637 return;
6638 }
6639 rettv->vval.v_number = 0;
6640#else
6641 rettv->vval.v_number = -1;
6642#endif
6643}
6644
6645 static void
6646f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6647{
6648 char_u *r = NULL;
6649
6650#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006651# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652 r = serverGetVimNames();
6653# else
6654 make_connection();
6655 if (X_DISPLAY != NULL)
6656 r = serverGetVimNames(X_DISPLAY);
6657# endif
6658#endif
6659 rettv->v_type = VAR_STRING;
6660 rettv->vval.v_string = r;
6661}
6662
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006663 static void
6664f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6665{
6666 dict_T *d;
6667 dictitem_T *di;
6668 char_u *csearch;
6669
6670 if (argvars[0].v_type != VAR_DICT)
6671 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006672 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006673 return;
6674 }
6675
6676 if ((d = argvars[0].vval.v_dict) != NULL)
6677 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006678 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006679 if (csearch != NULL)
6680 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006681 if (enc_utf8)
6682 {
6683 int pcc[MAX_MCO];
6684 int c = utfc_ptr2char(csearch, pcc);
6685
6686 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6687 }
6688 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006690 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006691 }
6692
6693 di = dict_find(d, (char_u *)"forward", -1);
6694 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006695 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006696 ? FORWARD : BACKWARD);
6697
6698 di = dict_find(d, (char_u *)"until", -1);
6699 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006700 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 }
6702}
6703
6704/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006705 * "setenv()" function
6706 */
6707 static void
6708f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6709{
6710 char_u namebuf[NUMBUFLEN];
6711 char_u valbuf[NUMBUFLEN];
6712 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6713
6714 if (argvars[1].v_type == VAR_SPECIAL
6715 && argvars[1].vval.v_number == VVAL_NULL)
6716 vim_unsetenv(name);
6717 else
6718 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6719}
6720
6721/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006722 * "setfperm({fname}, {mode})" function
6723 */
6724 static void
6725f_setfperm(typval_T *argvars, typval_T *rettv)
6726{
6727 char_u *fname;
6728 char_u modebuf[NUMBUFLEN];
6729 char_u *mode_str;
6730 int i;
6731 int mask;
6732 int mode = 0;
6733
6734 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006735 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006736 if (fname == NULL)
6737 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006738 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 if (mode_str == NULL)
6740 return;
6741 if (STRLEN(mode_str) != 9)
6742 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006743 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006744 return;
6745 }
6746
6747 mask = 1;
6748 for (i = 8; i >= 0; --i)
6749 {
6750 if (mode_str[i] != '-')
6751 mode |= mask;
6752 mask = mask << 1;
6753 }
6754 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6755}
6756
6757/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 * "setpos()" function
6759 */
6760 static void
6761f_setpos(typval_T *argvars, typval_T *rettv)
6762{
6763 pos_T pos;
6764 int fnum;
6765 char_u *name;
6766 colnr_T curswant = -1;
6767
6768 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006769 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770 if (name != NULL)
6771 {
6772 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6773 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006774 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006775 pos.col = 0;
6776 if (name[0] == '.' && name[1] == NUL)
6777 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006778 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006779 curwin->w_cursor = pos;
6780 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006781 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006782 curwin->w_curswant = curswant - 1;
6783 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006784 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006785 check_cursor();
6786 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006787 }
6788 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6789 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006790 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006791 if (setmark_pos(name[1], &pos, fnum) == OK)
6792 rettv->vval.v_number = 0;
6793 }
6794 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006795 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 }
6797 }
6798}
6799
6800/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006801 * "setreg()" function
6802 */
6803 static void
6804f_setreg(typval_T *argvars, typval_T *rettv)
6805{
6806 int regname;
6807 char_u *strregname;
6808 char_u *stropt;
6809 char_u *strval;
6810 int append;
6811 char_u yank_type;
6812 long block_len;
6813
6814 block_len = -1;
6815 yank_type = MAUTO;
6816 append = FALSE;
6817
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006818 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006819 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006820
6821 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006822 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006823 regname = *strregname;
6824 if (regname == 0 || regname == '@')
6825 regname = '"';
6826
6827 if (argvars[2].v_type != VAR_UNKNOWN)
6828 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006829 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006831 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006832 for (; *stropt != NUL; ++stropt)
6833 switch (*stropt)
6834 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006835 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836 append = TRUE;
6837 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006838 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006839 yank_type = MCHAR;
6840 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006841 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842 yank_type = MLINE;
6843 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006844 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006845 yank_type = MBLOCK;
6846 if (VIM_ISDIGIT(stropt[1]))
6847 {
6848 ++stropt;
6849 block_len = getdigits(&stropt) - 1;
6850 --stropt;
6851 }
6852 break;
6853 }
6854 }
6855
6856 if (argvars[1].v_type == VAR_LIST)
6857 {
6858 char_u **lstval;
6859 char_u **allocval;
6860 char_u buf[NUMBUFLEN];
6861 char_u **curval;
6862 char_u **curallocval;
6863 list_T *ll = argvars[1].vval.v_list;
6864 listitem_T *li;
6865 int len;
6866
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006867 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868 len = ll == NULL ? 0 : ll->lv_len;
6869
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006870 // First half: use for pointers to result lines; second half: use for
6871 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006872 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006873 if (lstval == NULL)
6874 return;
6875 curval = lstval;
6876 allocval = lstval + len + 2;
6877 curallocval = allocval;
6878
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006879 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006881 range_list_materialize(ll);
6882 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006884 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006885 if (strval == NULL)
6886 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006887 if (strval == buf)
6888 {
6889 // Need to make a copy, next tv_get_string_buf_chk() will
6890 // overwrite the string.
6891 strval = vim_strsave(buf);
6892 if (strval == NULL)
6893 goto free_lstval;
6894 *curallocval++ = strval;
6895 }
6896 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006897 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006898 }
6899 *curval++ = NULL;
6900
6901 write_reg_contents_lst(regname, lstval, -1,
6902 append, yank_type, block_len);
6903free_lstval:
6904 while (curallocval > allocval)
6905 vim_free(*--curallocval);
6906 vim_free(lstval);
6907 }
6908 else
6909 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006910 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006911 if (strval == NULL)
6912 return;
6913 write_reg_contents_ex(regname, strval, -1,
6914 append, yank_type, block_len);
6915 }
6916 rettv->vval.v_number = 0;
6917}
6918
6919/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006920 * "settagstack()" function
6921 */
6922 static void
6923f_settagstack(typval_T *argvars, typval_T *rettv)
6924{
6925 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6926 win_T *wp;
6927 dict_T *d;
6928 int action = 'r';
6929
6930 rettv->vval.v_number = -1;
6931
6932 // first argument: window number or id
6933 wp = find_win_by_nr_or_id(&argvars[0]);
6934 if (wp == NULL)
6935 return;
6936
6937 // second argument: dict with items to set in the tag stack
6938 if (argvars[1].v_type != VAR_DICT)
6939 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006940 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006941 return;
6942 }
6943 d = argvars[1].vval.v_dict;
6944 if (d == NULL)
6945 return;
6946
6947 // third argument: action - 'a' for append and 'r' for replace.
6948 // default is to replace the stack.
6949 if (argvars[2].v_type == VAR_UNKNOWN)
6950 action = 'r';
6951 else if (argvars[2].v_type == VAR_STRING)
6952 {
6953 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006954 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006955 if (actstr == NULL)
6956 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006957 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6958 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006959 action = *actstr;
6960 else
6961 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006962 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006963 return;
6964 }
6965 }
6966 else
6967 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006968 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006969 return;
6970 }
6971
6972 if (set_tagstack(wp, d, action) == OK)
6973 rettv->vval.v_number = 0;
6974}
6975
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006976#ifdef FEAT_CRYPT
6977/*
6978 * "sha256({string})" function
6979 */
6980 static void
6981f_sha256(typval_T *argvars, typval_T *rettv)
6982{
6983 char_u *p;
6984
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006985 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986 rettv->vval.v_string = vim_strsave(
6987 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6988 rettv->v_type = VAR_STRING;
6989}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006990#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991
6992/*
6993 * "shellescape({string})" function
6994 */
6995 static void
6996f_shellescape(typval_T *argvars, typval_T *rettv)
6997{
Bram Moolenaar20615522017-06-05 18:46:26 +02006998 int do_special = non_zero_arg(&argvars[1]);
6999
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007000 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007001 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007002 rettv->v_type = VAR_STRING;
7003}
7004
7005/*
7006 * shiftwidth() function
7007 */
7008 static void
7009f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7010{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007011 rettv->vval.v_number = 0;
7012
7013 if (argvars[0].v_type != VAR_UNKNOWN)
7014 {
7015 long col;
7016
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007017 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007018 if (col < 0)
7019 return; // type error; errmsg already given
7020#ifdef FEAT_VARTABS
7021 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7022 return;
7023#endif
7024 }
7025
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007026 rettv->vval.v_number = get_sw_value(curbuf);
7027}
7028
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029#ifdef FEAT_FLOAT
7030/*
7031 * "sin()" function
7032 */
7033 static void
7034f_sin(typval_T *argvars, typval_T *rettv)
7035{
7036 float_T f = 0.0;
7037
7038 rettv->v_type = VAR_FLOAT;
7039 if (get_float_arg(argvars, &f) == OK)
7040 rettv->vval.v_float = sin(f);
7041 else
7042 rettv->vval.v_float = 0.0;
7043}
7044
7045/*
7046 * "sinh()" function
7047 */
7048 static void
7049f_sinh(typval_T *argvars, typval_T *rettv)
7050{
7051 float_T f = 0.0;
7052
7053 rettv->v_type = VAR_FLOAT;
7054 if (get_float_arg(argvars, &f) == OK)
7055 rettv->vval.v_float = sinh(f);
7056 else
7057 rettv->vval.v_float = 0.0;
7058}
7059#endif
7060
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007061/*
7062 * "soundfold({word})" function
7063 */
7064 static void
7065f_soundfold(typval_T *argvars, typval_T *rettv)
7066{
7067 char_u *s;
7068
7069 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007070 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071#ifdef FEAT_SPELL
7072 rettv->vval.v_string = eval_soundfold(s);
7073#else
7074 rettv->vval.v_string = vim_strsave(s);
7075#endif
7076}
7077
7078/*
7079 * "spellbadword()" function
7080 */
7081 static void
7082f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7083{
7084 char_u *word = (char_u *)"";
7085 hlf_T attr = HLF_COUNT;
7086 int len = 0;
7087
7088 if (rettv_list_alloc(rettv) == FAIL)
7089 return;
7090
7091#ifdef FEAT_SPELL
7092 if (argvars[0].v_type == VAR_UNKNOWN)
7093 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007094 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007095 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7096 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007097 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007098 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007099 curwin->w_set_curswant = TRUE;
7100 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007101 }
7102 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7103 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007104 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007105 int capcol = -1;
7106
7107 if (str != NULL)
7108 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007109 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007110 while (*str != NUL)
7111 {
7112 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7113 if (attr != HLF_COUNT)
7114 {
7115 word = str;
7116 break;
7117 }
7118 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007119 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007120 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007121 }
7122 }
7123 }
7124#endif
7125
7126 list_append_string(rettv->vval.v_list, word, len);
7127 list_append_string(rettv->vval.v_list, (char_u *)(
7128 attr == HLF_SPB ? "bad" :
7129 attr == HLF_SPR ? "rare" :
7130 attr == HLF_SPL ? "local" :
7131 attr == HLF_SPC ? "caps" :
7132 ""), -1);
7133}
7134
7135/*
7136 * "spellsuggest()" function
7137 */
7138 static void
7139f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7140{
7141#ifdef FEAT_SPELL
7142 char_u *str;
7143 int typeerr = FALSE;
7144 int maxcount;
7145 garray_T ga;
7146 int i;
7147 listitem_T *li;
7148 int need_capital = FALSE;
7149#endif
7150
7151 if (rettv_list_alloc(rettv) == FAIL)
7152 return;
7153
7154#ifdef FEAT_SPELL
7155 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7156 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007157 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007158 if (argvars[1].v_type != VAR_UNKNOWN)
7159 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007160 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007161 if (maxcount <= 0)
7162 return;
7163 if (argvars[2].v_type != VAR_UNKNOWN)
7164 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007165 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007166 if (typeerr)
7167 return;
7168 }
7169 }
7170 else
7171 maxcount = 25;
7172
7173 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7174
7175 for (i = 0; i < ga.ga_len; ++i)
7176 {
7177 str = ((char_u **)ga.ga_data)[i];
7178
7179 li = listitem_alloc();
7180 if (li == NULL)
7181 vim_free(str);
7182 else
7183 {
7184 li->li_tv.v_type = VAR_STRING;
7185 li->li_tv.v_lock = 0;
7186 li->li_tv.vval.v_string = str;
7187 list_append(rettv->vval.v_list, li);
7188 }
7189 }
7190 ga_clear(&ga);
7191 }
7192#endif
7193}
7194
7195 static void
7196f_split(typval_T *argvars, typval_T *rettv)
7197{
7198 char_u *str;
7199 char_u *end;
7200 char_u *pat = NULL;
7201 regmatch_T regmatch;
7202 char_u patbuf[NUMBUFLEN];
7203 char_u *save_cpo;
7204 int match;
7205 colnr_T col = 0;
7206 int keepempty = FALSE;
7207 int typeerr = FALSE;
7208
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007209 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007210 save_cpo = p_cpo;
7211 p_cpo = (char_u *)"";
7212
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007213 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007214 if (argvars[1].v_type != VAR_UNKNOWN)
7215 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007216 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007217 if (pat == NULL)
7218 typeerr = TRUE;
7219 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007220 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007221 }
7222 if (pat == NULL || *pat == NUL)
7223 pat = (char_u *)"[\\x01- ]\\+";
7224
7225 if (rettv_list_alloc(rettv) == FAIL)
7226 return;
7227 if (typeerr)
7228 return;
7229
7230 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7231 if (regmatch.regprog != NULL)
7232 {
7233 regmatch.rm_ic = FALSE;
7234 while (*str != NUL || keepempty)
7235 {
7236 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007237 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238 else
7239 match = vim_regexec_nl(&regmatch, str, col);
7240 if (match)
7241 end = regmatch.startp[0];
7242 else
7243 end = str + STRLEN(str);
7244 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7245 && *str != NUL && match && end < regmatch.endp[0]))
7246 {
7247 if (list_append_string(rettv->vval.v_list, str,
7248 (int)(end - str)) == FAIL)
7249 break;
7250 }
7251 if (!match)
7252 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007253 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 if (regmatch.endp[0] > str)
7255 col = 0;
7256 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007257 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007259 str = regmatch.endp[0];
7260 }
7261
7262 vim_regfree(regmatch.regprog);
7263 }
7264
7265 p_cpo = save_cpo;
7266}
7267
7268#ifdef FEAT_FLOAT
7269/*
7270 * "sqrt()" function
7271 */
7272 static void
7273f_sqrt(typval_T *argvars, typval_T *rettv)
7274{
7275 float_T f = 0.0;
7276
7277 rettv->v_type = VAR_FLOAT;
7278 if (get_float_arg(argvars, &f) == OK)
7279 rettv->vval.v_float = sqrt(f);
7280 else
7281 rettv->vval.v_float = 0.0;
7282}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007283#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007284
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007285#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007286/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007287 * "str2float()" function
7288 */
7289 static void
7290f_str2float(typval_T *argvars, typval_T *rettv)
7291{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007292 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007293 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294
Bram Moolenaar08243d22017-01-10 16:12:29 +01007295 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007296 p = skipwhite(p + 1);
7297 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007298 if (isneg)
7299 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007300 rettv->v_type = VAR_FLOAT;
7301}
7302#endif
7303
7304/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007305 * "str2list()" function
7306 */
7307 static void
7308f_str2list(typval_T *argvars, typval_T *rettv)
7309{
7310 char_u *p;
7311 int utf8 = FALSE;
7312
7313 if (rettv_list_alloc(rettv) == FAIL)
7314 return;
7315
7316 if (argvars[1].v_type != VAR_UNKNOWN)
7317 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7318
7319 p = tv_get_string(&argvars[0]);
7320
7321 if (has_mbyte || utf8)
7322 {
7323 int (*ptr2len)(char_u *);
7324 int (*ptr2char)(char_u *);
7325
7326 if (utf8 || enc_utf8)
7327 {
7328 ptr2len = utf_ptr2len;
7329 ptr2char = utf_ptr2char;
7330 }
7331 else
7332 {
7333 ptr2len = mb_ptr2len;
7334 ptr2char = mb_ptr2char;
7335 }
7336
7337 for ( ; *p != NUL; p += (*ptr2len)(p))
7338 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7339 }
7340 else
7341 for ( ; *p != NUL; ++p)
7342 list_append_number(rettv->vval.v_list, *p);
7343}
7344
7345/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346 * "str2nr()" function
7347 */
7348 static void
7349f_str2nr(typval_T *argvars, typval_T *rettv)
7350{
7351 int base = 10;
7352 char_u *p;
7353 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007354 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007355 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356
7357 if (argvars[1].v_type != VAR_UNKNOWN)
7358 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007359 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007360 if (base != 2 && base != 8 && base != 10 && base != 16)
7361 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007362 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007363 return;
7364 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007365 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7366 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007367 }
7368
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007369 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007370 isneg = (*p == '-');
7371 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007372 p = skipwhite(p + 1);
7373 switch (base)
7374 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007375 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7376 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7377 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007378 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007379 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7380 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007381 if (isneg)
7382 rettv->vval.v_number = -n;
7383 else
7384 rettv->vval.v_number = n;
7385
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386}
7387
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388/*
7389 * "strgetchar()" function
7390 */
7391 static void
7392f_strgetchar(typval_T *argvars, typval_T *rettv)
7393{
7394 char_u *str;
7395 int len;
7396 int error = FALSE;
7397 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007398 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007399
7400 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007401 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007402 if (str == NULL)
7403 return;
7404 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007405 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007406 if (error)
7407 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007408
Bram Moolenaar13505972019-01-24 15:04:48 +01007409 while (charidx >= 0 && byteidx < len)
7410 {
7411 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007413 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7414 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007415 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007416 --charidx;
7417 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007419}
7420
7421/*
7422 * "stridx()" function
7423 */
7424 static void
7425f_stridx(typval_T *argvars, typval_T *rettv)
7426{
7427 char_u buf[NUMBUFLEN];
7428 char_u *needle;
7429 char_u *haystack;
7430 char_u *save_haystack;
7431 char_u *pos;
7432 int start_idx;
7433
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007434 needle = tv_get_string_chk(&argvars[1]);
7435 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007436 rettv->vval.v_number = -1;
7437 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007438 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439
7440 if (argvars[2].v_type != VAR_UNKNOWN)
7441 {
7442 int error = FALSE;
7443
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007444 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007445 if (error || start_idx >= (int)STRLEN(haystack))
7446 return;
7447 if (start_idx >= 0)
7448 haystack += start_idx;
7449 }
7450
7451 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7452 if (pos != NULL)
7453 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7454}
7455
7456/*
7457 * "string()" function
7458 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007459 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007460f_string(typval_T *argvars, typval_T *rettv)
7461{
7462 char_u *tofree;
7463 char_u numbuf[NUMBUFLEN];
7464
7465 rettv->v_type = VAR_STRING;
7466 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7467 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007468 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007469 if (rettv->vval.v_string != NULL && tofree == NULL)
7470 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7471}
7472
7473/*
7474 * "strlen()" function
7475 */
7476 static void
7477f_strlen(typval_T *argvars, typval_T *rettv)
7478{
7479 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007480 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007481}
7482
7483/*
7484 * "strchars()" function
7485 */
7486 static void
7487f_strchars(typval_T *argvars, typval_T *rettv)
7488{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007489 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007490 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491 varnumber_T len = 0;
7492 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007493
7494 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007495 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007496 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007497 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498 else
7499 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007500 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7501 while (*s != NUL)
7502 {
7503 func_mb_ptr2char_adv(&s);
7504 ++len;
7505 }
7506 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507 }
7508}
7509
7510/*
7511 * "strdisplaywidth()" function
7512 */
7513 static void
7514f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7515{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007516 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 int col = 0;
7518
7519 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007520 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521
7522 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7523}
7524
7525/*
7526 * "strwidth()" function
7527 */
7528 static void
7529f_strwidth(typval_T *argvars, typval_T *rettv)
7530{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007531 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532
Bram Moolenaar13505972019-01-24 15:04:48 +01007533 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007534}
7535
7536/*
7537 * "strcharpart()" function
7538 */
7539 static void
7540f_strcharpart(typval_T *argvars, typval_T *rettv)
7541{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007542 char_u *p;
7543 int nchar;
7544 int nbyte = 0;
7545 int charlen;
7546 int len = 0;
7547 int slen;
7548 int error = FALSE;
7549
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007550 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007551 slen = (int)STRLEN(p);
7552
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007553 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554 if (!error)
7555 {
7556 if (nchar > 0)
7557 while (nchar > 0 && nbyte < slen)
7558 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007559 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007560 --nchar;
7561 }
7562 else
7563 nbyte = nchar;
7564 if (argvars[2].v_type != VAR_UNKNOWN)
7565 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007566 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567 while (charlen > 0 && nbyte + len < slen)
7568 {
7569 int off = nbyte + len;
7570
7571 if (off < 0)
7572 len += 1;
7573 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007574 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575 --charlen;
7576 }
7577 }
7578 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007579 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007580 }
7581
7582 /*
7583 * Only return the overlap between the specified part and the actual
7584 * string.
7585 */
7586 if (nbyte < 0)
7587 {
7588 len += nbyte;
7589 nbyte = 0;
7590 }
7591 else if (nbyte > slen)
7592 nbyte = slen;
7593 if (len < 0)
7594 len = 0;
7595 else if (nbyte + len > slen)
7596 len = slen - nbyte;
7597
7598 rettv->v_type = VAR_STRING;
7599 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600}
7601
7602/*
7603 * "strpart()" function
7604 */
7605 static void
7606f_strpart(typval_T *argvars, typval_T *rettv)
7607{
7608 char_u *p;
7609 int n;
7610 int len;
7611 int slen;
7612 int error = FALSE;
7613
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007614 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007615 slen = (int)STRLEN(p);
7616
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007617 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007618 if (error)
7619 len = 0;
7620 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007621 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007622 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007623 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007624
7625 /*
7626 * Only return the overlap between the specified part and the actual
7627 * string.
7628 */
7629 if (n < 0)
7630 {
7631 len += n;
7632 n = 0;
7633 }
7634 else if (n > slen)
7635 n = slen;
7636 if (len < 0)
7637 len = 0;
7638 else if (n + len > slen)
7639 len = slen - n;
7640
7641 rettv->v_type = VAR_STRING;
7642 rettv->vval.v_string = vim_strnsave(p + n, len);
7643}
7644
7645/*
7646 * "strridx()" function
7647 */
7648 static void
7649f_strridx(typval_T *argvars, typval_T *rettv)
7650{
7651 char_u buf[NUMBUFLEN];
7652 char_u *needle;
7653 char_u *haystack;
7654 char_u *rest;
7655 char_u *lastmatch = NULL;
7656 int haystack_len, end_idx;
7657
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007658 needle = tv_get_string_chk(&argvars[1]);
7659 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007660
7661 rettv->vval.v_number = -1;
7662 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007663 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007664
7665 haystack_len = (int)STRLEN(haystack);
7666 if (argvars[2].v_type != VAR_UNKNOWN)
7667 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007668 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007669 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007671 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 }
7673 else
7674 end_idx = haystack_len;
7675
7676 if (*needle == NUL)
7677 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007678 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007679 lastmatch = haystack + end_idx;
7680 }
7681 else
7682 {
7683 for (rest = haystack; *rest != '\0'; ++rest)
7684 {
7685 rest = (char_u *)strstr((char *)rest, (char *)needle);
7686 if (rest == NULL || rest > haystack + end_idx)
7687 break;
7688 lastmatch = rest;
7689 }
7690 }
7691
7692 if (lastmatch == NULL)
7693 rettv->vval.v_number = -1;
7694 else
7695 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7696}
7697
7698/*
7699 * "strtrans()" function
7700 */
7701 static void
7702f_strtrans(typval_T *argvars, typval_T *rettv)
7703{
7704 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007705 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007706}
7707
7708/*
7709 * "submatch()" function
7710 */
7711 static void
7712f_submatch(typval_T *argvars, typval_T *rettv)
7713{
7714 int error = FALSE;
7715 int no;
7716 int retList = 0;
7717
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007718 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007719 if (error)
7720 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007721 if (no < 0 || no >= NSUBEXP)
7722 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007723 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007724 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007725 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007727 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728 if (error)
7729 return;
7730
7731 if (retList == 0)
7732 {
7733 rettv->v_type = VAR_STRING;
7734 rettv->vval.v_string = reg_submatch(no);
7735 }
7736 else
7737 {
7738 rettv->v_type = VAR_LIST;
7739 rettv->vval.v_list = reg_submatch_list(no);
7740 }
7741}
7742
7743/*
7744 * "substitute()" function
7745 */
7746 static void
7747f_substitute(typval_T *argvars, typval_T *rettv)
7748{
7749 char_u patbuf[NUMBUFLEN];
7750 char_u subbuf[NUMBUFLEN];
7751 char_u flagsbuf[NUMBUFLEN];
7752
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007753 char_u *str = tv_get_string_chk(&argvars[0]);
7754 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007755 char_u *sub = NULL;
7756 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007757 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007758
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007759 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7760 expr = &argvars[2];
7761 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007762 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007763
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007764 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007765 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7766 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767 rettv->vval.v_string = NULL;
7768 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007769 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770}
7771
7772/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007773 * "swapinfo(swap_filename)" function
7774 */
7775 static void
7776f_swapinfo(typval_T *argvars, typval_T *rettv)
7777{
7778 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007779 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007780}
7781
7782/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007783 * "swapname(expr)" function
7784 */
7785 static void
7786f_swapname(typval_T *argvars, typval_T *rettv)
7787{
7788 buf_T *buf;
7789
7790 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007791 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007792 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7793 || buf->b_ml.ml_mfp->mf_fname == NULL)
7794 rettv->vval.v_string = NULL;
7795 else
7796 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7797}
7798
7799/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007800 * "synID(lnum, col, trans)" function
7801 */
7802 static void
7803f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7804{
7805 int id = 0;
7806#ifdef FEAT_SYN_HL
7807 linenr_T lnum;
7808 colnr_T col;
7809 int trans;
7810 int transerr = FALSE;
7811
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007812 lnum = tv_get_lnum(argvars); // -1 on type error
7813 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007814 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007815
7816 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7817 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7818 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7819#endif
7820
7821 rettv->vval.v_number = id;
7822}
7823
7824/*
7825 * "synIDattr(id, what [, mode])" function
7826 */
7827 static void
7828f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7829{
7830 char_u *p = NULL;
7831#ifdef FEAT_SYN_HL
7832 int id;
7833 char_u *what;
7834 char_u *mode;
7835 char_u modebuf[NUMBUFLEN];
7836 int modec;
7837
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007838 id = (int)tv_get_number(&argvars[0]);
7839 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 if (argvars[2].v_type != VAR_UNKNOWN)
7841 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007842 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843 modec = TOLOWER_ASC(mode[0]);
7844 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007845 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 }
7847 else
7848 {
7849#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7850 if (USE_24BIT)
7851 modec = 'g';
7852 else
7853#endif
7854 if (t_colors > 1)
7855 modec = 'c';
7856 else
7857 modec = 't';
7858 }
7859
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007860 switch (TOLOWER_ASC(what[0]))
7861 {
7862 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007863 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007864 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007865 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 p = highlight_has_attr(id, HL_BOLD, modec);
7867 break;
7868
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007869 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007870 p = highlight_color(id, what, modec);
7871 break;
7872
7873 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007874 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007876 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007877 p = highlight_has_attr(id, HL_ITALIC, modec);
7878 break;
7879
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007880 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007881 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882 break;
7883
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007884 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885 p = highlight_has_attr(id, HL_INVERSE, modec);
7886 break;
7887
7888 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007889 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007891 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007892 else if (TOLOWER_ASC(what[1]) == 't' &&
7893 TOLOWER_ASC(what[2]) == 'r')
7894 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007895 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007896 p = highlight_has_attr(id, HL_STANDOUT, modec);
7897 break;
7898
7899 case 'u':
7900 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007901 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007902 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7903 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007904 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007905 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7906 break;
7907 }
7908
7909 if (p != NULL)
7910 p = vim_strsave(p);
7911#endif
7912 rettv->v_type = VAR_STRING;
7913 rettv->vval.v_string = p;
7914}
7915
7916/*
7917 * "synIDtrans(id)" function
7918 */
7919 static void
7920f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7921{
7922 int id;
7923
7924#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007925 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007926
7927 if (id > 0)
7928 id = syn_get_final_id(id);
7929 else
7930#endif
7931 id = 0;
7932
7933 rettv->vval.v_number = id;
7934}
7935
7936/*
7937 * "synconcealed(lnum, col)" function
7938 */
7939 static void
7940f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7941{
7942#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7943 linenr_T lnum;
7944 colnr_T col;
7945 int syntax_flags = 0;
7946 int cchar;
7947 int matchid = 0;
7948 char_u str[NUMBUFLEN];
7949#endif
7950
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007951 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007952
7953#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007954 lnum = tv_get_lnum(argvars); // -1 on type error
7955 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007956
7957 vim_memset(str, NUL, sizeof(str));
7958
7959 if (rettv_list_alloc(rettv) != FAIL)
7960 {
7961 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7962 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7963 && curwin->w_p_cole > 0)
7964 {
7965 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7966 syntax_flags = get_syntax_info(&matchid);
7967
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007968 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007969 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7970 {
7971 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007972 if (cchar == NUL && curwin->w_p_cole == 1)
7973 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007974 if (cchar != NUL)
7975 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976 if (has_mbyte)
7977 (*mb_char2bytes)(cchar, str);
7978 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979 str[0] = cchar;
7980 }
7981 }
7982 }
7983
7984 list_append_number(rettv->vval.v_list,
7985 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007986 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987 list_append_string(rettv->vval.v_list, str, -1);
7988 list_append_number(rettv->vval.v_list, matchid);
7989 }
7990#endif
7991}
7992
7993/*
7994 * "synstack(lnum, col)" function
7995 */
7996 static void
7997f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7998{
7999#ifdef FEAT_SYN_HL
8000 linenr_T lnum;
8001 colnr_T col;
8002 int i;
8003 int id;
8004#endif
8005
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008006 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007
8008#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008009 lnum = tv_get_lnum(argvars); // -1 on type error
8010 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011
8012 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8013 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8014 && rettv_list_alloc(rettv) != FAIL)
8015 {
8016 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8017 for (i = 0; ; ++i)
8018 {
8019 id = syn_get_stack_item(i);
8020 if (id < 0)
8021 break;
8022 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8023 break;
8024 }
8025 }
8026#endif
8027}
8028
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029/*
8030 * "tabpagebuflist()" function
8031 */
8032 static void
8033f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8034{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008035 tabpage_T *tp;
8036 win_T *wp = NULL;
8037
8038 if (argvars[0].v_type == VAR_UNKNOWN)
8039 wp = firstwin;
8040 else
8041 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008042 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008043 if (tp != NULL)
8044 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8045 }
8046 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8047 {
8048 for (; wp != NULL; wp = wp->w_next)
8049 if (list_append_number(rettv->vval.v_list,
8050 wp->w_buffer->b_fnum) == FAIL)
8051 break;
8052 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053}
8054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008055/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008056 * "tagfiles()" function
8057 */
8058 static void
8059f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8060{
8061 char_u *fname;
8062 tagname_T tn;
8063 int first;
8064
8065 if (rettv_list_alloc(rettv) == FAIL)
8066 return;
8067 fname = alloc(MAXPATHL);
8068 if (fname == NULL)
8069 return;
8070
8071 for (first = TRUE; ; first = FALSE)
8072 if (get_tagfname(&tn, first, fname) == FAIL
8073 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8074 break;
8075 tagname_free(&tn);
8076 vim_free(fname);
8077}
8078
8079/*
8080 * "taglist()" function
8081 */
8082 static void
8083f_taglist(typval_T *argvars, typval_T *rettv)
8084{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008085 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 char_u *tag_pattern;
8087
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008088 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008089
8090 rettv->vval.v_number = FALSE;
8091 if (*tag_pattern == NUL)
8092 return;
8093
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008094 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008095 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008097 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008098}
8099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008100#ifdef FEAT_FLOAT
8101/*
8102 * "tan()" function
8103 */
8104 static void
8105f_tan(typval_T *argvars, typval_T *rettv)
8106{
8107 float_T f = 0.0;
8108
8109 rettv->v_type = VAR_FLOAT;
8110 if (get_float_arg(argvars, &f) == OK)
8111 rettv->vval.v_float = tan(f);
8112 else
8113 rettv->vval.v_float = 0.0;
8114}
8115
8116/*
8117 * "tanh()" function
8118 */
8119 static void
8120f_tanh(typval_T *argvars, typval_T *rettv)
8121{
8122 float_T f = 0.0;
8123
8124 rettv->v_type = VAR_FLOAT;
8125 if (get_float_arg(argvars, &f) == OK)
8126 rettv->vval.v_float = tanh(f);
8127 else
8128 rettv->vval.v_float = 0.0;
8129}
8130#endif
8131
8132/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133 * "tolower(string)" function
8134 */
8135 static void
8136f_tolower(typval_T *argvars, typval_T *rettv)
8137{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008138 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008139 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140}
8141
8142/*
8143 * "toupper(string)" function
8144 */
8145 static void
8146f_toupper(typval_T *argvars, typval_T *rettv)
8147{
8148 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008149 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150}
8151
8152/*
8153 * "tr(string, fromstr, tostr)" function
8154 */
8155 static void
8156f_tr(typval_T *argvars, typval_T *rettv)
8157{
8158 char_u *in_str;
8159 char_u *fromstr;
8160 char_u *tostr;
8161 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008162 int inlen;
8163 int fromlen;
8164 int tolen;
8165 int idx;
8166 char_u *cpstr;
8167 int cplen;
8168 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008169 char_u buf[NUMBUFLEN];
8170 char_u buf2[NUMBUFLEN];
8171 garray_T ga;
8172
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008173 in_str = tv_get_string(&argvars[0]);
8174 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8175 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008177 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008178 rettv->v_type = VAR_STRING;
8179 rettv->vval.v_string = NULL;
8180 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008181 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 ga_init2(&ga, (int)sizeof(char), 80);
8183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008185 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 if (STRLEN(fromstr) != STRLEN(tostr))
8187 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008189 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 ga_clear(&ga);
8191 return;
8192 }
8193
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008194 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 while (*in_str != NUL)
8196 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008197 if (has_mbyte)
8198 {
8199 inlen = (*mb_ptr2len)(in_str);
8200 cpstr = in_str;
8201 cplen = inlen;
8202 idx = 0;
8203 for (p = fromstr; *p != NUL; p += fromlen)
8204 {
8205 fromlen = (*mb_ptr2len)(p);
8206 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8207 {
8208 for (p = tostr; *p != NUL; p += tolen)
8209 {
8210 tolen = (*mb_ptr2len)(p);
8211 if (idx-- == 0)
8212 {
8213 cplen = tolen;
8214 cpstr = p;
8215 break;
8216 }
8217 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008218 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008219 goto error;
8220 break;
8221 }
8222 ++idx;
8223 }
8224
8225 if (first && cpstr == in_str)
8226 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008227 // Check that fromstr and tostr have the same number of
8228 // (multi-byte) characters. Done only once when a character
8229 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008230 first = FALSE;
8231 for (p = tostr; *p != NUL; p += tolen)
8232 {
8233 tolen = (*mb_ptr2len)(p);
8234 --idx;
8235 }
8236 if (idx != 0)
8237 goto error;
8238 }
8239
8240 (void)ga_grow(&ga, cplen);
8241 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8242 ga.ga_len += cplen;
8243
8244 in_str += inlen;
8245 }
8246 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008247 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008248 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008249 p = vim_strchr(fromstr, *in_str);
8250 if (p != NULL)
8251 ga_append(&ga, tostr[p - fromstr]);
8252 else
8253 ga_append(&ga, *in_str);
8254 ++in_str;
8255 }
8256 }
8257
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008258 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 (void)ga_grow(&ga, 1);
8260 ga_append(&ga, NUL);
8261
8262 rettv->vval.v_string = ga.ga_data;
8263}
8264
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008265/*
8266 * "trim({expr})" function
8267 */
8268 static void
8269f_trim(typval_T *argvars, typval_T *rettv)
8270{
8271 char_u buf1[NUMBUFLEN];
8272 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008273 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008274 char_u *mask = NULL;
8275 char_u *tail;
8276 char_u *prev;
8277 char_u *p;
8278 int c1;
8279
8280 rettv->v_type = VAR_STRING;
8281 if (head == NULL)
8282 {
8283 rettv->vval.v_string = NULL;
8284 return;
8285 }
8286
8287 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008288 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008289
8290 while (*head != NUL)
8291 {
8292 c1 = PTR2CHAR(head);
8293 if (mask == NULL)
8294 {
8295 if (c1 > ' ' && c1 != 0xa0)
8296 break;
8297 }
8298 else
8299 {
8300 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8301 if (c1 == PTR2CHAR(p))
8302 break;
8303 if (*p == NUL)
8304 break;
8305 }
8306 MB_PTR_ADV(head);
8307 }
8308
8309 for (tail = head + STRLEN(head); tail > head; tail = prev)
8310 {
8311 prev = tail;
8312 MB_PTR_BACK(head, prev);
8313 c1 = PTR2CHAR(prev);
8314 if (mask == NULL)
8315 {
8316 if (c1 > ' ' && c1 != 0xa0)
8317 break;
8318 }
8319 else
8320 {
8321 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8322 if (c1 == PTR2CHAR(p))
8323 break;
8324 if (*p == NUL)
8325 break;
8326 }
8327 }
8328 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8329}
8330
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008331#ifdef FEAT_FLOAT
8332/*
8333 * "trunc({float})" function
8334 */
8335 static void
8336f_trunc(typval_T *argvars, typval_T *rettv)
8337{
8338 float_T f = 0.0;
8339
8340 rettv->v_type = VAR_FLOAT;
8341 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008342 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008343 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8344 else
8345 rettv->vval.v_float = 0.0;
8346}
8347#endif
8348
8349/*
8350 * "type(expr)" function
8351 */
8352 static void
8353f_type(typval_T *argvars, typval_T *rettv)
8354{
8355 int n = -1;
8356
8357 switch (argvars[0].v_type)
8358 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008359 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8360 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008361 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008362 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8363 case VAR_LIST: n = VAR_TYPE_LIST; break;
8364 case VAR_DICT: n = VAR_TYPE_DICT; break;
8365 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8366 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8367 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008368 case VAR_JOB: n = VAR_TYPE_JOB; break;
8369 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008370 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008372 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008373 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374 n = -1;
8375 break;
8376 }
8377 rettv->vval.v_number = n;
8378}
8379
8380/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008381 * "virtcol(string)" function
8382 */
8383 static void
8384f_virtcol(typval_T *argvars, typval_T *rettv)
8385{
8386 colnr_T vcol = 0;
8387 pos_T *fp;
8388 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008389 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390
8391 fp = var2fpos(&argvars[0], FALSE, &fnum);
8392 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8393 && fnum == curbuf->b_fnum)
8394 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008395 // Limit the column to a valid value, getvvcol() doesn't check.
8396 if (fp->col < 0)
8397 fp->col = 0;
8398 else
8399 {
8400 len = (int)STRLEN(ml_get(fp->lnum));
8401 if (fp->col > len)
8402 fp->col = len;
8403 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 getvvcol(curwin, fp, NULL, NULL, &vcol);
8405 ++vcol;
8406 }
8407
8408 rettv->vval.v_number = vcol;
8409}
8410
8411/*
8412 * "visualmode()" function
8413 */
8414 static void
8415f_visualmode(typval_T *argvars, typval_T *rettv)
8416{
8417 char_u str[2];
8418
8419 rettv->v_type = VAR_STRING;
8420 str[0] = curbuf->b_visual_mode_eval;
8421 str[1] = NUL;
8422 rettv->vval.v_string = vim_strsave(str);
8423
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008424 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008425 if (non_zero_arg(&argvars[0]))
8426 curbuf->b_visual_mode_eval = NUL;
8427}
8428
8429/*
8430 * "wildmenumode()" function
8431 */
8432 static void
8433f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8434{
8435#ifdef FEAT_WILDMENU
8436 if (wild_menu_showing)
8437 rettv->vval.v_number = 1;
8438#endif
8439}
8440
8441/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008442 * "windowsversion()" function
8443 */
8444 static void
8445f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8446{
8447 rettv->v_type = VAR_STRING;
8448 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8449}
8450
8451/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008452 * "wordcount()" function
8453 */
8454 static void
8455f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8456{
8457 if (rettv_dict_alloc(rettv) == FAIL)
8458 return;
8459 cursor_pos_info(rettv->vval.v_dict);
8460}
8461
8462/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463 * "xor(expr, expr)" function
8464 */
8465 static void
8466f_xor(typval_T *argvars, typval_T *rettv)
8467{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008468 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8469 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470}
8471
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008472#endif // FEAT_EVAL