blob: cf9c2c45ca54576de737ca16f978b521570e8085 [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);
Bram Moolenaarbb861e22020-06-07 18:16:36 +020097static void f_getreginfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020098static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010099static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +0200100static void f_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
102static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_hlID(typval_T *argvars, typval_T *rettv);
104static void f_hlexists(typval_T *argvars, typval_T *rettv);
105static void f_hostname(typval_T *argvars, typval_T *rettv);
106static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_index(typval_T *argvars, typval_T *rettv);
108static void f_input(typval_T *argvars, typval_T *rettv);
109static void f_inputdialog(typval_T *argvars, typval_T *rettv);
110static void f_inputlist(typval_T *argvars, typval_T *rettv);
111static void f_inputrestore(typval_T *argvars, typval_T *rettv);
112static void f_inputsave(typval_T *argvars, typval_T *rettv);
113static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100114static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200115static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200116static void f_islocked(typval_T *argvars, typval_T *rettv);
117#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200118static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_isnan(typval_T *argvars, typval_T *rettv);
120#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
122static void f_len(typval_T *argvars, typval_T *rettv);
123static void f_libcall(typval_T *argvars, typval_T *rettv);
124static void f_libcallnr(typval_T *argvars, typval_T *rettv);
125static void f_line(typval_T *argvars, typval_T *rettv);
126static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127#ifdef FEAT_FLOAT
128static void f_log(typval_T *argvars, typval_T *rettv);
129static void f_log10(typval_T *argvars, typval_T *rettv);
130#endif
131#ifdef FEAT_LUA
132static void f_luaeval(typval_T *argvars, typval_T *rettv);
133#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200134static void f_maparg(typval_T *argvars, typval_T *rettv);
135static void f_mapcheck(typval_T *argvars, typval_T *rettv);
136static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_matchend(typval_T *argvars, typval_T *rettv);
138static void f_matchlist(typval_T *argvars, typval_T *rettv);
139static void f_matchstr(typval_T *argvars, typval_T *rettv);
140static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
141static void f_max(typval_T *argvars, typval_T *rettv);
142static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200143#ifdef FEAT_MZSCHEME
144static void f_mzeval(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
147static void f_nr2char(typval_T *argvars, typval_T *rettv);
148static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200149#ifdef FEAT_PERL
150static void f_perleval(typval_T *argvars, typval_T *rettv);
151#endif
152#ifdef FEAT_FLOAT
153static void f_pow(typval_T *argvars, typval_T *rettv);
154#endif
155static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
156static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200157static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200158static void f_pumvisible(typval_T *argvars, typval_T *rettv);
159#ifdef FEAT_PYTHON3
160static void f_py3eval(typval_T *argvars, typval_T *rettv);
161#endif
162#ifdef FEAT_PYTHON
163static void f_pyeval(typval_T *argvars, typval_T *rettv);
164#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100165#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
166static void f_pyxeval(typval_T *argvars, typval_T *rettv);
167#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100168static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100169static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200171static void f_reg_executing(typval_T *argvars, typval_T *rettv);
172static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_rename(typval_T *argvars, typval_T *rettv);
174static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175#ifdef FEAT_FLOAT
176static void f_round(typval_T *argvars, typval_T *rettv);
177#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100178#ifdef FEAT_RUBY
179static void f_rubyeval(typval_T *argvars, typval_T *rettv);
180#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200181static void f_screenattr(typval_T *argvars, typval_T *rettv);
182static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100183static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200184static void f_screencol(typval_T *argvars, typval_T *rettv);
185static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100186static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_search(typval_T *argvars, typval_T *rettv);
188static void f_searchdecl(typval_T *argvars, typval_T *rettv);
189static void f_searchpair(typval_T *argvars, typval_T *rettv);
190static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
191static void f_searchpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200193static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100197static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198#ifdef FEAT_CRYPT
199static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200200#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_shellescape(typval_T *argvars, typval_T *rettv);
202static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200203#ifdef FEAT_FLOAT
204static void f_sin(typval_T *argvars, typval_T *rettv);
205static void f_sinh(typval_T *argvars, typval_T *rettv);
206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_soundfold(typval_T *argvars, typval_T *rettv);
208static void f_spellbadword(typval_T *argvars, typval_T *rettv);
209static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
210static void f_split(typval_T *argvars, typval_T *rettv);
211#ifdef FEAT_FLOAT
212static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100213#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100214static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100215#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200216static void f_str2float(typval_T *argvars, typval_T *rettv);
217#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200218static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219static void f_str2nr(typval_T *argvars, typval_T *rettv);
220static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_strgetchar(typval_T *argvars, typval_T *rettv);
222static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200223static void f_strlen(typval_T *argvars, typval_T *rettv);
224static void f_strcharpart(typval_T *argvars, typval_T *rettv);
225static void f_strpart(typval_T *argvars, typval_T *rettv);
226static void f_strridx(typval_T *argvars, typval_T *rettv);
227static void f_strtrans(typval_T *argvars, typval_T *rettv);
228static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
229static void f_strwidth(typval_T *argvars, typval_T *rettv);
230static void f_submatch(typval_T *argvars, typval_T *rettv);
231static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200232static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200233static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_synID(typval_T *argvars, typval_T *rettv);
235static void f_synIDattr(typval_T *argvars, typval_T *rettv);
236static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
237static void f_synstack(typval_T *argvars, typval_T *rettv);
238static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200239static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_taglist(typval_T *argvars, typval_T *rettv);
241static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200242#ifdef FEAT_FLOAT
243static void f_tan(typval_T *argvars, typval_T *rettv);
244static void f_tanh(typval_T *argvars, typval_T *rettv);
245#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_tolower(typval_T *argvars, typval_T *rettv);
247static void f_toupper(typval_T *argvars, typval_T *rettv);
248static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100249static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200250#ifdef FEAT_FLOAT
251static void f_trunc(typval_T *argvars, typval_T *rettv);
252#endif
253static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200254static void f_virtcol(typval_T *argvars, typval_T *rettv);
255static void f_visualmode(typval_T *argvars, typval_T *rettv);
256static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100257static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200258static void f_wordcount(typval_T *argvars, typval_T *rettv);
259static void f_xor(typval_T *argvars, typval_T *rettv);
260
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100261
Bram Moolenaar94738d82020-10-21 14:25:07 +0200262/*
263 * Functions that check the argument type of a builtin function.
264 * Each function returns FAIL and gives an error message if the type is wrong.
265 */
266
267// Context passed to an arg_ function.
268typedef struct {
Bram Moolenaarca174532020-10-21 16:42:22 +0200269 int arg_count; // actual argument count
270 type_T **arg_types; // list of argument types
271 int arg_idx; // current argument index (first arg is zero)
Bram Moolenaar94738d82020-10-21 14:25:07 +0200272} argcontext_T;
273
274// A function to check one argument type. The first argument is the type to
275// check. If needed, other argument types can be obtained with the context.
276// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
277typedef int (*argcheck_T)(type_T *, argcontext_T *);
278
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100279/*
280 * Check "type" is a float or a number.
281 */
Bram Moolenaar94738d82020-10-21 14:25:07 +0200282 static int
283arg_float_or_nr(type_T *type, argcontext_T *context)
284{
Bram Moolenaarca174532020-10-21 16:42:22 +0200285 if (type->tt_type == VAR_ANY
286 || type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER)
Bram Moolenaar94738d82020-10-21 14:25:07 +0200287 return OK;
288 arg_type_mismatch(&t_number, type, context->arg_idx + 1);
289 return FAIL;
290}
291
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100292/*
293 * Check "type" is a number.
294 */
Bram Moolenaarca174532020-10-21 16:42:22 +0200295 static int
296arg_number(type_T *type, argcontext_T *context)
297{
Bram Moolenaar193f6202020-11-16 20:08:35 +0100298 return check_arg_type(&t_number, type, context->arg_idx + 1);
Bram Moolenaarca174532020-10-21 16:42:22 +0200299}
300
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100301/*
302 * Check "type" is a string.
303 */
304 static int
305arg_string(type_T *type, argcontext_T *context)
306{
Bram Moolenaar193f6202020-11-16 20:08:35 +0100307 return check_arg_type(&t_string, type, context->arg_idx + 1);
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100308}
309
310/*
311 * Check "type" is a list or a blob.
312 */
Bram Moolenaarca174532020-10-21 16:42:22 +0200313 static int
314arg_list_or_blob(type_T *type, argcontext_T *context)
315{
316 if (type->tt_type == VAR_ANY
317 || type->tt_type == VAR_LIST || type->tt_type == VAR_BLOB)
318 return OK;
319 arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
320 return FAIL;
321}
322
323/*
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100324 * Check "type" is a list or a dict.
325 */
326 static int
327arg_list_or_dict(type_T *type, argcontext_T *context)
328{
329 if (type->tt_type == VAR_ANY
330 || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
331 return OK;
332 arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
333 return FAIL;
334}
335
336/*
337 * Check "type" is the same type as the previous argument
338 * Must not be used for the first argcheck_T entry.
339 */
340 static int
341arg_same_as_prev(type_T *type, argcontext_T *context)
342{
343 type_T *prev_type = context->arg_types[context->arg_idx - 1];
344
Bram Moolenaar193f6202020-11-16 20:08:35 +0100345 return check_arg_type(prev_type, type, context->arg_idx + 1);
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100346}
347
348/*
349 * Check "type" is an item of the list or blob of the previous arg.
Bram Moolenaarca174532020-10-21 16:42:22 +0200350 * Must not be used for the first argcheck_T entry.
351 */
352 static int
353arg_item_of_prev(type_T *type, argcontext_T *context)
354{
355 type_T *prev_type = context->arg_types[context->arg_idx - 1];
356 type_T *expected;
357
358 if (prev_type->tt_type == VAR_LIST)
359 expected = prev_type->tt_member;
360 else if (prev_type->tt_type == VAR_BLOB)
361 expected = &t_number;
362 else
363 // probably VAR_ANY, can't check
364 return OK;
365
Bram Moolenaar193f6202020-11-16 20:08:35 +0100366 return check_arg_type(expected, type, context->arg_idx + 1);
Bram Moolenaarca174532020-10-21 16:42:22 +0200367}
368
Bram Moolenaar94738d82020-10-21 14:25:07 +0200369/*
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100370 * Check "type" which is the third argument of extend().
371 */
372 static int
373arg_extend3(type_T *type, argcontext_T *context)
374{
375 type_T *first_type = context->arg_types[context->arg_idx - 2];
376
377 if (first_type->tt_type == VAR_LIST)
378 return arg_number(type, context);
379 if (first_type->tt_type == VAR_DICT)
380 return arg_string(type, context);
381 return OK;
382}
383
384
385/*
Bram Moolenaar94738d82020-10-21 14:25:07 +0200386 * Lists of functions that check the argument types of a builtin function.
387 */
388argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100389argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
390argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
Bram Moolenaarca174532020-10-21 16:42:22 +0200391argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
Bram Moolenaar94738d82020-10-21 14:25:07 +0200392
393/*
394 * Functions that return the return type of a builtin function.
Bram Moolenaara1224cb2020-10-22 12:31:49 +0200395 * Note that "argtypes" is NULL if "argcount" is zero.
Bram Moolenaar94738d82020-10-21 14:25:07 +0200396 */
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100397 static type_T *
398ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
399{
400 return &t_void;
401}
402 static type_T *
403ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
404{
405 return &t_any;
406}
407 static type_T *
Bram Moolenaar403dc312020-10-17 19:29:51 +0200408ret_bool(int argcount UNUSED, type_T **argtypes UNUSED)
409{
410 return &t_bool;
411}
412 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100413ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
414{
415 return &t_number;
416}
417 static type_T *
418ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
419{
420 return &t_float;
421}
422 static type_T *
423ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
424{
425 return &t_string;
426}
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200427 static type_T *
428ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100429{
430 return &t_list_any;
431}
432 static type_T *
433ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
434{
435 return &t_list_number;
436}
437 static type_T *
438ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
439{
440 return &t_list_string;
441}
442 static type_T *
443ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
444{
445 return &t_list_dict_any;
446}
447 static type_T *
448ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
449{
450 return &t_dict_any;
451}
452 static type_T *
453ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
454{
455 return &t_dict_number;
456}
457 static type_T *
458ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
459{
460 return &t_dict_string;
461}
462 static type_T *
463ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
464{
465 return &t_blob;
466}
467 static type_T *
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200468ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100469{
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200470 return &t_func_any;
471}
472 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100473ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
474{
475 return &t_channel;
476}
477 static type_T *
478ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
479{
480 return &t_job;
481}
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200482 static type_T *
483ret_first_arg(int argcount, type_T **argtypes)
484{
485 if (argcount > 0)
486 return argtypes[0];
487 return &t_void;
488}
Bram Moolenaarea696852020-11-09 18:31:39 +0100489// for map(): returns first argument but item type may differ
490 static type_T *
491ret_first_cont(int argcount UNUSED, type_T **argtypes)
492{
493 if (argtypes[0]->tt_type == VAR_LIST)
494 return &t_list_any;
495 if (argtypes[0]->tt_type == VAR_DICT)
496 return &t_dict_any;
497 if (argtypes[0]->tt_type == VAR_BLOB)
498 return argtypes[0];
499 return &t_any;
500}
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200501
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200502/*
503 * Used for getqflist(): returns list if there is no argument, dict if there is
504 * one.
505 */
506 static type_T *
507ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
508{
509 if (argcount > 0)
510 return &t_dict_any;
511 return &t_list_dict_any;
512}
513
514/*
515 * Used for getloclist(): returns list if there is one argument, dict if there
516 * are two.
517 */
518 static type_T *
519ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
520{
521 if (argcount > 1)
522 return &t_dict_any;
523 return &t_list_dict_any;
524}
525
Bram Moolenaar846178a2020-07-05 17:04:13 +0200526 static type_T *
527ret_argv(int argcount, type_T **argtypes UNUSED)
528{
529 // argv() returns list of strings
530 if (argcount == 0)
531 return &t_list_string;
532
533 // argv(0) returns a string, but argv(-1] returns a list
534 return &t_any;
535}
536
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200537 static type_T *
538ret_remove(int argcount UNUSED, type_T **argtypes)
539{
Bram Moolenaar5e654232020-09-16 15:22:00 +0200540 if (argtypes != NULL)
541 {
542 if (argtypes[0]->tt_type == VAR_LIST
543 || argtypes[0]->tt_type == VAR_DICT)
544 return argtypes[0]->tt_member;
545 if (argtypes[0]->tt_type == VAR_BLOB)
546 return &t_number;
547 }
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200548 return &t_any;
549}
550
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200551 static type_T *
552ret_getreg(int argcount, type_T **argtypes UNUSED)
553{
554 // Assume that if the third argument is passed it's non-zero
555 if (argcount == 3)
556 return &t_list_string;
557 return &t_string;
558}
559
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200560 static type_T *
561ret_maparg(int argcount, type_T **argtypes UNUSED)
562{
563 // Assume that if the fourth argument is passed it's non-zero
564 if (argcount == 4)
565 return &t_dict_any;
566 return &t_string;
567}
568
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100569static type_T *ret_f_function(int argcount, type_T **argtypes);
570
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200571/*
572 * Array with names and number of arguments of all internal functions
573 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
574 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200575typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200576{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200577 char *f_name; // function name
578 char f_min_argc; // minimal number of arguments
579 char f_max_argc; // maximal number of arguments
580 char f_argtype; // for method: FEARG_ values
Bram Moolenaar94738d82020-10-21 14:25:07 +0200581 argcheck_T *f_argcheck; // list of functions to check argument types
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100582 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
583 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200584 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200585 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200586} funcentry_T;
587
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200588// values for f_argtype; zero means it cannot be used as a method
589#define FEARG_1 1 // base is the first argument
590#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200591#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200592#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200593#define FEARG_LAST 9 // base is the last argument
594
Bram Moolenaar15c47602020-03-26 22:16:48 +0100595#ifdef FEAT_FLOAT
596# define FLOAT_FUNC(name) name
597#else
598# define FLOAT_FUNC(name) NULL
599#endif
600#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
601# define MATH_FUNC(name) name
602#else
603# define MATH_FUNC(name) NULL
604#endif
605#ifdef FEAT_TIMERS
606# define TIMER_FUNC(name) name
607#else
608# define TIMER_FUNC(name) NULL
609#endif
610#ifdef FEAT_JOB_CHANNEL
611# define JOB_FUNC(name) name
612#else
613# define JOB_FUNC(name) NULL
614#endif
615#ifdef FEAT_PROP_POPUP
616# define PROP_FUNC(name) name
617#else
618# define PROP_FUNC(name) NULL
619#endif
620#ifdef FEAT_SIGNS
621# define SIGN_FUNC(name) name
622#else
623# define SIGN_FUNC(name) NULL
624#endif
625#ifdef FEAT_SOUND
626# define SOUND_FUNC(name) name
627#else
628# define SOUND_FUNC(name) NULL
629#endif
630#ifdef FEAT_TERMINAL
631# define TERM_FUNC(name) name
632#else
633# define TERM_FUNC(name) NULL
634#endif
635
Bram Moolenaarac92e252019-08-03 21:58:38 +0200636static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637{
Bram Moolenaar94738d82020-10-21 14:25:07 +0200638 {"abs", 1, 1, FEARG_1, arg1_float_or_nr,
639 ret_any, FLOAT_FUNC(f_abs)},
640 {"acos", 1, 1, FEARG_1, NULL,
641 ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100642 {"add", 2, 2, FEARG_1, NULL /* arg2_listblob_item */,
Bram Moolenaar94738d82020-10-21 14:25:07 +0200643 ret_first_arg, f_add},
644 {"and", 2, 2, FEARG_1, NULL,
645 ret_number, f_and},
646 {"append", 2, 2, FEARG_2, NULL,
647 ret_number, f_append},
648 {"appendbufline", 3, 3, FEARG_3, NULL,
649 ret_number, f_appendbufline},
650 {"argc", 0, 1, 0, NULL,
651 ret_number, f_argc},
652 {"argidx", 0, 0, 0, NULL,
653 ret_number, f_argidx},
654 {"arglistid", 0, 2, 0, NULL,
655 ret_number, f_arglistid},
656 {"argv", 0, 2, 0, NULL,
657 ret_argv, f_argv},
658 {"asin", 1, 1, FEARG_1, NULL,
659 ret_float, FLOAT_FUNC(f_asin)},
660 {"assert_beeps", 1, 2, FEARG_1, NULL,
661 ret_number, f_assert_beeps},
662 {"assert_equal", 2, 3, FEARG_2, NULL,
663 ret_number, f_assert_equal},
664 {"assert_equalfile", 2, 3, FEARG_1, NULL,
665 ret_number, f_assert_equalfile},
666 {"assert_exception", 1, 2, 0, NULL,
667 ret_number, f_assert_exception},
668 {"assert_fails", 1, 5, FEARG_1, NULL,
669 ret_number, f_assert_fails},
670 {"assert_false", 1, 2, FEARG_1, NULL,
671 ret_number, f_assert_false},
672 {"assert_inrange", 3, 4, FEARG_3, NULL,
673 ret_number, f_assert_inrange},
674 {"assert_match", 2, 3, FEARG_2, NULL,
675 ret_number, f_assert_match},
676 {"assert_notequal", 2, 3, FEARG_2, NULL,
677 ret_number, f_assert_notequal},
678 {"assert_notmatch", 2, 3, FEARG_2, NULL,
679 ret_number, f_assert_notmatch},
680 {"assert_report", 1, 1, FEARG_1, NULL,
681 ret_number, f_assert_report},
682 {"assert_true", 1, 2, FEARG_1, NULL,
683 ret_number, f_assert_true},
684 {"atan", 1, 1, FEARG_1, NULL,
685 ret_float, FLOAT_FUNC(f_atan)},
686 {"atan2", 2, 2, FEARG_1, NULL,
687 ret_float, FLOAT_FUNC(f_atan2)},
688 {"balloon_gettext", 0, 0, 0, NULL,
689 ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100690#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100691 f_balloon_gettext
692#else
693 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100694#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100695 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200696 {"balloon_show", 1, 1, FEARG_1, NULL,
697 ret_void,
Bram Moolenaar15c47602020-03-26 22:16:48 +0100698#ifdef FEAT_BEVAL
699 f_balloon_show
700#else
701 NULL
702#endif
703 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200704 {"balloon_split", 1, 1, FEARG_1, NULL,
705 ret_list_string,
Bram Moolenaar15c47602020-03-26 22:16:48 +0100706#if defined(FEAT_BEVAL_TERM)
707 f_balloon_split
708#else
709 NULL
710#endif
711 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200712 {"browse", 4, 4, 0, NULL,
713 ret_string, f_browse},
714 {"browsedir", 2, 2, 0, NULL,
715 ret_string, f_browsedir},
716 {"bufadd", 1, 1, FEARG_1, NULL,
717 ret_number, f_bufadd},
718 {"bufexists", 1, 1, FEARG_1, NULL,
719 ret_number, f_bufexists},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +0200720 {"buffer_exists", 1, 1, FEARG_1, NULL, // obsolete
721 ret_number, f_bufexists},
722 {"buffer_name", 0, 1, FEARG_1, NULL, // obsolete
723 ret_string, f_bufname},
724 {"buffer_number", 0, 1, FEARG_1, NULL, // obsolete
725 ret_number, f_bufnr},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200726 {"buflisted", 1, 1, FEARG_1, NULL,
727 ret_number, f_buflisted},
728 {"bufload", 1, 1, FEARG_1, NULL,
729 ret_void, f_bufload},
730 {"bufloaded", 1, 1, FEARG_1, NULL,
731 ret_number, f_bufloaded},
732 {"bufname", 0, 1, FEARG_1, NULL,
733 ret_string, f_bufname},
734 {"bufnr", 0, 2, FEARG_1, NULL,
735 ret_number, f_bufnr},
736 {"bufwinid", 1, 1, FEARG_1, NULL,
737 ret_number, f_bufwinid},
738 {"bufwinnr", 1, 1, FEARG_1, NULL,
739 ret_number, f_bufwinnr},
740 {"byte2line", 1, 1, FEARG_1, NULL,
741 ret_number, f_byte2line},
742 {"byteidx", 2, 2, FEARG_1, NULL,
743 ret_number, f_byteidx},
744 {"byteidxcomp", 2, 2, FEARG_1, NULL,
745 ret_number, f_byteidxcomp},
746 {"call", 2, 3, FEARG_1, NULL,
747 ret_any, f_call},
748 {"ceil", 1, 1, FEARG_1, NULL,
749 ret_float, FLOAT_FUNC(f_ceil)},
750 {"ch_canread", 1, 1, FEARG_1, NULL,
751 ret_number, JOB_FUNC(f_ch_canread)},
752 {"ch_close", 1, 1, FEARG_1, NULL,
753 ret_void, JOB_FUNC(f_ch_close)},
754 {"ch_close_in", 1, 1, FEARG_1, NULL,
755 ret_void, JOB_FUNC(f_ch_close_in)},
756 {"ch_evalexpr", 2, 3, FEARG_1, NULL,
757 ret_any, JOB_FUNC(f_ch_evalexpr)},
758 {"ch_evalraw", 2, 3, FEARG_1, NULL,
759 ret_any, JOB_FUNC(f_ch_evalraw)},
760 {"ch_getbufnr", 2, 2, FEARG_1, NULL,
761 ret_number, JOB_FUNC(f_ch_getbufnr)},
762 {"ch_getjob", 1, 1, FEARG_1, NULL,
763 ret_job, JOB_FUNC(f_ch_getjob)},
764 {"ch_info", 1, 1, FEARG_1, NULL,
765 ret_dict_any, JOB_FUNC(f_ch_info)},
766 {"ch_log", 1, 2, FEARG_1, NULL,
767 ret_void, JOB_FUNC(f_ch_log)},
768 {"ch_logfile", 1, 2, FEARG_1, NULL,
769 ret_void, JOB_FUNC(f_ch_logfile)},
770 {"ch_open", 1, 2, FEARG_1, NULL,
771 ret_channel, JOB_FUNC(f_ch_open)},
772 {"ch_read", 1, 2, FEARG_1, NULL,
773 ret_string, JOB_FUNC(f_ch_read)},
774 {"ch_readblob", 1, 2, FEARG_1, NULL,
775 ret_blob, JOB_FUNC(f_ch_readblob)},
776 {"ch_readraw", 1, 2, FEARG_1, NULL,
777 ret_string, JOB_FUNC(f_ch_readraw)},
778 {"ch_sendexpr", 2, 3, FEARG_1, NULL,
779 ret_void, JOB_FUNC(f_ch_sendexpr)},
780 {"ch_sendraw", 2, 3, FEARG_1, NULL,
781 ret_void, JOB_FUNC(f_ch_sendraw)},
782 {"ch_setoptions", 2, 2, FEARG_1, NULL,
783 ret_void, JOB_FUNC(f_ch_setoptions)},
784 {"ch_status", 1, 2, FEARG_1, NULL,
785 ret_string, JOB_FUNC(f_ch_status)},
786 {"changenr", 0, 0, 0, NULL,
787 ret_number, f_changenr},
788 {"char2nr", 1, 2, FEARG_1, NULL,
789 ret_number, f_char2nr},
790 {"charclass", 1, 1, FEARG_1, NULL,
791 ret_number, f_charclass},
792 {"chdir", 1, 1, FEARG_1, NULL,
793 ret_string, f_chdir},
794 {"cindent", 1, 1, FEARG_1, NULL,
795 ret_number, f_cindent},
796 {"clearmatches", 0, 1, FEARG_1, NULL,
797 ret_void, f_clearmatches},
798 {"col", 1, 1, FEARG_1, NULL,
799 ret_number, f_col},
800 {"complete", 2, 2, FEARG_2, NULL,
801 ret_void, f_complete},
802 {"complete_add", 1, 1, FEARG_1, NULL,
803 ret_number, f_complete_add},
804 {"complete_check", 0, 0, 0, NULL,
805 ret_number, f_complete_check},
806 {"complete_info", 0, 1, FEARG_1, NULL,
807 ret_dict_any, f_complete_info},
808 {"confirm", 1, 4, FEARG_1, NULL,
809 ret_number, f_confirm},
810 {"copy", 1, 1, FEARG_1, NULL,
811 ret_first_arg, f_copy},
812 {"cos", 1, 1, FEARG_1, NULL,
813 ret_float, FLOAT_FUNC(f_cos)},
814 {"cosh", 1, 1, FEARG_1, NULL,
815 ret_float, FLOAT_FUNC(f_cosh)},
816 {"count", 2, 4, FEARG_1, NULL,
817 ret_number, f_count},
818 {"cscope_connection",0,3, 0, NULL,
819 ret_number, f_cscope_connection},
820 {"cursor", 1, 3, FEARG_1, NULL,
821 ret_number, f_cursor},
822 {"debugbreak", 1, 1, FEARG_1, NULL,
823 ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100824#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100825 f_debugbreak
826#else
827 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200828#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100829 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200830 {"deepcopy", 1, 2, FEARG_1, NULL,
831 ret_first_arg, f_deepcopy},
832 {"delete", 1, 2, FEARG_1, NULL,
833 ret_number, f_delete},
834 {"deletebufline", 2, 3, FEARG_1, NULL,
835 ret_number, f_deletebufline},
836 {"did_filetype", 0, 0, 0, NULL,
837 ret_number, f_did_filetype},
838 {"diff_filler", 1, 1, FEARG_1, NULL,
839 ret_number, f_diff_filler},
840 {"diff_hlID", 2, 2, FEARG_1, NULL,
841 ret_number, f_diff_hlID},
842 {"echoraw", 1, 1, FEARG_1, NULL,
843 ret_number, f_echoraw},
844 {"empty", 1, 1, FEARG_1, NULL,
845 ret_number, f_empty},
846 {"environ", 0, 0, 0, NULL,
847 ret_dict_string, f_environ},
848 {"escape", 2, 2, FEARG_1, NULL,
849 ret_string, f_escape},
850 {"eval", 1, 1, FEARG_1, NULL,
851 ret_any, f_eval},
852 {"eventhandler", 0, 0, 0, NULL,
853 ret_number, f_eventhandler},
854 {"executable", 1, 1, FEARG_1, NULL,
855 ret_number, f_executable},
856 {"execute", 1, 2, FEARG_1, NULL,
857 ret_string, f_execute},
858 {"exepath", 1, 1, FEARG_1, NULL,
859 ret_string, f_exepath},
860 {"exists", 1, 1, FEARG_1, NULL,
861 ret_number, f_exists},
862 {"exp", 1, 1, FEARG_1, NULL,
863 ret_float, FLOAT_FUNC(f_exp)},
864 {"expand", 1, 3, FEARG_1, NULL,
865 ret_any, f_expand},
866 {"expandcmd", 1, 1, FEARG_1, NULL,
867 ret_string, f_expandcmd},
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100868 {"extend", 2, 3, FEARG_1, arg23_extend,
Bram Moolenaar94738d82020-10-21 14:25:07 +0200869 ret_first_arg, f_extend},
870 {"feedkeys", 1, 2, FEARG_1, NULL,
871 ret_void, f_feedkeys},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +0200872 {"file_readable", 1, 1, FEARG_1, NULL, // obsolete
873 ret_number, f_filereadable},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200874 {"filereadable", 1, 1, FEARG_1, NULL,
875 ret_number, f_filereadable},
876 {"filewritable", 1, 1, FEARG_1, NULL,
877 ret_number, f_filewritable},
878 {"filter", 2, 2, FEARG_1, NULL,
879 ret_first_arg, f_filter},
880 {"finddir", 1, 3, FEARG_1, NULL,
881 ret_string, f_finddir},
882 {"findfile", 1, 3, FEARG_1, NULL,
883 ret_string, f_findfile},
884 {"flatten", 1, 2, FEARG_1, NULL,
885 ret_list_any, f_flatten},
886 {"float2nr", 1, 1, FEARG_1, NULL,
887 ret_number, FLOAT_FUNC(f_float2nr)},
888 {"floor", 1, 1, FEARG_1, NULL,
889 ret_float, FLOAT_FUNC(f_floor)},
890 {"fmod", 2, 2, FEARG_1, NULL,
891 ret_float, FLOAT_FUNC(f_fmod)},
892 {"fnameescape", 1, 1, FEARG_1, NULL,
893 ret_string, f_fnameescape},
894 {"fnamemodify", 2, 2, FEARG_1, NULL,
895 ret_string, f_fnamemodify},
896 {"foldclosed", 1, 1, FEARG_1, NULL,
897 ret_number, f_foldclosed},
898 {"foldclosedend", 1, 1, FEARG_1, NULL,
899 ret_number, f_foldclosedend},
900 {"foldlevel", 1, 1, FEARG_1, NULL,
901 ret_number, f_foldlevel},
902 {"foldtext", 0, 0, 0, NULL,
903 ret_string, f_foldtext},
904 {"foldtextresult", 1, 1, FEARG_1, NULL,
905 ret_string, f_foldtextresult},
906 {"foreground", 0, 0, 0, NULL,
907 ret_void, f_foreground},
908 {"funcref", 1, 3, FEARG_1, NULL,
909 ret_func_any, f_funcref},
910 {"function", 1, 3, FEARG_1, NULL,
911 ret_f_function, f_function},
912 {"garbagecollect", 0, 1, 0, NULL,
913 ret_void, f_garbagecollect},
914 {"get", 2, 3, FEARG_1, NULL,
915 ret_any, f_get},
916 {"getbufinfo", 0, 1, FEARG_1, NULL,
917 ret_list_dict_any, f_getbufinfo},
918 {"getbufline", 2, 3, FEARG_1, NULL,
919 ret_list_string, f_getbufline},
920 {"getbufvar", 2, 3, FEARG_1, NULL,
921 ret_any, f_getbufvar},
922 {"getchangelist", 0, 1, FEARG_1, NULL,
923 ret_list_any, f_getchangelist},
924 {"getchar", 0, 1, 0, NULL,
925 ret_number, f_getchar},
926 {"getcharmod", 0, 0, 0, NULL,
927 ret_number, f_getcharmod},
928 {"getcharsearch", 0, 0, 0, NULL,
929 ret_dict_any, f_getcharsearch},
930 {"getcmdline", 0, 0, 0, NULL,
931 ret_string, f_getcmdline},
932 {"getcmdpos", 0, 0, 0, NULL,
933 ret_number, f_getcmdpos},
934 {"getcmdtype", 0, 0, 0, NULL,
935 ret_string, f_getcmdtype},
936 {"getcmdwintype", 0, 0, 0, NULL,
937 ret_string, f_getcmdwintype},
938 {"getcompletion", 2, 3, FEARG_1, NULL,
939 ret_list_string, f_getcompletion},
940 {"getcurpos", 0, 1, FEARG_1, NULL,
941 ret_list_number, f_getcurpos},
942 {"getcwd", 0, 2, FEARG_1, NULL,
943 ret_string, f_getcwd},
944 {"getenv", 1, 1, FEARG_1, NULL,
945 ret_string, f_getenv},
946 {"getfontname", 0, 1, 0, NULL,
947 ret_string, f_getfontname},
948 {"getfperm", 1, 1, FEARG_1, NULL,
949 ret_string, f_getfperm},
950 {"getfsize", 1, 1, FEARG_1, NULL,
951 ret_number, f_getfsize},
952 {"getftime", 1, 1, FEARG_1, NULL,
953 ret_number, f_getftime},
954 {"getftype", 1, 1, FEARG_1, NULL,
955 ret_string, f_getftype},
956 {"getimstatus", 0, 0, 0, NULL,
957 ret_number, f_getimstatus},
958 {"getjumplist", 0, 2, FEARG_1, NULL,
959 ret_list_any, f_getjumplist},
960 {"getline", 1, 2, FEARG_1, NULL,
961 ret_f_getline, f_getline},
962 {"getloclist", 1, 2, 0, NULL,
963 ret_list_or_dict_1, f_getloclist},
964 {"getmarklist", 0, 1, FEARG_1, NULL,
965 ret_list_dict_any, f_getmarklist},
966 {"getmatches", 0, 1, 0, NULL,
967 ret_list_dict_any, f_getmatches},
968 {"getmousepos", 0, 0, 0, NULL,
969 ret_dict_number, f_getmousepos},
970 {"getpid", 0, 0, 0, NULL,
971 ret_number, f_getpid},
972 {"getpos", 1, 1, FEARG_1, NULL,
973 ret_list_number, f_getpos},
974 {"getqflist", 0, 1, 0, NULL,
975 ret_list_or_dict_0, f_getqflist},
976 {"getreg", 0, 3, FEARG_1, NULL,
977 ret_getreg, f_getreg},
978 {"getreginfo", 0, 1, FEARG_1, NULL,
979 ret_dict_any, f_getreginfo},
980 {"getregtype", 0, 1, FEARG_1, NULL,
981 ret_string, f_getregtype},
982 {"gettabinfo", 0, 1, FEARG_1, NULL,
983 ret_list_dict_any, f_gettabinfo},
984 {"gettabvar", 2, 3, FEARG_1, NULL,
985 ret_any, f_gettabvar},
986 {"gettabwinvar", 3, 4, FEARG_1, NULL,
987 ret_any, f_gettabwinvar},
988 {"gettagstack", 0, 1, FEARG_1, NULL,
989 ret_dict_any, f_gettagstack},
990 {"gettext", 1, 1, FEARG_1, NULL,
991 ret_string, f_gettext},
992 {"getwininfo", 0, 1, FEARG_1, NULL,
993 ret_list_dict_any, f_getwininfo},
994 {"getwinpos", 0, 1, FEARG_1, NULL,
995 ret_list_number, f_getwinpos},
996 {"getwinposx", 0, 0, 0, NULL,
997 ret_number, f_getwinposx},
998 {"getwinposy", 0, 0, 0, NULL,
999 ret_number, f_getwinposy},
1000 {"getwinvar", 2, 3, FEARG_1, NULL,
1001 ret_any, f_getwinvar},
1002 {"glob", 1, 4, FEARG_1, NULL,
1003 ret_any, f_glob},
1004 {"glob2regpat", 1, 1, FEARG_1, NULL,
1005 ret_string, f_glob2regpat},
1006 {"globpath", 2, 5, FEARG_2, NULL,
1007 ret_any, f_globpath},
1008 {"has", 1, 2, 0, NULL,
1009 ret_number, f_has},
1010 {"has_key", 2, 2, FEARG_1, NULL,
1011 ret_number, f_has_key},
1012 {"haslocaldir", 0, 2, FEARG_1, NULL,
1013 ret_number, f_haslocaldir},
1014 {"hasmapto", 1, 3, FEARG_1, NULL,
1015 ret_number, f_hasmapto},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +02001016 {"highlightID", 1, 1, FEARG_1, NULL, // obsolete
1017 ret_number, f_hlID},
1018 {"highlight_exists",1, 1, FEARG_1, NULL, // obsolete
1019 ret_number, f_hlexists},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001020 {"histadd", 2, 2, FEARG_2, NULL,
1021 ret_number, f_histadd},
1022 {"histdel", 1, 2, FEARG_1, NULL,
1023 ret_number, f_histdel},
1024 {"histget", 1, 2, FEARG_1, NULL,
1025 ret_string, f_histget},
1026 {"histnr", 1, 1, FEARG_1, NULL,
1027 ret_number, f_histnr},
1028 {"hlID", 1, 1, FEARG_1, NULL,
1029 ret_number, f_hlID},
1030 {"hlexists", 1, 1, FEARG_1, NULL,
1031 ret_number, f_hlexists},
1032 {"hostname", 0, 0, 0, NULL,
1033 ret_string, f_hostname},
1034 {"iconv", 3, 3, FEARG_1, NULL,
1035 ret_string, f_iconv},
1036 {"indent", 1, 1, FEARG_1, NULL,
1037 ret_number, f_indent},
1038 {"index", 2, 4, FEARG_1, NULL,
1039 ret_number, f_index},
1040 {"input", 1, 3, FEARG_1, NULL,
1041 ret_string, f_input},
1042 {"inputdialog", 1, 3, FEARG_1, NULL,
1043 ret_string, f_inputdialog},
1044 {"inputlist", 1, 1, FEARG_1, NULL,
1045 ret_number, f_inputlist},
1046 {"inputrestore", 0, 0, 0, NULL,
1047 ret_number, f_inputrestore},
1048 {"inputsave", 0, 0, 0, NULL,
1049 ret_number, f_inputsave},
1050 {"inputsecret", 1, 2, FEARG_1, NULL,
1051 ret_string, f_inputsecret},
Bram Moolenaarca174532020-10-21 16:42:22 +02001052 {"insert", 2, 3, FEARG_1, arg3_insert,
Bram Moolenaar94738d82020-10-21 14:25:07 +02001053 ret_first_arg, f_insert},
1054 {"interrupt", 0, 0, 0, NULL,
1055 ret_void, f_interrupt},
1056 {"invert", 1, 1, FEARG_1, NULL,
1057 ret_number, f_invert},
1058 {"isdirectory", 1, 1, FEARG_1, NULL,
1059 ret_number, f_isdirectory},
1060 {"isinf", 1, 1, FEARG_1, NULL,
1061 ret_number, MATH_FUNC(f_isinf)},
1062 {"islocked", 1, 1, FEARG_1, NULL,
1063 ret_number, f_islocked},
1064 {"isnan", 1, 1, FEARG_1, NULL,
1065 ret_number, MATH_FUNC(f_isnan)},
1066 {"items", 1, 1, FEARG_1, NULL,
1067 ret_list_any, f_items},
1068 {"job_getchannel", 1, 1, FEARG_1, NULL,
1069 ret_channel, JOB_FUNC(f_job_getchannel)},
1070 {"job_info", 0, 1, FEARG_1, NULL,
1071 ret_dict_any, JOB_FUNC(f_job_info)},
1072 {"job_setoptions", 2, 2, FEARG_1, NULL,
1073 ret_void, JOB_FUNC(f_job_setoptions)},
1074 {"job_start", 1, 2, FEARG_1, NULL,
1075 ret_job, JOB_FUNC(f_job_start)},
1076 {"job_status", 1, 1, FEARG_1, NULL,
1077 ret_string, JOB_FUNC(f_job_status)},
1078 {"job_stop", 1, 2, FEARG_1, NULL,
1079 ret_number, JOB_FUNC(f_job_stop)},
1080 {"join", 1, 2, FEARG_1, NULL,
1081 ret_string, f_join},
1082 {"js_decode", 1, 1, FEARG_1, NULL,
1083 ret_any, f_js_decode},
1084 {"js_encode", 1, 1, FEARG_1, NULL,
1085 ret_string, f_js_encode},
1086 {"json_decode", 1, 1, FEARG_1, NULL,
1087 ret_any, f_json_decode},
1088 {"json_encode", 1, 1, FEARG_1, NULL,
1089 ret_string, f_json_encode},
1090 {"keys", 1, 1, FEARG_1, NULL,
1091 ret_list_string, f_keys},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +02001092 {"last_buffer_nr", 0, 0, 0, NULL, // obsolete
1093 ret_number, f_last_buffer_nr},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001094 {"len", 1, 1, FEARG_1, NULL,
1095 ret_number, f_len},
1096 {"libcall", 3, 3, FEARG_3, NULL,
1097 ret_string, f_libcall},
1098 {"libcallnr", 3, 3, FEARG_3, NULL,
1099 ret_number, f_libcallnr},
1100 {"line", 1, 2, FEARG_1, NULL,
1101 ret_number, f_line},
1102 {"line2byte", 1, 1, FEARG_1, NULL,
1103 ret_number, f_line2byte},
1104 {"lispindent", 1, 1, FEARG_1, NULL,
1105 ret_number, f_lispindent},
1106 {"list2str", 1, 2, FEARG_1, NULL,
1107 ret_string, f_list2str},
1108 {"listener_add", 1, 2, FEARG_2, NULL,
1109 ret_number, f_listener_add},
1110 {"listener_flush", 0, 1, FEARG_1, NULL,
1111 ret_void, f_listener_flush},
1112 {"listener_remove", 1, 1, FEARG_1, NULL,
1113 ret_number, f_listener_remove},
1114 {"localtime", 0, 0, 0, NULL,
1115 ret_number, f_localtime},
1116 {"log", 1, 1, FEARG_1, NULL,
1117 ret_float, FLOAT_FUNC(f_log)},
1118 {"log10", 1, 1, FEARG_1, NULL,
1119 ret_float, FLOAT_FUNC(f_log10)},
1120 {"luaeval", 1, 2, FEARG_1, NULL,
1121 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001122#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +01001123 f_luaeval
1124#else
1125 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001126#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001127 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001128 {"map", 2, 2, FEARG_1, NULL,
Bram Moolenaarea696852020-11-09 18:31:39 +01001129 ret_first_cont, f_map},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001130 {"maparg", 1, 4, FEARG_1, NULL,
1131 ret_maparg, f_maparg},
1132 {"mapcheck", 1, 3, FEARG_1, NULL,
1133 ret_string, f_mapcheck},
Bram Moolenaarea696852020-11-09 18:31:39 +01001134 {"mapnew", 2, 2, FEARG_1, NULL,
1135 ret_first_cont, f_mapnew},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001136 {"mapset", 3, 3, FEARG_1, NULL,
1137 ret_void, f_mapset},
1138 {"match", 2, 4, FEARG_1, NULL,
1139 ret_any, f_match},
1140 {"matchadd", 2, 5, FEARG_1, NULL,
1141 ret_number, f_matchadd},
1142 {"matchaddpos", 2, 5, FEARG_1, NULL,
1143 ret_number, f_matchaddpos},
1144 {"matcharg", 1, 1, FEARG_1, NULL,
1145 ret_list_string, f_matcharg},
1146 {"matchdelete", 1, 2, FEARG_1, NULL,
1147 ret_number, f_matchdelete},
1148 {"matchend", 2, 4, FEARG_1, NULL,
1149 ret_number, f_matchend},
1150 {"matchfuzzy", 2, 3, FEARG_1, NULL,
1151 ret_list_string, f_matchfuzzy},
1152 {"matchfuzzypos", 2, 3, FEARG_1, NULL,
1153 ret_list_any, f_matchfuzzypos},
1154 {"matchlist", 2, 4, FEARG_1, NULL,
1155 ret_list_string, f_matchlist},
1156 {"matchstr", 2, 4, FEARG_1, NULL,
1157 ret_string, f_matchstr},
1158 {"matchstrpos", 2, 4, FEARG_1, NULL,
1159 ret_list_any, f_matchstrpos},
1160 {"max", 1, 1, FEARG_1, NULL,
1161 ret_any, f_max},
1162 {"menu_info", 1, 2, FEARG_1, NULL,
1163 ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +01001164#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +01001165 f_menu_info
1166#else
1167 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +01001168#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001169 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001170 {"min", 1, 1, FEARG_1, NULL,
1171 ret_any, f_min},
1172 {"mkdir", 1, 3, FEARG_1, NULL,
1173 ret_number, f_mkdir},
1174 {"mode", 0, 1, FEARG_1, NULL,
1175 ret_string, f_mode},
1176 {"mzeval", 1, 1, FEARG_1, NULL,
1177 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001178#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +01001179 f_mzeval
1180#else
1181 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001182#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001183 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001184 {"nextnonblank", 1, 1, FEARG_1, NULL,
1185 ret_number, f_nextnonblank},
1186 {"nr2char", 1, 2, FEARG_1, NULL,
1187 ret_string, f_nr2char},
1188 {"or", 2, 2, FEARG_1, NULL,
1189 ret_number, f_or},
1190 {"pathshorten", 1, 2, FEARG_1, NULL,
1191 ret_string, f_pathshorten},
1192 {"perleval", 1, 1, FEARG_1, NULL,
1193 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001194#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +01001195 f_perleval
1196#else
1197 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001198#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001199 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001200 {"popup_atcursor", 2, 2, FEARG_1, NULL,
1201 ret_number, PROP_FUNC(f_popup_atcursor)},
1202 {"popup_beval", 2, 2, FEARG_1, NULL,
1203 ret_number, PROP_FUNC(f_popup_beval)},
1204 {"popup_clear", 0, 1, 0, NULL,
1205 ret_void, PROP_FUNC(f_popup_clear)},
1206 {"popup_close", 1, 2, FEARG_1, NULL,
1207 ret_void, PROP_FUNC(f_popup_close)},
1208 {"popup_create", 2, 2, FEARG_1, NULL,
1209 ret_number, PROP_FUNC(f_popup_create)},
1210 {"popup_dialog", 2, 2, FEARG_1, NULL,
1211 ret_number, PROP_FUNC(f_popup_dialog)},
1212 {"popup_filter_menu", 2, 2, 0, NULL,
1213 ret_bool, PROP_FUNC(f_popup_filter_menu)},
1214 {"popup_filter_yesno", 2, 2, 0, NULL,
1215 ret_bool, PROP_FUNC(f_popup_filter_yesno)},
1216 {"popup_findinfo", 0, 0, 0, NULL,
1217 ret_number, PROP_FUNC(f_popup_findinfo)},
1218 {"popup_findpreview", 0, 0, 0, NULL,
1219 ret_number, PROP_FUNC(f_popup_findpreview)},
1220 {"popup_getoptions", 1, 1, FEARG_1, NULL,
1221 ret_dict_any, PROP_FUNC(f_popup_getoptions)},
1222 {"popup_getpos", 1, 1, FEARG_1, NULL,
1223 ret_dict_any, PROP_FUNC(f_popup_getpos)},
1224 {"popup_hide", 1, 1, FEARG_1, NULL,
1225 ret_void, PROP_FUNC(f_popup_hide)},
1226 {"popup_list", 0, 0, 0, NULL,
1227 ret_list_number, PROP_FUNC(f_popup_list)},
1228 {"popup_locate", 2, 2, 0, NULL,
1229 ret_number, PROP_FUNC(f_popup_locate)},
1230 {"popup_menu", 2, 2, FEARG_1, NULL,
1231 ret_number, PROP_FUNC(f_popup_menu)},
1232 {"popup_move", 2, 2, FEARG_1, NULL,
1233 ret_void, PROP_FUNC(f_popup_move)},
1234 {"popup_notification", 2, 2, FEARG_1, NULL,
1235 ret_number, PROP_FUNC(f_popup_notification)},
1236 {"popup_setoptions", 2, 2, FEARG_1, NULL,
1237 ret_void, PROP_FUNC(f_popup_setoptions)},
1238 {"popup_settext", 2, 2, FEARG_1, NULL,
1239 ret_void, PROP_FUNC(f_popup_settext)},
1240 {"popup_show", 1, 1, FEARG_1, NULL,
1241 ret_void, PROP_FUNC(f_popup_show)},
1242 {"pow", 2, 2, FEARG_1, NULL,
1243 ret_float, FLOAT_FUNC(f_pow)},
1244 {"prevnonblank", 1, 1, FEARG_1, NULL,
1245 ret_number, f_prevnonblank},
1246 {"printf", 1, 19, FEARG_2, NULL,
1247 ret_string, f_printf},
1248 {"prompt_getprompt", 1, 1, FEARG_1, NULL,
1249 ret_string, JOB_FUNC(f_prompt_getprompt)},
1250 {"prompt_setcallback", 2, 2, FEARG_1, NULL,
1251 ret_void, JOB_FUNC(f_prompt_setcallback)},
1252 {"prompt_setinterrupt", 2, 2, FEARG_1, NULL,
1253 ret_void, JOB_FUNC(f_prompt_setinterrupt)},
1254 {"prompt_setprompt", 2, 2, FEARG_1, NULL,
1255 ret_void, JOB_FUNC(f_prompt_setprompt)},
1256 {"prop_add", 3, 3, FEARG_1, NULL,
1257 ret_void, PROP_FUNC(f_prop_add)},
1258 {"prop_clear", 1, 3, FEARG_1, NULL,
1259 ret_void, PROP_FUNC(f_prop_clear)},
1260 {"prop_find", 1, 2, FEARG_1, NULL,
1261 ret_dict_any, PROP_FUNC(f_prop_find)},
1262 {"prop_list", 1, 2, FEARG_1, NULL,
1263 ret_list_dict_any, PROP_FUNC(f_prop_list)},
1264 {"prop_remove", 1, 3, FEARG_1, NULL,
1265 ret_number, PROP_FUNC(f_prop_remove)},
1266 {"prop_type_add", 2, 2, FEARG_1, NULL,
1267 ret_void, PROP_FUNC(f_prop_type_add)},
1268 {"prop_type_change", 2, 2, FEARG_1, NULL,
1269 ret_void, PROP_FUNC(f_prop_type_change)},
1270 {"prop_type_delete", 1, 2, FEARG_1, NULL,
1271 ret_void, PROP_FUNC(f_prop_type_delete)},
1272 {"prop_type_get", 1, 2, FEARG_1, NULL,
1273 ret_dict_any, PROP_FUNC(f_prop_type_get)},
1274 {"prop_type_list", 0, 1, FEARG_1, NULL,
1275 ret_list_string, PROP_FUNC(f_prop_type_list)},
1276 {"pum_getpos", 0, 0, 0, NULL,
1277 ret_dict_number, f_pum_getpos},
1278 {"pumvisible", 0, 0, 0, NULL,
1279 ret_number, f_pumvisible},
1280 {"py3eval", 1, 1, FEARG_1, NULL,
1281 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001282#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +01001283 f_py3eval
1284#else
1285 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001286#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001287 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001288 {"pyeval", 1, 1, FEARG_1, NULL,
1289 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001290#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +01001291 f_pyeval
1292#else
1293 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001294#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001295 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001296 {"pyxeval", 1, 1, FEARG_1, NULL,
1297 ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001298#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +01001299 f_pyxeval
1300#else
1301 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001302#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001303 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001304 {"rand", 0, 1, FEARG_1, NULL,
1305 ret_number, f_rand},
1306 {"range", 1, 3, FEARG_1, NULL,
1307 ret_list_number, f_range},
1308 {"readdir", 1, 3, FEARG_1, NULL,
1309 ret_list_string, f_readdir},
1310 {"readdirex", 1, 3, FEARG_1, NULL,
1311 ret_list_dict_any, f_readdirex},
1312 {"readfile", 1, 3, FEARG_1, NULL,
1313 ret_any, f_readfile},
1314 {"reduce", 2, 3, FEARG_1, NULL,
1315 ret_any, f_reduce},
1316 {"reg_executing", 0, 0, 0, NULL,
1317 ret_string, f_reg_executing},
1318 {"reg_recording", 0, 0, 0, NULL,
1319 ret_string, f_reg_recording},
1320 {"reltime", 0, 2, FEARG_1, NULL,
1321 ret_list_any, f_reltime},
1322 {"reltimefloat", 1, 1, FEARG_1, NULL,
1323 ret_float, FLOAT_FUNC(f_reltimefloat)},
1324 {"reltimestr", 1, 1, FEARG_1, NULL,
1325 ret_string, f_reltimestr},
1326 {"remote_expr", 2, 4, FEARG_1, NULL,
1327 ret_string, f_remote_expr},
1328 {"remote_foreground", 1, 1, FEARG_1, NULL,
1329 ret_string, f_remote_foreground},
1330 {"remote_peek", 1, 2, FEARG_1, NULL,
1331 ret_number, f_remote_peek},
1332 {"remote_read", 1, 2, FEARG_1, NULL,
1333 ret_string, f_remote_read},
1334 {"remote_send", 2, 3, FEARG_1, NULL,
1335 ret_string, f_remote_send},
1336 {"remote_startserver", 1, 1, FEARG_1, NULL,
1337 ret_void, f_remote_startserver},
1338 {"remove", 2, 3, FEARG_1, NULL,
1339 ret_remove, f_remove},
1340 {"rename", 2, 2, FEARG_1, NULL,
1341 ret_number, f_rename},
1342 {"repeat", 2, 2, FEARG_1, NULL,
1343 ret_first_arg, f_repeat},
1344 {"resolve", 1, 1, FEARG_1, NULL,
1345 ret_string, f_resolve},
1346 {"reverse", 1, 1, FEARG_1, NULL,
1347 ret_first_arg, f_reverse},
1348 {"round", 1, 1, FEARG_1, NULL,
1349 ret_float, FLOAT_FUNC(f_round)},
1350 {"rubyeval", 1, 1, FEARG_1, NULL,
1351 ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +01001352#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +01001353 f_rubyeval
1354#else
1355 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +01001356#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001357 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001358 {"screenattr", 2, 2, FEARG_1, NULL,
1359 ret_number, f_screenattr},
1360 {"screenchar", 2, 2, FEARG_1, NULL,
1361 ret_number, f_screenchar},
1362 {"screenchars", 2, 2, FEARG_1, NULL,
1363 ret_list_number, f_screenchars},
1364 {"screencol", 0, 0, 0, NULL,
1365 ret_number, f_screencol},
1366 {"screenpos", 3, 3, FEARG_1, NULL,
1367 ret_dict_number, f_screenpos},
1368 {"screenrow", 0, 0, 0, NULL,
1369 ret_number, f_screenrow},
1370 {"screenstring", 2, 2, FEARG_1, NULL,
1371 ret_string, f_screenstring},
1372 {"search", 1, 5, FEARG_1, NULL,
1373 ret_number, f_search},
1374 {"searchcount", 0, 1, FEARG_1, NULL,
1375 ret_dict_any, f_searchcount},
1376 {"searchdecl", 1, 3, FEARG_1, NULL,
1377 ret_number, f_searchdecl},
1378 {"searchpair", 3, 7, 0, NULL,
1379 ret_number, f_searchpair},
1380 {"searchpairpos", 3, 7, 0, NULL,
1381 ret_list_number, f_searchpairpos},
1382 {"searchpos", 1, 5, FEARG_1, NULL,
1383 ret_list_number, f_searchpos},
1384 {"server2client", 2, 2, FEARG_1, NULL,
1385 ret_number, f_server2client},
1386 {"serverlist", 0, 0, 0, NULL,
1387 ret_string, f_serverlist},
1388 {"setbufline", 3, 3, FEARG_3, NULL,
1389 ret_number, f_setbufline},
1390 {"setbufvar", 3, 3, FEARG_3, NULL,
1391 ret_void, f_setbufvar},
1392 {"setcellwidths", 1, 1, FEARG_1, NULL,
1393 ret_void, f_setcellwidths},
1394 {"setcharsearch", 1, 1, FEARG_1, NULL,
1395 ret_void, f_setcharsearch},
1396 {"setcmdpos", 1, 1, FEARG_1, NULL,
1397 ret_number, f_setcmdpos},
1398 {"setenv", 2, 2, FEARG_2, NULL,
1399 ret_void, f_setenv},
1400 {"setfperm", 2, 2, FEARG_1, NULL,
1401 ret_number, f_setfperm},
1402 {"setline", 2, 2, FEARG_2, NULL,
1403 ret_number, f_setline},
1404 {"setloclist", 2, 4, FEARG_2, NULL,
1405 ret_number, f_setloclist},
1406 {"setmatches", 1, 2, FEARG_1, NULL,
1407 ret_number, f_setmatches},
1408 {"setpos", 2, 2, FEARG_2, NULL,
1409 ret_number, f_setpos},
1410 {"setqflist", 1, 3, FEARG_1, NULL,
1411 ret_number, f_setqflist},
1412 {"setreg", 2, 3, FEARG_2, NULL,
1413 ret_number, f_setreg},
1414 {"settabvar", 3, 3, FEARG_3, NULL,
1415 ret_void, f_settabvar},
1416 {"settabwinvar", 4, 4, FEARG_4, NULL,
1417 ret_void, f_settabwinvar},
1418 {"settagstack", 2, 3, FEARG_2, NULL,
1419 ret_number, f_settagstack},
1420 {"setwinvar", 3, 3, FEARG_3, NULL,
1421 ret_void, f_setwinvar},
1422 {"sha256", 1, 1, FEARG_1, NULL,
1423 ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001424#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +01001425 f_sha256
1426#else
1427 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001428#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001429 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001430 {"shellescape", 1, 2, FEARG_1, NULL,
1431 ret_string, f_shellescape},
1432 {"shiftwidth", 0, 1, FEARG_1, NULL,
1433 ret_number, f_shiftwidth},
1434 {"sign_define", 1, 2, FEARG_1, NULL,
1435 ret_any, SIGN_FUNC(f_sign_define)},
1436 {"sign_getdefined", 0, 1, FEARG_1, NULL,
1437 ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
1438 {"sign_getplaced", 0, 2, FEARG_1, NULL,
1439 ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
1440 {"sign_jump", 3, 3, FEARG_1, NULL,
1441 ret_number, SIGN_FUNC(f_sign_jump)},
1442 {"sign_place", 4, 5, FEARG_1, NULL,
1443 ret_number, SIGN_FUNC(f_sign_place)},
1444 {"sign_placelist", 1, 1, FEARG_1, NULL,
1445 ret_list_number, SIGN_FUNC(f_sign_placelist)},
1446 {"sign_undefine", 0, 1, FEARG_1, NULL,
1447 ret_number, SIGN_FUNC(f_sign_undefine)},
1448 {"sign_unplace", 1, 2, FEARG_1, NULL,
1449 ret_number, SIGN_FUNC(f_sign_unplace)},
1450 {"sign_unplacelist", 1, 2, FEARG_1, NULL,
1451 ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
1452 {"simplify", 1, 1, FEARG_1, NULL,
1453 ret_string, f_simplify},
1454 {"sin", 1, 1, FEARG_1, NULL,
1455 ret_float, FLOAT_FUNC(f_sin)},
1456 {"sinh", 1, 1, FEARG_1, NULL,
1457 ret_float, FLOAT_FUNC(f_sinh)},
1458 {"sort", 1, 3, FEARG_1, NULL,
1459 ret_first_arg, f_sort},
1460 {"sound_clear", 0, 0, 0, NULL,
1461 ret_void, SOUND_FUNC(f_sound_clear)},
1462 {"sound_playevent", 1, 2, FEARG_1, NULL,
1463 ret_number, SOUND_FUNC(f_sound_playevent)},
1464 {"sound_playfile", 1, 2, FEARG_1, NULL,
1465 ret_number, SOUND_FUNC(f_sound_playfile)},
1466 {"sound_stop", 1, 1, FEARG_1, NULL,
1467 ret_void, SOUND_FUNC(f_sound_stop)},
1468 {"soundfold", 1, 1, FEARG_1, NULL,
1469 ret_string, f_soundfold},
1470 {"spellbadword", 0, 1, FEARG_1, NULL,
1471 ret_list_string, f_spellbadword},
1472 {"spellsuggest", 1, 3, FEARG_1, NULL,
1473 ret_list_string, f_spellsuggest},
1474 {"split", 1, 3, FEARG_1, NULL,
1475 ret_list_string, f_split},
1476 {"sqrt", 1, 1, FEARG_1, NULL,
1477 ret_float, FLOAT_FUNC(f_sqrt)},
1478 {"srand", 0, 1, FEARG_1, NULL,
1479 ret_list_number, f_srand},
1480 {"state", 0, 1, FEARG_1, NULL,
1481 ret_string, f_state},
1482 {"str2float", 1, 1, FEARG_1, NULL,
1483 ret_float, FLOAT_FUNC(f_str2float)},
1484 {"str2list", 1, 2, FEARG_1, NULL,
1485 ret_list_number, f_str2list},
1486 {"str2nr", 1, 3, FEARG_1, NULL,
1487 ret_number, f_str2nr},
1488 {"strcharpart", 2, 3, FEARG_1, NULL,
1489 ret_string, f_strcharpart},
1490 {"strchars", 1, 2, FEARG_1, NULL,
1491 ret_number, f_strchars},
1492 {"strdisplaywidth", 1, 2, FEARG_1, NULL,
1493 ret_number, f_strdisplaywidth},
1494 {"strftime", 1, 2, FEARG_1, NULL,
1495 ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001496#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +01001497 f_strftime
1498#else
1499 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001500#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001501 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001502 {"strgetchar", 2, 2, FEARG_1, NULL,
1503 ret_number, f_strgetchar},
1504 {"stridx", 2, 3, FEARG_1, NULL,
1505 ret_number, f_stridx},
1506 {"string", 1, 1, FEARG_1, NULL,
1507 ret_string, f_string},
1508 {"strlen", 1, 1, FEARG_1, NULL,
1509 ret_number, f_strlen},
1510 {"strpart", 2, 4, FEARG_1, NULL,
1511 ret_string, f_strpart},
1512 {"strptime", 2, 2, FEARG_1, NULL,
1513 ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +01001514#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +01001515 f_strptime
1516#else
1517 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +01001518#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001519 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001520 {"strridx", 2, 3, FEARG_1, NULL,
1521 ret_number, f_strridx},
1522 {"strtrans", 1, 1, FEARG_1, NULL,
1523 ret_string, f_strtrans},
1524 {"strwidth", 1, 1, FEARG_1, NULL,
1525 ret_number, f_strwidth},
1526 {"submatch", 1, 2, FEARG_1, NULL,
1527 ret_string, f_submatch},
1528 {"substitute", 4, 4, FEARG_1, NULL,
1529 ret_string, f_substitute},
1530 {"swapinfo", 1, 1, FEARG_1, NULL,
1531 ret_dict_any, f_swapinfo},
1532 {"swapname", 1, 1, FEARG_1, NULL,
1533 ret_string, f_swapname},
1534 {"synID", 3, 3, 0, NULL,
1535 ret_number, f_synID},
1536 {"synIDattr", 2, 3, FEARG_1, NULL,
1537 ret_string, f_synIDattr},
1538 {"synIDtrans", 1, 1, FEARG_1, NULL,
1539 ret_number, f_synIDtrans},
1540 {"synconcealed", 2, 2, 0, NULL,
1541 ret_list_any, f_synconcealed},
1542 {"synstack", 2, 2, 0, NULL,
1543 ret_list_number, f_synstack},
1544 {"system", 1, 2, FEARG_1, NULL,
1545 ret_string, f_system},
1546 {"systemlist", 1, 2, FEARG_1, NULL,
1547 ret_list_string, f_systemlist},
1548 {"tabpagebuflist", 0, 1, FEARG_1, NULL,
1549 ret_list_number, f_tabpagebuflist},
1550 {"tabpagenr", 0, 1, 0, NULL,
1551 ret_number, f_tabpagenr},
1552 {"tabpagewinnr", 1, 2, FEARG_1, NULL,
1553 ret_number, f_tabpagewinnr},
1554 {"tagfiles", 0, 0, 0, NULL,
1555 ret_list_string, f_tagfiles},
1556 {"taglist", 1, 2, FEARG_1, NULL,
1557 ret_list_dict_any, f_taglist},
1558 {"tan", 1, 1, FEARG_1, NULL,
1559 ret_float, FLOAT_FUNC(f_tan)},
1560 {"tanh", 1, 1, FEARG_1, NULL,
1561 ret_float, FLOAT_FUNC(f_tanh)},
1562 {"tempname", 0, 0, 0, NULL,
1563 ret_string, f_tempname},
1564 {"term_dumpdiff", 2, 3, FEARG_1, NULL,
1565 ret_number, TERM_FUNC(f_term_dumpdiff)},
1566 {"term_dumpload", 1, 2, FEARG_1, NULL,
1567 ret_number, TERM_FUNC(f_term_dumpload)},
1568 {"term_dumpwrite", 2, 3, FEARG_2, NULL,
1569 ret_void, TERM_FUNC(f_term_dumpwrite)},
1570 {"term_getaltscreen", 1, 1, FEARG_1, NULL,
1571 ret_number, TERM_FUNC(f_term_getaltscreen)},
1572 {"term_getansicolors", 1, 1, FEARG_1, NULL,
1573 ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001574#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001575 f_term_getansicolors
1576#else
1577 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001578#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001579 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001580 {"term_getattr", 2, 2, FEARG_1, NULL,
1581 ret_number, TERM_FUNC(f_term_getattr)},
1582 {"term_getcursor", 1, 1, FEARG_1, NULL,
1583 ret_list_any, TERM_FUNC(f_term_getcursor)},
1584 {"term_getjob", 1, 1, FEARG_1, NULL,
1585 ret_job, TERM_FUNC(f_term_getjob)},
1586 {"term_getline", 2, 2, FEARG_1, NULL,
1587 ret_string, TERM_FUNC(f_term_getline)},
1588 {"term_getscrolled", 1, 1, FEARG_1, NULL,
1589 ret_number, TERM_FUNC(f_term_getscrolled)},
1590 {"term_getsize", 1, 1, FEARG_1, NULL,
1591 ret_list_number, TERM_FUNC(f_term_getsize)},
1592 {"term_getstatus", 1, 1, FEARG_1, NULL,
1593 ret_string, TERM_FUNC(f_term_getstatus)},
1594 {"term_gettitle", 1, 1, FEARG_1, NULL,
1595 ret_string, TERM_FUNC(f_term_gettitle)},
1596 {"term_gettty", 1, 2, FEARG_1, NULL,
1597 ret_string, TERM_FUNC(f_term_gettty)},
1598 {"term_list", 0, 0, 0, NULL,
1599 ret_list_number, TERM_FUNC(f_term_list)},
1600 {"term_scrape", 2, 2, FEARG_1, NULL,
1601 ret_list_dict_any, TERM_FUNC(f_term_scrape)},
1602 {"term_sendkeys", 2, 2, FEARG_1, NULL,
1603 ret_void, TERM_FUNC(f_term_sendkeys)},
1604 {"term_setansicolors", 2, 2, FEARG_1, NULL,
1605 ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001606#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001607 f_term_setansicolors
1608#else
1609 NULL
1610#endif
1611 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001612 {"term_setapi", 2, 2, FEARG_1, NULL,
1613 ret_void, TERM_FUNC(f_term_setapi)},
1614 {"term_setkill", 2, 2, FEARG_1, NULL,
1615 ret_void, TERM_FUNC(f_term_setkill)},
1616 {"term_setrestore", 2, 2, FEARG_1, NULL,
1617 ret_void, TERM_FUNC(f_term_setrestore)},
1618 {"term_setsize", 3, 3, FEARG_1, NULL,
1619 ret_void, TERM_FUNC(f_term_setsize)},
1620 {"term_start", 1, 2, FEARG_1, NULL,
1621 ret_number, TERM_FUNC(f_term_start)},
1622 {"term_wait", 1, 2, FEARG_1, NULL,
1623 ret_void, TERM_FUNC(f_term_wait)},
1624 {"terminalprops", 0, 0, 0, NULL,
1625 ret_dict_string, f_terminalprops},
1626 {"test_alloc_fail", 3, 3, FEARG_1, NULL,
1627 ret_void, f_test_alloc_fail},
1628 {"test_autochdir", 0, 0, 0, NULL,
1629 ret_void, f_test_autochdir},
1630 {"test_feedinput", 1, 1, FEARG_1, NULL,
1631 ret_void, f_test_feedinput},
1632 {"test_garbagecollect_now", 0, 0, 0, NULL,
1633 ret_void, f_test_garbagecollect_now},
1634 {"test_garbagecollect_soon", 0, 0, 0, NULL,
1635 ret_void, f_test_garbagecollect_soon},
1636 {"test_getvalue", 1, 1, FEARG_1, NULL,
1637 ret_number, f_test_getvalue},
1638 {"test_ignore_error", 1, 1, FEARG_1, NULL,
1639 ret_void, f_test_ignore_error},
1640 {"test_null_blob", 0, 0, 0, NULL,
1641 ret_blob, f_test_null_blob},
1642 {"test_null_channel", 0, 0, 0, NULL,
1643 ret_channel, JOB_FUNC(f_test_null_channel)},
1644 {"test_null_dict", 0, 0, 0, NULL,
1645 ret_dict_any, f_test_null_dict},
1646 {"test_null_function", 0, 0, 0, NULL,
1647 ret_func_any, f_test_null_function},
1648 {"test_null_job", 0, 0, 0, NULL,
1649 ret_job, JOB_FUNC(f_test_null_job)},
1650 {"test_null_list", 0, 0, 0, NULL,
1651 ret_list_any, f_test_null_list},
1652 {"test_null_partial", 0, 0, 0, NULL,
1653 ret_func_any, f_test_null_partial},
1654 {"test_null_string", 0, 0, 0, NULL,
1655 ret_string, f_test_null_string},
1656 {"test_option_not_set", 1, 1, FEARG_1, NULL,
1657 ret_void, f_test_option_not_set},
1658 {"test_override", 2, 2, FEARG_2, NULL,
1659 ret_void, f_test_override},
1660 {"test_refcount", 1, 1, FEARG_1, NULL,
1661 ret_number, f_test_refcount},
1662 {"test_scrollbar", 3, 3, FEARG_2, NULL,
1663 ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +02001664#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +01001665 f_test_scrollbar
1666#else
1667 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +02001668#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001669 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001670 {"test_setmouse", 2, 2, 0, NULL,
1671 ret_void, f_test_setmouse},
1672 {"test_settime", 1, 1, FEARG_1, NULL,
1673 ret_void, f_test_settime},
1674 {"test_srand_seed", 0, 1, FEARG_1, NULL,
1675 ret_void, f_test_srand_seed},
1676 {"test_unknown", 0, 0, 0, NULL,
1677 ret_any, f_test_unknown},
1678 {"test_void", 0, 0, 0, NULL,
1679 ret_void, f_test_void},
1680 {"timer_info", 0, 1, FEARG_1, NULL,
1681 ret_list_dict_any, TIMER_FUNC(f_timer_info)},
1682 {"timer_pause", 2, 2, FEARG_1, NULL,
1683 ret_void, TIMER_FUNC(f_timer_pause)},
1684 {"timer_start", 2, 3, FEARG_1, NULL,
1685 ret_number, TIMER_FUNC(f_timer_start)},
1686 {"timer_stop", 1, 1, FEARG_1, NULL,
1687 ret_void, TIMER_FUNC(f_timer_stop)},
1688 {"timer_stopall", 0, 0, 0, NULL,
1689 ret_void, TIMER_FUNC(f_timer_stopall)},
1690 {"tolower", 1, 1, FEARG_1, NULL,
1691 ret_string, f_tolower},
1692 {"toupper", 1, 1, FEARG_1, NULL,
1693 ret_string, f_toupper},
1694 {"tr", 3, 3, FEARG_1, NULL,
1695 ret_string, f_tr},
1696 {"trim", 1, 3, FEARG_1, NULL,
1697 ret_string, f_trim},
1698 {"trunc", 1, 1, FEARG_1, NULL,
1699 ret_float, FLOAT_FUNC(f_trunc)},
1700 {"type", 1, 1, FEARG_1, NULL,
1701 ret_number, f_type},
1702 {"undofile", 1, 1, FEARG_1, NULL,
1703 ret_string, f_undofile},
1704 {"undotree", 0, 0, 0, NULL,
1705 ret_dict_any, f_undotree},
1706 {"uniq", 1, 3, FEARG_1, NULL,
1707 ret_list_any, f_uniq},
1708 {"values", 1, 1, FEARG_1, NULL,
1709 ret_list_any, f_values},
1710 {"virtcol", 1, 1, FEARG_1, NULL,
1711 ret_number, f_virtcol},
1712 {"visualmode", 0, 1, 0, NULL,
1713 ret_string, f_visualmode},
1714 {"wildmenumode", 0, 0, 0, NULL,
1715 ret_number, f_wildmenumode},
1716 {"win_execute", 2, 3, FEARG_2, NULL,
1717 ret_string, f_win_execute},
1718 {"win_findbuf", 1, 1, FEARG_1, NULL,
1719 ret_list_number, f_win_findbuf},
1720 {"win_getid", 0, 2, FEARG_1, NULL,
1721 ret_number, f_win_getid},
1722 {"win_gettype", 0, 1, FEARG_1, NULL,
1723 ret_string, f_win_gettype},
1724 {"win_gotoid", 1, 1, FEARG_1, NULL,
1725 ret_number, f_win_gotoid},
1726 {"win_id2tabwin", 1, 1, FEARG_1, NULL,
1727 ret_list_number, f_win_id2tabwin},
1728 {"win_id2win", 1, 1, FEARG_1, NULL,
1729 ret_number, f_win_id2win},
1730 {"win_screenpos", 1, 1, FEARG_1, NULL,
1731 ret_list_number, f_win_screenpos},
1732 {"win_splitmove", 2, 3, FEARG_1, NULL,
1733 ret_number, f_win_splitmove},
1734 {"winbufnr", 1, 1, FEARG_1, NULL,
1735 ret_number, f_winbufnr},
1736 {"wincol", 0, 0, 0, NULL,
1737 ret_number, f_wincol},
1738 {"windowsversion", 0, 0, 0, NULL,
1739 ret_string, f_windowsversion},
1740 {"winheight", 1, 1, FEARG_1, NULL,
1741 ret_number, f_winheight},
1742 {"winlayout", 0, 1, FEARG_1, NULL,
1743 ret_list_any, f_winlayout},
1744 {"winline", 0, 0, 0, NULL,
1745 ret_number, f_winline},
1746 {"winnr", 0, 1, FEARG_1, NULL,
1747 ret_number, f_winnr},
1748 {"winrestcmd", 0, 0, 0, NULL,
1749 ret_string, f_winrestcmd},
1750 {"winrestview", 1, 1, FEARG_1, NULL,
1751 ret_void, f_winrestview},
1752 {"winsaveview", 0, 0, 0, NULL,
1753 ret_dict_any, f_winsaveview},
1754 {"winwidth", 1, 1, FEARG_1, NULL,
1755 ret_number, f_winwidth},
1756 {"wordcount", 0, 0, 0, NULL,
1757 ret_dict_number, f_wordcount},
1758 {"writefile", 2, 3, FEARG_1, NULL,
1759 ret_number, f_writefile},
1760 {"xor", 2, 2, FEARG_1, NULL,
1761 ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001762};
1763
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001764/*
1765 * Function given to ExpandGeneric() to obtain the list of internal
1766 * or user defined function names.
1767 */
1768 char_u *
1769get_function_name(expand_T *xp, int idx)
1770{
1771 static int intidx = -1;
1772 char_u *name;
1773
1774 if (idx == 0)
1775 intidx = -1;
1776 if (intidx < 0)
1777 {
1778 name = get_user_func_name(xp, idx);
1779 if (name != NULL)
1780 return name;
1781 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001782 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001783 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001784 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001785 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001786 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001787 STRCAT(IObuff, ")");
1788 return IObuff;
1789 }
1790
1791 return NULL;
1792}
1793
1794/*
1795 * Function given to ExpandGeneric() to obtain the list of internal or
1796 * user defined variable or function names.
1797 */
1798 char_u *
1799get_expr_name(expand_T *xp, int idx)
1800{
1801 static int intidx = -1;
1802 char_u *name;
1803
1804 if (idx == 0)
1805 intidx = -1;
1806 if (intidx < 0)
1807 {
1808 name = get_function_name(xp, idx);
1809 if (name != NULL)
1810 return name;
1811 }
1812 return get_user_var_name(xp, ++intidx);
1813}
1814
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001815/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001816 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001817 * Return index, or -1 if not found or "implemented" is TRUE and the function
1818 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001819 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001820 static int
1821find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822{
1823 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001824 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 int cmp;
1826 int x;
1827
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001828 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001829
1830 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001831 while (first <= last)
1832 {
1833 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001834 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835 if (cmp < 0)
1836 last = x - 1;
1837 else if (cmp > 0)
1838 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001839 else if (implemented && global_functions[x].f_func == NULL)
1840 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001841 else
1842 return x;
1843 }
1844 return -1;
1845}
1846
Bram Moolenaar15c47602020-03-26 22:16:48 +01001847/*
1848 * Find internal function "name" in table "global_functions".
1849 * Return index, or -1 if not found or the function is not implemented.
1850 */
1851 int
1852find_internal_func(char_u *name)
1853{
1854 return find_internal_func_opt(name, TRUE);
1855}
1856
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001857 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001858has_internal_func(char_u *name)
1859{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001860 return find_internal_func_opt(name, TRUE) >= 0;
1861}
1862
1863 static int
1864has_internal_func_name(char_u *name)
1865{
1866 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001867}
1868
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001869 char *
1870internal_func_name(int idx)
1871{
1872 return global_functions[idx].f_name;
1873}
1874
Bram Moolenaar94738d82020-10-21 14:25:07 +02001875/*
1876 * Check the argument types for builting function "idx".
1877 * Uses the list of types on the type stack: "types".
1878 * Return FAIL and gives an error message when a type is wrong.
1879 */
1880 int
Bram Moolenaarca174532020-10-21 16:42:22 +02001881internal_func_check_arg_types(type_T **types, int idx, int argcount)
Bram Moolenaar94738d82020-10-21 14:25:07 +02001882{
1883 argcheck_T *argchecks = global_functions[idx].f_argcheck;
1884 int i;
1885
1886 if (argchecks != NULL)
1887 {
1888 argcontext_T context;
1889
1890 context.arg_count = argcount;
Bram Moolenaarca174532020-10-21 16:42:22 +02001891 context.arg_types = types;
Bram Moolenaar94738d82020-10-21 14:25:07 +02001892 for (i = 0; i < argcount; ++i)
1893 if (argchecks[i] != NULL)
1894 {
1895 context.arg_idx = i;
Bram Moolenaarca174532020-10-21 16:42:22 +02001896 if (argchecks[i](types[i], &context) == FAIL)
Bram Moolenaar94738d82020-10-21 14:25:07 +02001897 return FAIL;
1898 }
1899 }
1900 return OK;
1901}
1902
Bram Moolenaara1224cb2020-10-22 12:31:49 +02001903/*
1904 * Call the "f_retfunc" function to obtain the return type of function "idx".
1905 * "argtypes" is the list of argument types or NULL when there are no
1906 * arguments.
1907 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001908 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001909internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001910{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001911 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001912}
1913
1914/*
1915 * Check the argument count to use for internal function "idx".
Bram Moolenaar389df252020-07-09 21:20:47 +02001916 * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
1917 * first argument, 2 if method base is second argument, etc. 9 if method base
1918 * is last argument.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001919 */
1920 int
1921check_internal_func(int idx, int argcount)
1922{
1923 int res;
1924 char *name;
1925
1926 if (argcount < global_functions[idx].f_min_argc)
1927 res = FCERR_TOOFEW;
1928 else if (argcount > global_functions[idx].f_max_argc)
1929 res = FCERR_TOOMANY;
1930 else
Bram Moolenaar389df252020-07-09 21:20:47 +02001931 return global_functions[idx].f_argtype;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001932
1933 name = internal_func_name(idx);
1934 if (res == FCERR_TOOMANY)
1935 semsg(_(e_toomanyarg), name);
1936 else
1937 semsg(_(e_toofewarg), name);
Bram Moolenaar389df252020-07-09 21:20:47 +02001938 return -1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001939}
1940
Bram Moolenaarac92e252019-08-03 21:58:38 +02001941 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942call_internal_func(
1943 char_u *name,
1944 int argcount,
1945 typval_T *argvars,
1946 typval_T *rettv)
1947{
1948 int i;
1949
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001950 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001951 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001952 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001953 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001954 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001955 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001956 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001958 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001959 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001960}
1961
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001962 void
1963call_internal_func_by_idx(
1964 int idx,
1965 typval_T *argvars,
1966 typval_T *rettv)
1967{
1968 global_functions[idx].f_func(argvars, rettv);
1969}
1970
Bram Moolenaarac92e252019-08-03 21:58:38 +02001971/*
1972 * Invoke a method for base->method().
1973 */
1974 int
1975call_internal_method(
1976 char_u *name,
1977 int argcount,
1978 typval_T *argvars,
1979 typval_T *rettv,
1980 typval_T *basetv)
1981{
1982 int i;
1983 int fi;
1984 typval_T argv[MAX_FUNC_ARGS + 1];
1985
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001986 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001987 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001988 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001989 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001990 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001991 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001992 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001993 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001994 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001995
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001996 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001997 {
1998 // base value goes last
1999 for (i = 0; i < argcount; ++i)
2000 argv[i] = argvars[i];
2001 argv[argcount] = *basetv;
2002 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002003 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02002004 {
2005 // base value goes second
2006 argv[0] = argvars[0];
2007 argv[1] = *basetv;
2008 for (i = 1; i < argcount; ++i)
2009 argv[i + 1] = argvars[i];
2010 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02002011 else if (global_functions[fi].f_argtype == FEARG_3)
2012 {
2013 // base value goes third
2014 argv[0] = argvars[0];
2015 argv[1] = argvars[1];
2016 argv[2] = *basetv;
2017 for (i = 2; i < argcount; ++i)
2018 argv[i + 1] = argvars[i];
2019 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02002020 else if (global_functions[fi].f_argtype == FEARG_4)
2021 {
2022 // base value goes fourth
2023 argv[0] = argvars[0];
2024 argv[1] = argvars[1];
2025 argv[2] = argvars[2];
2026 argv[3] = *basetv;
2027 for (i = 3; i < argcount; ++i)
2028 argv[i + 1] = argvars[i];
2029 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02002030 else
2031 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002032 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02002033 argv[0] = *basetv;
2034 for (i = 0; i < argcount; ++i)
2035 argv[i + 1] = argvars[i];
2036 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02002037 argv[argcount + 1].v_type = VAR_UNKNOWN;
2038
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002039 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01002040 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002041}
2042
2043/*
2044 * Return TRUE for a non-zero Number and a non-empty String.
2045 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02002046 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002047non_zero_arg(typval_T *argvars)
2048{
2049 return ((argvars[0].v_type == VAR_NUMBER
2050 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01002051 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052 && argvars[0].vval.v_number == VVAL_TRUE)
2053 || (argvars[0].v_type == VAR_STRING
2054 && argvars[0].vval.v_string != NULL
2055 && *argvars[0].vval.v_string != NUL));
2056}
2057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002059/*
2060 * Get the float value of "argvars[0]" into "f".
2061 * Returns FAIL when the argument is not a Number or Float.
2062 */
2063 static int
2064get_float_arg(typval_T *argvars, float_T *f)
2065{
2066 if (argvars[0].v_type == VAR_FLOAT)
2067 {
2068 *f = argvars[0].vval.v_float;
2069 return OK;
2070 }
2071 if (argvars[0].v_type == VAR_NUMBER)
2072 {
2073 *f = (float_T)argvars[0].vval.v_number;
2074 return OK;
2075 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002076 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077 return FAIL;
2078}
2079
2080/*
2081 * "abs(expr)" function
2082 */
2083 static void
2084f_abs(typval_T *argvars, typval_T *rettv)
2085{
2086 if (argvars[0].v_type == VAR_FLOAT)
2087 {
2088 rettv->v_type = VAR_FLOAT;
2089 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
2090 }
2091 else
2092 {
2093 varnumber_T n;
2094 int error = FALSE;
2095
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002096 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 if (error)
2098 rettv->vval.v_number = -1;
2099 else if (n > 0)
2100 rettv->vval.v_number = n;
2101 else
2102 rettv->vval.v_number = -n;
2103 }
2104}
2105
2106/*
2107 * "acos()" function
2108 */
2109 static void
2110f_acos(typval_T *argvars, typval_T *rettv)
2111{
2112 float_T f = 0.0;
2113
2114 rettv->v_type = VAR_FLOAT;
2115 if (get_float_arg(argvars, &f) == OK)
2116 rettv->vval.v_float = acos(f);
2117 else
2118 rettv->vval.v_float = 0.0;
2119}
2120#endif
2121
2122/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002123 * "and(expr, expr)" function
2124 */
2125 static void
2126f_and(typval_T *argvars, typval_T *rettv)
2127{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002128 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
2129 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02002130}
2131
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002132#ifdef FEAT_FLOAT
2133/*
2134 * "asin()" function
2135 */
2136 static void
2137f_asin(typval_T *argvars, typval_T *rettv)
2138{
2139 float_T f = 0.0;
2140
2141 rettv->v_type = VAR_FLOAT;
2142 if (get_float_arg(argvars, &f) == OK)
2143 rettv->vval.v_float = asin(f);
2144 else
2145 rettv->vval.v_float = 0.0;
2146}
2147
2148/*
2149 * "atan()" function
2150 */
2151 static void
2152f_atan(typval_T *argvars, typval_T *rettv)
2153{
2154 float_T f = 0.0;
2155
2156 rettv->v_type = VAR_FLOAT;
2157 if (get_float_arg(argvars, &f) == OK)
2158 rettv->vval.v_float = atan(f);
2159 else
2160 rettv->vval.v_float = 0.0;
2161}
2162
2163/*
2164 * "atan2()" function
2165 */
2166 static void
2167f_atan2(typval_T *argvars, typval_T *rettv)
2168{
2169 float_T fx = 0.0, fy = 0.0;
2170
2171 rettv->v_type = VAR_FLOAT;
2172 if (get_float_arg(argvars, &fx) == OK
2173 && get_float_arg(&argvars[1], &fy) == OK)
2174 rettv->vval.v_float = atan2(fx, fy);
2175 else
2176 rettv->vval.v_float = 0.0;
2177}
2178#endif
2179
2180/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01002181 * "balloon_show()" function
2182 */
2183#ifdef FEAT_BEVAL
2184 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002185f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
2186{
2187 rettv->v_type = VAR_STRING;
2188 if (balloonEval != NULL)
2189 {
2190 if (balloonEval->msg == NULL)
2191 rettv->vval.v_string = NULL;
2192 else
2193 rettv->vval.v_string = vim_strsave(balloonEval->msg);
2194 }
2195}
2196
2197 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01002198f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
2199{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01002200 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01002201 {
2202 if (argvars[0].v_type == VAR_LIST
2203# ifdef FEAT_GUI
2204 && !gui.in_use
2205# endif
2206 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002207 {
2208 list_T *l = argvars[0].vval.v_list;
2209
2210 // empty list removes the balloon
2211 post_balloon(balloonEval, NULL,
2212 l == NULL || l->lv_len == 0 ? NULL : l);
2213 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01002214 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002215 {
2216 char_u *mesg = tv_get_string_chk(&argvars[0]);
2217
2218 if (mesg != NULL)
2219 // empty string removes the balloon
2220 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
2221 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01002222 }
2223}
2224
Bram Moolenaar669a8282017-11-19 20:13:05 +01002225# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01002226 static void
2227f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
2228{
2229 if (rettv_list_alloc(rettv) == OK)
2230 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002231 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01002232
2233 if (msg != NULL)
2234 {
2235 pumitem_T *array;
2236 int size = split_message(msg, &array);
2237 int i;
2238
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002239 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01002240 for (i = 1; i < size - 1; ++i)
2241 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01002242 while (size > 0)
2243 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01002244 vim_free(array);
2245 }
2246 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01002247}
Bram Moolenaar669a8282017-11-19 20:13:05 +01002248# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01002249#endif
2250
2251/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002252 * Get the buffer from "arg" and give an error and return NULL if it is not
2253 * valid.
2254 */
Bram Moolenaara3347722019-05-11 21:14:24 +02002255 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002256get_buf_arg(typval_T *arg)
2257{
2258 buf_T *buf;
2259
2260 ++emsg_off;
2261 buf = tv_get_buf(arg, FALSE);
2262 --emsg_off;
2263 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002264 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002265 return buf;
2266}
2267
2268/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 * "byte2line(byte)" function
2270 */
2271 static void
2272f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2273{
2274#ifndef FEAT_BYTEOFF
2275 rettv->vval.v_number = -1;
2276#else
2277 long boff = 0;
2278
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002279 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 if (boff < 0)
2281 rettv->vval.v_number = -1;
2282 else
2283 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2284 (linenr_T)0, &boff);
2285#endif
2286}
2287
2288 static void
2289byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2290{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002291 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 char_u *str;
2293 varnumber_T idx;
2294
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002295 str = tv_get_string_chk(&argvars[0]);
2296 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 rettv->vval.v_number = -1;
2298 if (str == NULL || idx < 0)
2299 return;
2300
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 t = str;
2302 for ( ; idx > 0; idx--)
2303 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002304 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002305 return;
2306 if (enc_utf8 && comp)
2307 t += utf_ptr2len(t);
2308 else
2309 t += (*mb_ptr2len)(t);
2310 }
2311 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002312}
2313
2314/*
2315 * "byteidx()" function
2316 */
2317 static void
2318f_byteidx(typval_T *argvars, typval_T *rettv)
2319{
2320 byteidx(argvars, rettv, FALSE);
2321}
2322
2323/*
2324 * "byteidxcomp()" function
2325 */
2326 static void
2327f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2328{
2329 byteidx(argvars, rettv, TRUE);
2330}
2331
2332/*
2333 * "call(func, arglist [, dict])" function
2334 */
2335 static void
2336f_call(typval_T *argvars, typval_T *rettv)
2337{
2338 char_u *func;
2339 partial_T *partial = NULL;
2340 dict_T *selfdict = NULL;
2341
2342 if (argvars[1].v_type != VAR_LIST)
2343 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002344 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 return;
2346 }
2347 if (argvars[1].vval.v_list == NULL)
2348 return;
2349
2350 if (argvars[0].v_type == VAR_FUNC)
2351 func = argvars[0].vval.v_string;
2352 else if (argvars[0].v_type == VAR_PARTIAL)
2353 {
2354 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002355 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356 }
2357 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002358 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002360 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002361
2362 if (argvars[2].v_type != VAR_UNKNOWN)
2363 {
2364 if (argvars[2].v_type != VAR_DICT)
2365 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002366 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 return;
2368 }
2369 selfdict = argvars[2].vval.v_dict;
2370 }
2371
2372 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2373}
2374
2375#ifdef FEAT_FLOAT
2376/*
2377 * "ceil({float})" function
2378 */
2379 static void
2380f_ceil(typval_T *argvars, typval_T *rettv)
2381{
2382 float_T f = 0.0;
2383
2384 rettv->v_type = VAR_FLOAT;
2385 if (get_float_arg(argvars, &f) == OK)
2386 rettv->vval.v_float = ceil(f);
2387 else
2388 rettv->vval.v_float = 0.0;
2389}
2390#endif
2391
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002392/*
2393 * "changenr()" function
2394 */
2395 static void
2396f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2397{
2398 rettv->vval.v_number = curbuf->b_u_seq_cur;
2399}
2400
2401/*
2402 * "char2nr(string)" function
2403 */
2404 static void
2405f_char2nr(typval_T *argvars, typval_T *rettv)
2406{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002407 if (has_mbyte)
2408 {
2409 int utf8 = 0;
2410
2411 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar24f77502020-09-04 19:50:57 +02002412 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002413
2414 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002415 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002416 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002417 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002418 }
2419 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002420 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002421}
2422
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002423 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002424get_optional_window(typval_T *argvars, int idx)
2425{
2426 win_T *win = curwin;
2427
2428 if (argvars[idx].v_type != VAR_UNKNOWN)
2429 {
2430 win = find_win_by_nr_or_id(&argvars[idx]);
2431 if (win == NULL)
2432 {
2433 emsg(_(e_invalwindow));
2434 return NULL;
2435 }
2436 }
2437 return win;
2438}
2439
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002441 * "col(string)" function
2442 */
2443 static void
2444f_col(typval_T *argvars, typval_T *rettv)
2445{
2446 colnr_T col = 0;
2447 pos_T *fp;
2448 int fnum = curbuf->b_fnum;
2449
2450 fp = var2fpos(&argvars[0], FALSE, &fnum);
2451 if (fp != NULL && fnum == curbuf->b_fnum)
2452 {
2453 if (fp->col == MAXCOL)
2454 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002455 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002456 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2457 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2458 else
2459 col = MAXCOL;
2460 }
2461 else
2462 {
2463 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002464 // col(".") when the cursor is on the NUL at the end of the line
2465 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002466 if (virtual_active() && fp == &curwin->w_cursor)
2467 {
2468 char_u *p = ml_get_cursor();
2469
2470 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2471 curwin->w_virtcol - curwin->w_cursor.coladd))
2472 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002473 int l;
2474
2475 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2476 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002477 }
2478 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002479 }
2480 }
2481 rettv->vval.v_number = col;
2482}
2483
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002484/*
2485 * "confirm(message, buttons[, default [, type]])" function
2486 */
2487 static void
2488f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2489{
2490#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2491 char_u *message;
2492 char_u *buttons = NULL;
2493 char_u buf[NUMBUFLEN];
2494 char_u buf2[NUMBUFLEN];
2495 int def = 1;
2496 int type = VIM_GENERIC;
2497 char_u *typestr;
2498 int error = FALSE;
2499
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002500 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501 if (message == NULL)
2502 error = TRUE;
2503 if (argvars[1].v_type != VAR_UNKNOWN)
2504 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002505 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002506 if (buttons == NULL)
2507 error = TRUE;
2508 if (argvars[2].v_type != VAR_UNKNOWN)
2509 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002510 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511 if (argvars[3].v_type != VAR_UNKNOWN)
2512 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002513 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002514 if (typestr == NULL)
2515 error = TRUE;
2516 else
2517 {
2518 switch (TOUPPER_ASC(*typestr))
2519 {
2520 case 'E': type = VIM_ERROR; break;
2521 case 'Q': type = VIM_QUESTION; break;
2522 case 'I': type = VIM_INFO; break;
2523 case 'W': type = VIM_WARNING; break;
2524 case 'G': type = VIM_GENERIC; break;
2525 }
2526 }
2527 }
2528 }
2529 }
2530
2531 if (buttons == NULL || *buttons == NUL)
2532 buttons = (char_u *)_("&Ok");
2533
2534 if (!error)
2535 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2536 def, NULL, FALSE);
2537#endif
2538}
2539
2540/*
2541 * "copy()" function
2542 */
2543 static void
2544f_copy(typval_T *argvars, typval_T *rettv)
2545{
2546 item_copy(&argvars[0], rettv, FALSE, 0);
2547}
2548
2549#ifdef FEAT_FLOAT
2550/*
2551 * "cos()" function
2552 */
2553 static void
2554f_cos(typval_T *argvars, typval_T *rettv)
2555{
2556 float_T f = 0.0;
2557
2558 rettv->v_type = VAR_FLOAT;
2559 if (get_float_arg(argvars, &f) == OK)
2560 rettv->vval.v_float = cos(f);
2561 else
2562 rettv->vval.v_float = 0.0;
2563}
2564
2565/*
2566 * "cosh()" function
2567 */
2568 static void
2569f_cosh(typval_T *argvars, typval_T *rettv)
2570{
2571 float_T f = 0.0;
2572
2573 rettv->v_type = VAR_FLOAT;
2574 if (get_float_arg(argvars, &f) == OK)
2575 rettv->vval.v_float = cosh(f);
2576 else
2577 rettv->vval.v_float = 0.0;
2578}
2579#endif
2580
2581/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 * "cursor(lnum, col)" function, or
2583 * "cursor(list)"
2584 *
2585 * Moves the cursor to the specified line and column.
2586 * Returns 0 when the position could be set, -1 otherwise.
2587 */
2588 static void
2589f_cursor(typval_T *argvars, typval_T *rettv)
2590{
2591 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 int set_curswant = TRUE;
2594
2595 rettv->vval.v_number = -1;
2596 if (argvars[1].v_type == VAR_UNKNOWN)
2597 {
2598 pos_T pos;
2599 colnr_T curswant = -1;
2600
2601 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2602 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002603 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002604 return;
2605 }
2606 line = pos.lnum;
2607 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002608 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609 if (curswant >= 0)
2610 {
2611 curwin->w_curswant = curswant - 1;
2612 set_curswant = FALSE;
2613 }
2614 }
2615 else
2616 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002617 line = tv_get_lnum(argvars);
Bram Moolenaar9a963372020-12-21 21:58:46 +01002618 if (line < 0)
2619 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002620 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002622 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002623 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002624 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002625 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002626 if (line > 0)
2627 curwin->w_cursor.lnum = line;
2628 if (col > 0)
2629 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002630 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002631
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002632 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002633 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002634 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002635 if (has_mbyte)
2636 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002637
2638 curwin->w_set_curswant = set_curswant;
2639 rettv->vval.v_number = 0;
2640}
2641
Bram Moolenaar4f974752019-02-17 17:44:42 +01002642#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002643/*
2644 * "debugbreak()" function
2645 */
2646 static void
2647f_debugbreak(typval_T *argvars, typval_T *rettv)
2648{
2649 int pid;
2650
2651 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002652 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002653 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002654 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002655 else
2656 {
2657 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2658
2659 if (hProcess != NULL)
2660 {
2661 DebugBreakProcess(hProcess);
2662 CloseHandle(hProcess);
2663 rettv->vval.v_number = OK;
2664 }
2665 }
2666}
2667#endif
2668
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002669/*
2670 * "deepcopy()" function
2671 */
2672 static void
2673f_deepcopy(typval_T *argvars, typval_T *rettv)
2674{
2675 int noref = 0;
2676 int copyID;
2677
2678 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar44b4a242020-09-05 17:18:28 +02002679 noref = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002680 if (noref < 0 || noref > 1)
Bram Moolenaarbade44e2020-09-26 22:39:24 +02002681 semsg(_(e_using_number_as_bool_nr), noref);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 else
2683 {
2684 copyID = get_copyID();
2685 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2686 }
2687}
2688
2689/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002690 * "did_filetype()" function
2691 */
2692 static void
2693f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2694{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002695 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002696}
2697
2698/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01002699 * "echoraw({expr})" function
2700 */
2701 static void
2702f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
2703{
2704 char_u *str = tv_get_string_chk(&argvars[0]);
2705
2706 if (str != NULL && *str != NUL)
2707 {
2708 out_str(str);
2709 out_flush();
2710 }
2711}
2712
2713/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002714 * "empty({expr})" function
2715 */
2716 static void
2717f_empty(typval_T *argvars, typval_T *rettv)
2718{
2719 int n = FALSE;
2720
2721 switch (argvars[0].v_type)
2722 {
2723 case VAR_STRING:
2724 case VAR_FUNC:
2725 n = argvars[0].vval.v_string == NULL
2726 || *argvars[0].vval.v_string == NUL;
2727 break;
2728 case VAR_PARTIAL:
2729 n = FALSE;
2730 break;
2731 case VAR_NUMBER:
2732 n = argvars[0].vval.v_number == 0;
2733 break;
2734 case VAR_FLOAT:
2735#ifdef FEAT_FLOAT
2736 n = argvars[0].vval.v_float == 0.0;
2737 break;
2738#endif
2739 case VAR_LIST:
2740 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002741 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002742 break;
2743 case VAR_DICT:
2744 n = argvars[0].vval.v_dict == NULL
2745 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2746 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01002747 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002748 case VAR_SPECIAL:
2749 n = argvars[0].vval.v_number != VVAL_TRUE;
2750 break;
2751
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002752 case VAR_BLOB:
2753 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002754 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2755 break;
2756
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002757 case VAR_JOB:
2758#ifdef FEAT_JOB_CHANNEL
2759 n = argvars[0].vval.v_job == NULL
2760 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2761 break;
2762#endif
2763 case VAR_CHANNEL:
2764#ifdef FEAT_JOB_CHANNEL
2765 n = argvars[0].vval.v_channel == NULL
2766 || !channel_is_open(argvars[0].vval.v_channel);
2767 break;
2768#endif
2769 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002770 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002771 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01002772 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002773 n = TRUE;
2774 break;
2775 }
2776
2777 rettv->vval.v_number = n;
2778}
2779
2780/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002781 * "environ()" function
2782 */
2783 static void
2784f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2785{
2786#if !defined(AMIGA)
2787 int i = 0;
2788 char_u *entry, *value;
2789# ifdef MSWIN
2790 extern wchar_t **_wenviron;
2791# else
2792 extern char **environ;
2793# endif
2794
2795 if (rettv_dict_alloc(rettv) != OK)
2796 return;
2797
2798# ifdef MSWIN
2799 if (*_wenviron == NULL)
2800 return;
2801# else
2802 if (*environ == NULL)
2803 return;
2804# endif
2805
2806 for (i = 0; ; ++i)
2807 {
2808# ifdef MSWIN
2809 short_u *p;
2810
2811 if ((p = (short_u *)_wenviron[i]) == NULL)
2812 return;
2813 entry = utf16_to_enc(p, NULL);
2814# else
2815 if ((entry = (char_u *)environ[i]) == NULL)
2816 return;
2817 entry = vim_strsave(entry);
2818# endif
2819 if (entry == NULL) // out of memory
2820 return;
2821 if ((value = vim_strchr(entry, '=')) == NULL)
2822 {
2823 vim_free(entry);
2824 continue;
2825 }
2826 *value++ = NUL;
2827 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2828 vim_free(entry);
2829 }
2830#endif
2831}
2832
2833/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002834 * "escape({string}, {chars})" function
2835 */
2836 static void
2837f_escape(typval_T *argvars, typval_T *rettv)
2838{
2839 char_u buf[NUMBUFLEN];
2840
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002841 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2842 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002843 rettv->v_type = VAR_STRING;
2844}
2845
2846/*
2847 * "eval()" function
2848 */
2849 static void
2850f_eval(typval_T *argvars, typval_T *rettv)
2851{
2852 char_u *s, *p;
2853
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002854 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855 if (s != NULL)
2856 s = skipwhite(s);
2857
2858 p = s;
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02002859 if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860 {
2861 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002862 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002863 need_clr_eos = FALSE;
2864 rettv->v_type = VAR_NUMBER;
2865 rettv->vval.v_number = 0;
2866 }
2867 else if (*s != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02002868 semsg(_(e_trailing_arg), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869}
2870
2871/*
2872 * "eventhandler()" function
2873 */
2874 static void
2875f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2876{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002877 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878}
2879
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002880static garray_T redir_execute_ga;
2881
2882/*
2883 * Append "value[value_len]" to the execute() output.
2884 */
2885 void
2886execute_redir_str(char_u *value, int value_len)
2887{
2888 int len;
2889
2890 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002891 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002892 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002893 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002894 if (ga_grow(&redir_execute_ga, len) == OK)
2895 {
2896 mch_memmove((char *)redir_execute_ga.ga_data
2897 + redir_execute_ga.ga_len, value, len);
2898 redir_execute_ga.ga_len += len;
2899 }
2900}
2901
2902/*
2903 * Get next line from a list.
2904 * Called by do_cmdline() to get the next line.
2905 * Returns allocated string, or NULL for end of function.
2906 */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002907 static char_u *
2908get_list_line(
2909 int c UNUSED,
2910 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002911 int indent UNUSED,
Bram Moolenaar66250c92020-08-20 15:02:42 +02002912 getline_opt_T options UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002913{
2914 listitem_T **p = (listitem_T **)cookie;
2915 listitem_T *item = *p;
2916 char_u buf[NUMBUFLEN];
2917 char_u *s;
2918
2919 if (item == NULL)
2920 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002921 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922 *p = item->li_next;
2923 return s == NULL ? NULL : vim_strsave(s);
2924}
2925
2926/*
2927 * "execute()" function
2928 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002929 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002930execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002931{
2932 char_u *cmd = NULL;
2933 list_T *list = NULL;
2934 int save_msg_silent = msg_silent;
2935 int save_emsg_silent = emsg_silent;
2936 int save_emsg_noredir = emsg_noredir;
2937 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002938 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002939 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002940 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002941 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002942
2943 rettv->vval.v_string = NULL;
2944 rettv->v_type = VAR_STRING;
2945
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002946 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002947 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002948 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002949 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002950 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002951 return;
2952 ++list->lv_refcount;
2953 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002954 else if (argvars[arg_off].v_type == VAR_JOB
2955 || argvars[arg_off].v_type == VAR_CHANNEL)
2956 {
2957 emsg(_(e_inval_string));
2958 return;
2959 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002960 else
2961 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002962 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002963 if (cmd == NULL)
2964 return;
2965 }
2966
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002967 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002968 {
2969 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002970 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002971
2972 if (s == NULL)
2973 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002974 if (*s == NUL)
2975 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002976 if (STRNCMP(s, "silent", 6) == 0)
2977 ++msg_silent;
2978 if (STRCMP(s, "silent!") == 0)
2979 {
2980 emsg_silent = TRUE;
2981 emsg_noredir = TRUE;
2982 }
2983 }
2984 else
2985 ++msg_silent;
2986
2987 if (redir_execute)
2988 save_ga = redir_execute_ga;
2989 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2990 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002991 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002992 if (!echo_output)
2993 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002994
2995 if (cmd != NULL)
2996 do_cmdline_cmd(cmd);
2997 else
2998 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002999 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003000
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02003001 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003002 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003003 do_cmdline(NULL, get_list_line, (void *)&item,
3004 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3005 --list->lv_refcount;
3006 }
3007
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003008 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01003009 if (ga_grow(&redir_execute_ga, 1) == OK)
3010 {
3011 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3012 rettv->vval.v_string = redir_execute_ga.ga_data;
3013 }
3014 else
3015 {
3016 ga_clear(&redir_execute_ga);
3017 rettv->vval.v_string = NULL;
3018 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003019 msg_silent = save_msg_silent;
3020 emsg_silent = save_emsg_silent;
3021 emsg_noredir = save_emsg_noredir;
3022
3023 redir_execute = save_redir_execute;
3024 if (redir_execute)
3025 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003026 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003027
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003028 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003029 if (echo_output)
3030 // When not working silently: put it in column zero. A following
3031 // "echon" will overwrite the message, unavoidably.
3032 msg_col = 0;
3033 else
3034 // When working silently: Put it back where it was, since nothing
3035 // should have been written.
3036 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003037}
3038
3039/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003040 * "execute()" function
3041 */
3042 static void
3043f_execute(typval_T *argvars, typval_T *rettv)
3044{
3045 execute_common(argvars, rettv, 0);
3046}
3047
3048/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003049 * "exists()" function
3050 */
3051 static void
3052f_exists(typval_T *argvars, typval_T *rettv)
3053{
3054 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003055 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003056
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003057 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003058 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003060 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003061 if (mch_getenv(p + 1) != NULL)
3062 n = TRUE;
3063 else
3064 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003065 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003066 p = expand_env_save(p);
3067 if (p != NULL && *p != '$')
3068 n = TRUE;
3069 vim_free(p);
3070 }
3071 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003072 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 {
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02003074 n = (eval_option(&p, NULL, TRUE) == OK);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003076 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003078 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003080 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003081 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01003082 else if (*p == '?') // internal function only
3083 {
3084 n = has_internal_func_name(p + 1);
3085 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003086 else if (*p == ':')
3087 {
3088 n = cmd_exists(p + 1);
3089 }
3090 else if (*p == '#')
3091 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003092 if (p[1] == '#')
3093 n = autocmd_supported(p + 2);
3094 else
3095 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003097 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003099 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100 }
3101
3102 rettv->vval.v_number = n;
3103}
3104
3105#ifdef FEAT_FLOAT
3106/*
3107 * "exp()" function
3108 */
3109 static void
3110f_exp(typval_T *argvars, typval_T *rettv)
3111{
3112 float_T f = 0.0;
3113
3114 rettv->v_type = VAR_FLOAT;
3115 if (get_float_arg(argvars, &f) == OK)
3116 rettv->vval.v_float = exp(f);
3117 else
3118 rettv->vval.v_float = 0.0;
3119}
3120#endif
3121
3122/*
3123 * "expand()" function
3124 */
3125 static void
3126f_expand(typval_T *argvars, typval_T *rettv)
3127{
3128 char_u *s;
3129 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003130 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003131 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3132 expand_T xpc;
3133 int error = FALSE;
3134 char_u *result;
Bram Moolenaar8f187fc2020-09-26 18:47:11 +02003135#ifdef BACKSLASH_IN_FILENAME
3136 char_u *p_csl_save = p_csl;
3137
3138 // avoid using 'completeslash' here
3139 p_csl = empty_option;
3140#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003141
3142 rettv->v_type = VAR_STRING;
3143 if (argvars[1].v_type != VAR_UNKNOWN
3144 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02003145 && tv_get_bool_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003146 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003147 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003148
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003149 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003150 if (*s == '%' || *s == '#' || *s == '<')
3151 {
3152 ++emsg_off;
3153 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3154 --emsg_off;
3155 if (rettv->v_type == VAR_LIST)
3156 {
3157 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3158 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02003159 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003160 }
3161 else
3162 rettv->vval.v_string = result;
3163 }
3164 else
3165 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003166 // When the optional second argument is non-zero, don't remove matches
3167 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003168 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02003169 && tv_get_bool_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003170 options |= WILD_KEEP_ALL;
3171 if (!error)
3172 {
3173 ExpandInit(&xpc);
3174 xpc.xp_context = EXPAND_FILES;
3175 if (p_wic)
3176 options += WILD_ICASE;
3177 if (rettv->v_type == VAR_STRING)
3178 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3179 options, WILD_ALL);
3180 else if (rettv_list_alloc(rettv) != FAIL)
3181 {
3182 int i;
3183
3184 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3185 for (i = 0; i < xpc.xp_numfiles; i++)
3186 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3187 ExpandCleanup(&xpc);
3188 }
3189 }
3190 else
3191 rettv->vval.v_string = NULL;
3192 }
Bram Moolenaar8f187fc2020-09-26 18:47:11 +02003193#ifdef BACKSLASH_IN_FILENAME
3194 p_csl = p_csl_save;
3195#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003196}
3197
3198/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003199 * "expandcmd()" function
3200 * Expand all the special characters in a command string.
3201 */
3202 static void
3203f_expandcmd(typval_T *argvars, typval_T *rettv)
3204{
3205 exarg_T eap;
3206 char_u *cmdstr;
3207 char *errormsg = NULL;
3208
3209 rettv->v_type = VAR_STRING;
3210 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3211
3212 memset(&eap, 0, sizeof(eap));
3213 eap.cmd = cmdstr;
3214 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003215 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003216 eap.usefilter = FALSE;
3217 eap.nextcmd = NULL;
3218 eap.cmdidx = CMD_USER;
3219
3220 expand_filename(&eap, &cmdstr, &errormsg);
3221 if (errormsg != NULL && *errormsg != NUL)
3222 emsg(errormsg);
3223
3224 rettv->vval.v_string = cmdstr;
3225}
3226
3227/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003228 * "feedkeys()" function
3229 */
3230 static void
3231f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3232{
3233 int remap = TRUE;
3234 int insert = FALSE;
3235 char_u *keys, *flags;
3236 char_u nbuf[NUMBUFLEN];
3237 int typed = FALSE;
3238 int execute = FALSE;
3239 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003240 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003241 char_u *keys_esc;
3242
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003243 // This is not allowed in the sandbox. If the commands would still be
3244 // executed in the sandbox it would be OK, but it probably happens later,
3245 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003246 if (check_secure())
3247 return;
3248
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003249 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003250
3251 if (argvars[1].v_type != VAR_UNKNOWN)
3252 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003253 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003254 for ( ; *flags != NUL; ++flags)
3255 {
3256 switch (*flags)
3257 {
3258 case 'n': remap = FALSE; break;
3259 case 'm': remap = TRUE; break;
3260 case 't': typed = TRUE; break;
3261 case 'i': insert = TRUE; break;
3262 case 'x': execute = TRUE; break;
3263 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003264 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003265 }
3266 }
3267 }
3268
3269 if (*keys != NUL || execute)
3270 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003271 // Need to escape K_SPECIAL and CSI before putting the string in the
3272 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003273 keys_esc = vim_strsave_escape_csi(keys);
3274 if (keys_esc != NULL)
3275 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003276 if (lowlevel)
3277 {
3278#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01003279 int idx;
3280 int len = (int)STRLEN(keys);
3281
3282 for (idx = 0; idx < len; ++idx)
3283 {
3284 // if a CTRL-C was typed, set got_int, similar to what
3285 // happens in fill_input_buf()
3286 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
3287 got_int = TRUE;
3288 add_to_input_buf(keys + idx, 1);
3289 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003290#else
3291 emsg(_("E980: lowlevel input not supported"));
3292#endif
3293 }
3294 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003295 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003296 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003298 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003299#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003300 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003301#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02003302 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003303 typebuf_was_filled = TRUE;
3304 }
3305 vim_free(keys_esc);
3306
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003307 if (execute)
3308 {
3309 int save_msg_scroll = msg_scroll;
3310
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003311 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312 msg_scroll = FALSE;
3313
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003314 if (!dangerous)
Bram Moolenaar4934ad02020-09-28 22:29:58 +02003315 {
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003316 ++ex_normal_busy;
Bram Moolenaar4934ad02020-09-28 22:29:58 +02003317 ++in_feedkeys;
3318 }
Bram Moolenaar905dd902019-04-07 14:21:47 +02003319 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003320 if (!dangerous)
Bram Moolenaar189832b2020-09-23 12:29:11 +02003321 {
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003322 --ex_normal_busy;
Bram Moolenaar4934ad02020-09-28 22:29:58 +02003323 --in_feedkeys;
Bram Moolenaar189832b2020-09-23 12:29:11 +02003324 }
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003325
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003326 msg_scroll |= save_msg_scroll;
3327 }
3328 }
3329 }
3330}
3331
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003332#ifdef FEAT_FLOAT
3333/*
3334 * "float2nr({float})" function
3335 */
3336 static void
3337f_float2nr(typval_T *argvars, typval_T *rettv)
3338{
3339 float_T f = 0.0;
3340
3341 if (get_float_arg(argvars, &f) == OK)
3342 {
Bram Moolenaar37184272020-05-23 19:30:05 +02003343 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003344 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02003345 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003346 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003347 else
3348 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003349 }
3350}
3351
3352/*
3353 * "floor({float})" function
3354 */
3355 static void
3356f_floor(typval_T *argvars, typval_T *rettv)
3357{
3358 float_T f = 0.0;
3359
3360 rettv->v_type = VAR_FLOAT;
3361 if (get_float_arg(argvars, &f) == OK)
3362 rettv->vval.v_float = floor(f);
3363 else
3364 rettv->vval.v_float = 0.0;
3365}
3366
3367/*
3368 * "fmod()" function
3369 */
3370 static void
3371f_fmod(typval_T *argvars, typval_T *rettv)
3372{
3373 float_T fx = 0.0, fy = 0.0;
3374
3375 rettv->v_type = VAR_FLOAT;
3376 if (get_float_arg(argvars, &fx) == OK
3377 && get_float_arg(&argvars[1], &fy) == OK)
3378 rettv->vval.v_float = fmod(fx, fy);
3379 else
3380 rettv->vval.v_float = 0.0;
3381}
3382#endif
3383
3384/*
3385 * "fnameescape({string})" function
3386 */
3387 static void
3388f_fnameescape(typval_T *argvars, typval_T *rettv)
3389{
3390 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003391 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 rettv->v_type = VAR_STRING;
3393}
3394
3395/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003396 * "foreground()" function
3397 */
3398 static void
3399f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3400{
3401#ifdef FEAT_GUI
3402 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003403 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003404 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003405 return;
3406 }
3407#endif
3408#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003409 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003410#endif
3411}
3412
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003413 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003414common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003415{
3416 char_u *s;
3417 char_u *name;
3418 int use_string = FALSE;
3419 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003420 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003421 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422
3423 if (argvars[0].v_type == VAR_FUNC)
3424 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003425 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426 s = argvars[0].vval.v_string;
3427 }
3428 else if (argvars[0].v_type == VAR_PARTIAL
3429 && argvars[0].vval.v_partial != NULL)
3430 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003431 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003432 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003433 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003434 }
3435 else
3436 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003437 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003438 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003439 use_string = TRUE;
3440 }
3441
Bram Moolenaar843b8842016-08-21 14:36:15 +02003442 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003443 {
3444 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003445 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003446 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3447 if (*name != NUL)
3448 s = NULL;
3449 }
3450
Bram Moolenaar843b8842016-08-21 14:36:15 +02003451 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3452 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003453 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003454 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003455 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003456 ? find_func(trans_name, is_global, NULL) == NULL
3457 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003458 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003459 else
3460 {
3461 int dict_idx = 0;
3462 int arg_idx = 0;
3463 list_T *list = NULL;
3464
3465 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3466 {
3467 char sid_buf[25];
3468 int off = *s == 's' ? 2 : 5;
3469
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003470 // Expand s: and <SID> into <SNR>nr_, so that the function can
3471 // also be called from another script. Using trans_function_name()
3472 // would also work, but some plugins depend on the name being
3473 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003474 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003475 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003476 if (name != NULL)
3477 {
3478 STRCPY(name, sid_buf);
3479 STRCAT(name, s + off);
3480 }
3481 }
3482 else
3483 name = vim_strsave(s);
3484
3485 if (argvars[1].v_type != VAR_UNKNOWN)
3486 {
3487 if (argvars[2].v_type != VAR_UNKNOWN)
3488 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003489 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003490 arg_idx = 1;
3491 dict_idx = 2;
3492 }
3493 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003494 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003495 dict_idx = 1;
3496 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003497 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003498 arg_idx = 1;
3499 if (dict_idx > 0)
3500 {
3501 if (argvars[dict_idx].v_type != VAR_DICT)
3502 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003503 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003504 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003505 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506 }
3507 if (argvars[dict_idx].vval.v_dict == NULL)
3508 dict_idx = 0;
3509 }
3510 if (arg_idx > 0)
3511 {
3512 if (argvars[arg_idx].v_type != VAR_LIST)
3513 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003514 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003515 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003516 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517 }
3518 list = argvars[arg_idx].vval.v_list;
3519 if (list == NULL || list->lv_len == 0)
3520 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01003521 else if (list->lv_len > MAX_FUNC_ARGS)
3522 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01003523 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01003524 vim_free(name);
3525 goto theend;
3526 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003527 }
3528 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003529 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003530 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003531 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003532
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003533 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003534 if (pt == NULL)
3535 vim_free(name);
3536 else
3537 {
3538 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3539 {
3540 listitem_T *li;
3541 int i = 0;
3542 int arg_len = 0;
3543 int lv_len = 0;
3544
3545 if (arg_pt != NULL)
3546 arg_len = arg_pt->pt_argc;
3547 if (list != NULL)
3548 lv_len = list->lv_len;
3549 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003550 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003551 if (pt->pt_argv == NULL)
3552 {
3553 vim_free(pt);
3554 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003555 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003556 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003557 for (i = 0; i < arg_len; i++)
3558 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3559 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003560 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02003561 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003562 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003563 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003564 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565 }
3566
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003567 // For "function(dict.func, [], dict)" and "func" is a partial
3568 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569 if (dict_idx > 0)
3570 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003571 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3573 ++pt->pt_dict->dv_refcount;
3574 }
3575 else if (arg_pt != NULL)
3576 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003577 // If the dict was bound automatically the result is also
3578 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003579 pt->pt_dict = arg_pt->pt_dict;
3580 pt->pt_auto = arg_pt->pt_auto;
3581 if (pt->pt_dict != NULL)
3582 ++pt->pt_dict->dv_refcount;
3583 }
3584
3585 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003586 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3587 {
3588 pt->pt_func = arg_pt->pt_func;
3589 func_ptr_ref(pt->pt_func);
3590 vim_free(name);
3591 }
3592 else if (is_funcref)
3593 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003594 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003595 func_ptr_ref(pt->pt_func);
3596 vim_free(name);
3597 }
3598 else
3599 {
3600 pt->pt_name = name;
3601 func_ref(name);
3602 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603 }
3604 rettv->v_type = VAR_PARTIAL;
3605 rettv->vval.v_partial = pt;
3606 }
3607 else
3608 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003609 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003610 rettv->v_type = VAR_FUNC;
3611 rettv->vval.v_string = name;
3612 func_ref(name);
3613 }
3614 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003615theend:
3616 vim_free(trans_name);
3617}
3618
3619/*
3620 * "funcref()" function
3621 */
3622 static void
3623f_funcref(typval_T *argvars, typval_T *rettv)
3624{
3625 common_function(argvars, rettv, TRUE);
3626}
3627
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01003628 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02003629ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01003630{
3631 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
3632 return &t_func_any;
Bram Moolenaar5e654232020-09-16 15:22:00 +02003633 return &t_func_unknown;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01003634}
3635
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003636/*
3637 * "function()" function
3638 */
3639 static void
3640f_function(typval_T *argvars, typval_T *rettv)
3641{
3642 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643}
3644
3645/*
3646 * "garbagecollect()" function
3647 */
3648 static void
3649f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3650{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003651 // This is postponed until we are back at the toplevel, because we may be
3652 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003653 want_garbage_collect = TRUE;
3654
Bram Moolenaar2df47312020-09-05 17:30:44 +02003655 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656 garbage_collect_at_exit = TRUE;
3657}
3658
3659/*
3660 * "get()" function
3661 */
3662 static void
3663f_get(typval_T *argvars, typval_T *rettv)
3664{
3665 listitem_T *li;
3666 list_T *l;
3667 dictitem_T *di;
3668 dict_T *d;
3669 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003670 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003671
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003672 if (argvars[0].v_type == VAR_BLOB)
3673 {
3674 int error = FALSE;
3675 int idx = tv_get_number_chk(&argvars[1], &error);
3676
3677 if (!error)
3678 {
3679 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003680 if (idx < 0)
3681 idx = blob_len(argvars[0].vval.v_blob) + idx;
3682 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
3683 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003684 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003685 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003686 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003687 tv = rettv;
3688 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003689 }
3690 }
3691 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003692 {
3693 if ((l = argvars[0].vval.v_list) != NULL)
3694 {
3695 int error = FALSE;
3696
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003697 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003698 if (!error && li != NULL)
3699 tv = &li->li_tv;
3700 }
3701 }
3702 else if (argvars[0].v_type == VAR_DICT)
3703 {
3704 if ((d = argvars[0].vval.v_dict) != NULL)
3705 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003706 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707 if (di != NULL)
3708 tv = &di->di_tv;
3709 }
3710 }
3711 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3712 {
3713 partial_T *pt;
3714 partial_T fref_pt;
3715
3716 if (argvars[0].v_type == VAR_PARTIAL)
3717 pt = argvars[0].vval.v_partial;
3718 else
3719 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02003720 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003721 fref_pt.pt_name = argvars[0].vval.v_string;
3722 pt = &fref_pt;
3723 }
3724
3725 if (pt != NULL)
3726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003727 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003728 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003729
3730 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3731 {
3732 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003733 n = partial_name(pt);
3734 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735 rettv->vval.v_string = NULL;
3736 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003737 {
3738 rettv->vval.v_string = vim_strsave(n);
3739 if (rettv->v_type == VAR_FUNC)
3740 func_ref(rettv->vval.v_string);
3741 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742 }
3743 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003744 {
3745 what_is_dict = TRUE;
3746 if (pt->pt_dict != NULL)
3747 rettv_dict_set(rettv, pt->pt_dict);
3748 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003749 else if (STRCMP(what, "args") == 0)
3750 {
3751 rettv->v_type = VAR_LIST;
3752 if (rettv_list_alloc(rettv) == OK)
3753 {
3754 int i;
3755
3756 for (i = 0; i < pt->pt_argc; ++i)
3757 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3758 }
3759 }
3760 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003761 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003762
3763 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3764 // third argument
3765 if (!what_is_dict)
3766 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767 }
3768 }
3769 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003770 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003771
3772 if (tv == NULL)
3773 {
3774 if (argvars[2].v_type != VAR_UNKNOWN)
3775 copy_tv(&argvars[2], rettv);
3776 }
3777 else
3778 copy_tv(tv, rettv);
3779}
3780
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003781/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003782 * "getchangelist()" function
3783 */
3784 static void
3785f_getchangelist(typval_T *argvars, typval_T *rettv)
3786{
3787#ifdef FEAT_JUMPLIST
3788 buf_T *buf;
3789 int i;
3790 list_T *l;
3791 dict_T *d;
3792#endif
3793
3794 if (rettv_list_alloc(rettv) != OK)
3795 return;
3796
3797#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003798 if (argvars[0].v_type == VAR_UNKNOWN)
3799 buf = curbuf;
3800 else
Bram Moolenaara5d38412020-09-02 21:02:35 +02003801 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003802 if (buf == NULL)
3803 return;
3804
3805 l = list_alloc();
3806 if (l == NULL)
3807 return;
3808
3809 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3810 return;
3811 /*
3812 * The current window change list index tracks only the position in the
3813 * current buffer change list. For other buffers, use the change list
3814 * length as the current index.
3815 */
3816 list_append_number(rettv->vval.v_list,
3817 (varnumber_T)((buf == curwin->w_buffer)
3818 ? curwin->w_changelistidx : buf->b_changelistlen));
3819
3820 for (i = 0; i < buf->b_changelistlen; ++i)
3821 {
3822 if (buf->b_changelist[i].lnum == 0)
3823 continue;
3824 if ((d = dict_alloc()) == NULL)
3825 return;
3826 if (list_append_dict(l, d) == FAIL)
3827 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003828 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3829 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003830 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003831 }
3832#endif
3833}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834
3835/*
3836 * "getcharsearch()" function
3837 */
3838 static void
3839f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3840{
3841 if (rettv_dict_alloc(rettv) != FAIL)
3842 {
3843 dict_T *dict = rettv->vval.v_dict;
3844
Bram Moolenaare0be1672018-07-08 16:50:37 +02003845 dict_add_string(dict, "char", last_csearch());
3846 dict_add_number(dict, "forward", last_csearch_forward());
3847 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003848 }
3849}
3850
3851/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003852 * "getenv()" function
3853 */
3854 static void
3855f_getenv(typval_T *argvars, typval_T *rettv)
3856{
3857 int mustfree = FALSE;
3858 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3859
3860 if (p == NULL)
3861 {
3862 rettv->v_type = VAR_SPECIAL;
3863 rettv->vval.v_number = VVAL_NULL;
3864 return;
3865 }
3866 if (!mustfree)
3867 p = vim_strsave(p);
3868 rettv->vval.v_string = p;
3869 rettv->v_type = VAR_STRING;
3870}
3871
3872/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003873 * "getfontname()" function
3874 */
3875 static void
3876f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3877{
3878 rettv->v_type = VAR_STRING;
3879 rettv->vval.v_string = NULL;
3880#ifdef FEAT_GUI
3881 if (gui.in_use)
3882 {
3883 GuiFont font;
3884 char_u *name = NULL;
3885
3886 if (argvars[0].v_type == VAR_UNKNOWN)
3887 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003888 // Get the "Normal" font. Either the name saved by
3889 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003890 font = gui.norm_font;
3891 name = hl_get_font_name();
3892 }
3893 else
3894 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003895 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003896 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003897 return;
3898 font = gui_mch_get_font(name, FALSE);
3899 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003900 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003901 }
3902 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3903 if (argvars[0].v_type != VAR_UNKNOWN)
3904 gui_mch_free_font(font);
3905 }
3906#endif
3907}
3908
3909/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003910 * "getjumplist()" function
3911 */
3912 static void
3913f_getjumplist(typval_T *argvars, typval_T *rettv)
3914{
3915#ifdef FEAT_JUMPLIST
3916 win_T *wp;
3917 int i;
3918 list_T *l;
3919 dict_T *d;
3920#endif
3921
3922 if (rettv_list_alloc(rettv) != OK)
3923 return;
3924
3925#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003926 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003927 if (wp == NULL)
3928 return;
3929
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003930 cleanup_jumplist(wp, TRUE);
3931
Bram Moolenaar4f505882018-02-10 21:06:32 +01003932 l = list_alloc();
3933 if (l == NULL)
3934 return;
3935
3936 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3937 return;
3938 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3939
3940 for (i = 0; i < wp->w_jumplistlen; ++i)
3941 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003942 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3943 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003944 if ((d = dict_alloc()) == NULL)
3945 return;
3946 if (list_append_dict(l, d) == FAIL)
3947 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003948 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3949 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003950 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003951 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003952 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003953 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003954 }
3955#endif
3956}
3957
3958/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003959 * "getpid()" function
3960 */
3961 static void
3962f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3963{
3964 rettv->vval.v_number = mch_get_pid();
3965}
3966
3967 static void
3968getpos_both(
3969 typval_T *argvars,
3970 typval_T *rettv,
3971 int getcurpos)
3972{
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003973 pos_T *fp = NULL;
3974 win_T *wp = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003975 list_T *l;
3976 int fnum = -1;
3977
3978 if (rettv_list_alloc(rettv) == OK)
3979 {
3980 l = rettv->vval.v_list;
3981 if (getcurpos)
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003982 {
3983 if (argvars[0].v_type != VAR_UNKNOWN)
3984 {
3985 wp = find_win_by_nr_or_id(&argvars[0]);
3986 if (wp != NULL)
3987 fp = &wp->w_cursor;
3988 }
3989 else
3990 fp = &curwin->w_cursor;
3991 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003992 else
3993 fp = var2fpos(&argvars[0], TRUE, &fnum);
3994 if (fnum != -1)
3995 list_append_number(l, (varnumber_T)fnum);
3996 else
3997 list_append_number(l, (varnumber_T)0);
3998 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3999 : (varnumber_T)0);
4000 list_append_number(l, (fp != NULL)
4001 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4002 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01004003 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004004 (varnumber_T)0);
4005 if (getcurpos)
4006 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01004007 int save_set_curswant = curwin->w_set_curswant;
4008 colnr_T save_curswant = curwin->w_curswant;
4009 colnr_T save_virtcol = curwin->w_virtcol;
4010
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02004011 if (wp == curwin)
4012 update_curswant();
4013 list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
4014 ? (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01004015
4016 // Do not change "curswant", as it is unexpected that a get
4017 // function has a side effect.
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02004018 if (wp == curwin && save_set_curswant)
Bram Moolenaar19a66852019-03-07 11:25:32 +01004019 {
4020 curwin->w_set_curswant = save_set_curswant;
4021 curwin->w_curswant = save_curswant;
4022 curwin->w_virtcol = save_virtcol;
4023 curwin->w_valid &= ~VALID_VIRTCOL;
4024 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004025 }
4026 }
4027 else
4028 rettv->vval.v_number = FALSE;
4029}
4030
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004031/*
4032 * "getcurpos()" function
4033 */
4034 static void
4035f_getcurpos(typval_T *argvars, typval_T *rettv)
4036{
4037 getpos_both(argvars, rettv, TRUE);
4038}
4039
4040/*
4041 * "getpos(string)" function
4042 */
4043 static void
4044f_getpos(typval_T *argvars, typval_T *rettv)
4045{
4046 getpos_both(argvars, rettv, FALSE);
4047}
4048
4049/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004050 * "getreg()" function
4051 */
4052 static void
4053f_getreg(typval_T *argvars, typval_T *rettv)
4054{
4055 char_u *strregname;
4056 int regname;
4057 int arg2 = FALSE;
4058 int return_list = FALSE;
4059 int error = FALSE;
4060
4061 if (argvars[0].v_type != VAR_UNKNOWN)
4062 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004063 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004064 error = strregname == NULL;
4065 if (argvars[1].v_type != VAR_UNKNOWN)
4066 {
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02004067 arg2 = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004068 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02004069 return_list = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 }
4071 }
4072 else
4073 strregname = get_vim_var_str(VV_REG);
4074
4075 if (error)
4076 return;
4077
4078 regname = (strregname == NULL ? '"' : *strregname);
4079 if (regname == 0)
4080 regname = '"';
4081
4082 if (return_list)
4083 {
4084 rettv->v_type = VAR_LIST;
4085 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4086 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4087 if (rettv->vval.v_list == NULL)
4088 (void)rettv_list_alloc(rettv);
4089 else
4090 ++rettv->vval.v_list->lv_refcount;
4091 }
4092 else
4093 {
4094 rettv->v_type = VAR_STRING;
4095 rettv->vval.v_string = get_reg_contents(regname,
4096 arg2 ? GREG_EXPR_SRC : 0);
4097 }
4098}
4099
4100/*
4101 * "getregtype()" function
4102 */
4103 static void
4104f_getregtype(typval_T *argvars, typval_T *rettv)
4105{
4106 char_u *strregname;
4107 int regname;
4108 char_u buf[NUMBUFLEN + 2];
4109 long reglen = 0;
4110
4111 if (argvars[0].v_type != VAR_UNKNOWN)
4112 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004113 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004114 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004115 {
4116 rettv->v_type = VAR_STRING;
4117 rettv->vval.v_string = NULL;
4118 return;
4119 }
4120 }
4121 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004122 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004123 strregname = get_vim_var_str(VV_REG);
4124
4125 regname = (strregname == NULL ? '"' : *strregname);
4126 if (regname == 0)
4127 regname = '"';
4128
4129 buf[0] = NUL;
4130 buf[1] = NUL;
4131 switch (get_reg_type(regname, &reglen))
4132 {
4133 case MLINE: buf[0] = 'V'; break;
4134 case MCHAR: buf[0] = 'v'; break;
4135 case MBLOCK:
4136 buf[0] = Ctrl_V;
4137 sprintf((char *)buf + 1, "%ld", reglen + 1);
4138 break;
4139 }
4140 rettv->v_type = VAR_STRING;
4141 rettv->vval.v_string = vim_strsave(buf);
4142}
4143
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004144/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01004145 * "gettagstack()" function
4146 */
4147 static void
4148f_gettagstack(typval_T *argvars, typval_T *rettv)
4149{
4150 win_T *wp = curwin; // default is current window
4151
4152 if (rettv_dict_alloc(rettv) != OK)
4153 return;
4154
4155 if (argvars[0].v_type != VAR_UNKNOWN)
4156 {
4157 wp = find_win_by_nr_or_id(&argvars[0]);
4158 if (wp == NULL)
4159 return;
4160 }
4161
4162 get_tagstack(wp, rettv->vval.v_dict);
4163}
4164
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +02004165/*
4166 * "gettext()" function
4167 */
4168 static void
4169f_gettext(typval_T *argvars, typval_T *rettv)
4170{
4171 if (argvars[0].v_type != VAR_STRING
4172 || argvars[0].vval.v_string == NULL
4173 || *argvars[0].vval.v_string == NUL)
4174 {
4175 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
4176 }
4177 else
4178 {
4179 rettv->v_type = VAR_STRING;
4180 rettv->vval.v_string = vim_strsave(
4181 (char_u *)_(argvars[0].vval.v_string));
4182 }
4183}
4184
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004185// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004186#include "version.h"
4187
4188/*
4189 * "has()" function
4190 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01004191 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004192f_has(typval_T *argvars, typval_T *rettv)
4193{
4194 int i;
4195 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01004196 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004197 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01004198 typedef struct {
4199 char *name;
4200 short present;
4201 } has_item_T;
4202 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004204 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004205#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01004206 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004207#else
Bram Moolenaar79296512020-03-22 16:17:14 +01004208 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004209#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004210 },
4211 {"arp",
4212#if defined(AMIGA) && defined(FEAT_ARP)
4213 1
4214#else
4215 0
4216#endif
4217 },
Bram Moolenaar79296512020-03-22 16:17:14 +01004218 {"haiku",
4219#ifdef __HAIKU__
4220 1
4221#else
4222 0
4223#endif
4224 },
4225 {"bsd",
4226#if defined(BSD) && !defined(MACOS_X)
4227 1
4228#else
4229 0
4230#endif
4231 },
4232 {"hpux",
4233#ifdef hpux
4234 1
4235#else
4236 0
4237#endif
4238 },
4239 {"linux",
4240#ifdef __linux__
4241 1
4242#else
4243 0
4244#endif
4245 },
4246 {"mac", // Mac OS X (and, once, Mac OS Classic)
4247#ifdef MACOS_X
4248 1
4249#else
4250 0
4251#endif
4252 },
4253 {"osx", // Mac OS X
4254#ifdef MACOS_X
4255 1
4256#else
4257 0
4258#endif
4259 },
4260 {"macunix", // Mac OS X, with the darwin feature
4261#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4262 1
4263#else
4264 0
4265#endif
4266 },
4267 {"osxdarwin", // synonym for macunix
4268#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4269 1
4270#else
4271 0
4272#endif
4273 },
4274 {"qnx",
4275#ifdef __QNX__
4276 1
4277#else
4278 0
4279#endif
4280 },
4281 {"sun",
4282#ifdef SUN_SYSTEM
4283 1
4284#else
4285 0
4286#endif
4287 },
4288 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004289#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01004290 1
4291#else
4292 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004293#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004294 },
4295 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01004297 1
4298#else
4299 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004300#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004301 },
4302 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01004303#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01004304 1
4305#else
4306 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004308 },
4309 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01004310#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01004311 1
4312#else
4313 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004314#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004315 },
4316 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01004317#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01004318 1
4319#else
4320 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004321#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004322 },
4323 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004324#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01004325 1
4326#else
4327 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004328#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004329 },
4330 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004331#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01004332 1
4333#else
4334 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004335#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004336 },
4337 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004338#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01004339 1
4340#else
4341 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004342#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004343 },
4344 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004345#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01004346 1
4347#else
4348 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004349#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004350 },
4351 {"autocmd", 1},
4352 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004353#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01004354 1
4355#else
4356 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004357#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004358 },
4359 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01004360#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01004361 1
4362#else
4363 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01004364#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004365 },
4366 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004367#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01004368 1
4369#else
4370 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004371#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004372 },
4373 {"balloon_multiline",
4374#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
4375 // MS-Windows requires runtime check, see below
4376 1
4377#else
4378 0
4379#endif
4380 },
4381 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004382#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01004383 1
4384#else
4385 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01004386#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004387 },
4388 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004389#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01004390 1
4391#else
4392 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004393#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004394 },
4395 {"all_builtin_terms",
4396#if defined(ALL_BUILTIN_TCAPS)
4397 1
4398#else
4399 0
4400#endif
4401 },
4402 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004403#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01004404 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004405 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01004406 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004407#else
Bram Moolenaar79296512020-03-22 16:17:14 +01004408 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004409#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004410 },
4411 {"byte_offset",
4412#ifdef FEAT_BYTEOFF
4413 1
4414#else
4415 0
4416#endif
4417 },
4418 {"channel",
4419#ifdef FEAT_JOB_CHANNEL
4420 1
4421#else
4422 0
4423#endif
4424 },
4425 {"cindent",
4426#ifdef FEAT_CINDENT
4427 1
4428#else
4429 0
4430#endif
4431 },
4432 {"clientserver",
4433#ifdef FEAT_CLIENTSERVER
4434 1
4435#else
4436 0
4437#endif
4438 },
4439 {"clipboard",
4440#ifdef FEAT_CLIPBOARD
4441 1
4442#else
4443 0
4444#endif
4445 },
4446 {"cmdline_compl", 1},
4447 {"cmdline_hist", 1},
4448 {"comments", 1},
4449 {"conceal",
4450#ifdef FEAT_CONCEAL
4451 1
4452#else
4453 0
4454#endif
4455 },
4456 {"cryptv",
4457#ifdef FEAT_CRYPT
4458 1
4459#else
4460 0
4461#endif
4462 },
4463 {"crypt-blowfish",
4464#ifdef FEAT_CRYPT
4465 1
4466#else
4467 0
4468#endif
4469 },
4470 {"crypt-blowfish2",
4471#ifdef FEAT_CRYPT
4472 1
4473#else
4474 0
4475#endif
4476 },
4477 {"cscope",
4478#ifdef FEAT_CSCOPE
4479 1
4480#else
4481 0
4482#endif
4483 },
4484 {"cursorbind", 1},
4485 {"cursorshape",
4486#ifdef CURSOR_SHAPE
4487 1
4488#else
4489 0
4490#endif
4491 },
4492 {"debug",
4493#ifdef DEBUG
4494 1
4495#else
4496 0
4497#endif
4498 },
4499 {"dialog_con",
4500#ifdef FEAT_CON_DIALOG
4501 1
4502#else
4503 0
4504#endif
4505 },
4506 {"dialog_gui",
4507#ifdef FEAT_GUI_DIALOG
4508 1
4509#else
4510 0
4511#endif
4512 },
4513 {"diff",
4514#ifdef FEAT_DIFF
4515 1
4516#else
4517 0
4518#endif
4519 },
4520 {"digraphs",
4521#ifdef FEAT_DIGRAPHS
4522 1
4523#else
4524 0
4525#endif
4526 },
4527 {"directx",
4528#ifdef FEAT_DIRECTX
4529 1
4530#else
4531 0
4532#endif
4533 },
4534 {"dnd",
4535#ifdef FEAT_DND
4536 1
4537#else
4538 0
4539#endif
4540 },
4541 {"emacs_tags",
4542#ifdef FEAT_EMACS_TAGS
4543 1
4544#else
4545 0
4546#endif
4547 },
4548 {"eval", 1}, // always present, of course!
4549 {"ex_extra", 1}, // graduated feature
4550 {"extra_search",
4551#ifdef FEAT_SEARCH_EXTRA
4552 1
4553#else
4554 0
4555#endif
4556 },
4557 {"file_in_path",
4558#ifdef FEAT_SEARCHPATH
4559 1
4560#else
4561 0
4562#endif
4563 },
4564 {"filterpipe",
4565#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
4566 1
4567#else
4568 0
4569#endif
4570 },
4571 {"find_in_path",
4572#ifdef FEAT_FIND_ID
4573 1
4574#else
4575 0
4576#endif
4577 },
4578 {"float",
4579#ifdef FEAT_FLOAT
4580 1
4581#else
4582 0
4583#endif
4584 },
4585 {"folding",
4586#ifdef FEAT_FOLDING
4587 1
4588#else
4589 0
4590#endif
4591 },
4592 {"footer",
4593#ifdef FEAT_FOOTER
4594 1
4595#else
4596 0
4597#endif
4598 },
4599 {"fork",
4600#if !defined(USE_SYSTEM) && defined(UNIX)
4601 1
4602#else
4603 0
4604#endif
4605 },
4606 {"gettext",
4607#ifdef FEAT_GETTEXT
4608 1
4609#else
4610 0
4611#endif
4612 },
4613 {"gui",
4614#ifdef FEAT_GUI
4615 1
4616#else
4617 0
4618#endif
4619 },
4620 {"gui_neXtaw",
4621#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
4622 1
4623#else
4624 0
4625#endif
4626 },
4627 {"gui_athena",
4628#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
4629 1
4630#else
4631 0
4632#endif
4633 },
4634 {"gui_gtk",
4635#ifdef FEAT_GUI_GTK
4636 1
4637#else
4638 0
4639#endif
4640 },
4641 {"gui_gtk2",
4642#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
4643 1
4644#else
4645 0
4646#endif
4647 },
4648 {"gui_gtk3",
4649#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
4650 1
4651#else
4652 0
4653#endif
4654 },
4655 {"gui_gnome",
4656#ifdef FEAT_GUI_GNOME
4657 1
4658#else
4659 0
4660#endif
4661 },
4662 {"gui_haiku",
4663#ifdef FEAT_GUI_HAIKU
4664 1
4665#else
4666 0
4667#endif
4668 },
Bram Moolenaar097148e2020-08-11 21:58:20 +02004669 {"gui_mac", 0},
Bram Moolenaar79296512020-03-22 16:17:14 +01004670 {"gui_motif",
4671#ifdef FEAT_GUI_MOTIF
4672 1
4673#else
4674 0
4675#endif
4676 },
4677 {"gui_photon",
4678#ifdef FEAT_GUI_PHOTON
4679 1
4680#else
4681 0
4682#endif
4683 },
4684 {"gui_win32",
4685#ifdef FEAT_GUI_MSWIN
4686 1
4687#else
4688 0
4689#endif
4690 },
4691 {"iconv",
4692#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
4693 1
4694#else
4695 0
4696#endif
4697 },
4698 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02004699 {"ipv6",
4700#ifdef FEAT_IPV6
4701 1
4702#else
4703 0
4704#endif
4705 },
Bram Moolenaar79296512020-03-22 16:17:14 +01004706 {"job",
4707#ifdef FEAT_JOB_CHANNEL
4708 1
4709#else
4710 0
4711#endif
4712 },
4713 {"jumplist",
4714#ifdef FEAT_JUMPLIST
4715 1
4716#else
4717 0
4718#endif
4719 },
4720 {"keymap",
4721#ifdef FEAT_KEYMAP
4722 1
4723#else
4724 0
4725#endif
4726 },
4727 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
4728 {"langmap",
4729#ifdef FEAT_LANGMAP
4730 1
4731#else
4732 0
4733#endif
4734 },
4735 {"libcall",
4736#ifdef FEAT_LIBCALL
4737 1
4738#else
4739 0
4740#endif
4741 },
4742 {"linebreak",
4743#ifdef FEAT_LINEBREAK
4744 1
4745#else
4746 0
4747#endif
4748 },
4749 {"lispindent",
4750#ifdef FEAT_LISP
4751 1
4752#else
4753 0
4754#endif
4755 },
4756 {"listcmds", 1},
4757 {"localmap", 1},
4758 {"lua",
4759#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
4760 1
4761#else
4762 0
4763#endif
4764 },
4765 {"menu",
4766#ifdef FEAT_MENU
4767 1
4768#else
4769 0
4770#endif
4771 },
4772 {"mksession",
4773#ifdef FEAT_SESSION
4774 1
4775#else
4776 0
4777#endif
4778 },
4779 {"modify_fname", 1},
4780 {"mouse", 1},
4781 {"mouseshape",
4782#ifdef FEAT_MOUSESHAPE
4783 1
4784#else
4785 0
4786#endif
4787 },
4788 {"mouse_dec",
4789#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
4790 1
4791#else
4792 0
4793#endif
4794 },
4795 {"mouse_gpm",
4796#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
4797 1
4798#else
4799 0
4800#endif
4801 },
4802 {"mouse_jsbterm",
4803#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
4804 1
4805#else
4806 0
4807#endif
4808 },
4809 {"mouse_netterm",
4810#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
4811 1
4812#else
4813 0
4814#endif
4815 },
4816 {"mouse_pterm",
4817#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
4818 1
4819#else
4820 0
4821#endif
4822 },
4823 {"mouse_sgr",
4824#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4825 1
4826#else
4827 0
4828#endif
4829 },
4830 {"mouse_sysmouse",
4831#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4832 1
4833#else
4834 0
4835#endif
4836 },
4837 {"mouse_urxvt",
4838#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4839 1
4840#else
4841 0
4842#endif
4843 },
4844 {"mouse_xterm",
4845#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4846 1
4847#else
4848 0
4849#endif
4850 },
4851 {"multi_byte", 1},
4852 {"multi_byte_ime",
4853#ifdef FEAT_MBYTE_IME
4854 1
4855#else
4856 0
4857#endif
4858 },
4859 {"multi_lang",
4860#ifdef FEAT_MULTI_LANG
4861 1
4862#else
4863 0
4864#endif
4865 },
4866 {"mzscheme",
4867#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4868 1
4869#else
4870 0
4871#endif
4872 },
4873 {"num64", 1},
4874 {"ole",
4875#ifdef FEAT_OLE
4876 1
4877#else
4878 0
4879#endif
4880 },
4881 {"packages",
4882#ifdef FEAT_EVAL
4883 1
4884#else
4885 0
4886#endif
4887 },
4888 {"path_extra",
4889#ifdef FEAT_PATH_EXTRA
4890 1
4891#else
4892 0
4893#endif
4894 },
4895 {"perl",
4896#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4897 1
4898#else
4899 0
4900#endif
4901 },
4902 {"persistent_undo",
4903#ifdef FEAT_PERSISTENT_UNDO
4904 1
4905#else
4906 0
4907#endif
4908 },
4909 {"python_compiled",
4910#if defined(FEAT_PYTHON)
4911 1
4912#else
4913 0
4914#endif
4915 },
4916 {"python_dynamic",
4917#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4918 1
4919#else
4920 0
4921#endif
4922 },
4923 {"python",
4924#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4925 1
4926#else
4927 0
4928#endif
4929 },
4930 {"pythonx",
4931#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4932 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4933 1
4934#else
4935 0
4936#endif
4937 },
4938 {"python3_compiled",
4939#if defined(FEAT_PYTHON3)
4940 1
4941#else
4942 0
4943#endif
4944 },
4945 {"python3_dynamic",
4946#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4947 1
4948#else
4949 0
4950#endif
4951 },
4952 {"python3",
4953#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4954 1
4955#else
4956 0
4957#endif
4958 },
4959 {"popupwin",
4960#ifdef FEAT_PROP_POPUP
4961 1
4962#else
4963 0
4964#endif
4965 },
4966 {"postscript",
4967#ifdef FEAT_POSTSCRIPT
4968 1
4969#else
4970 0
4971#endif
4972 },
4973 {"printer",
4974#ifdef FEAT_PRINTER
4975 1
4976#else
4977 0
4978#endif
4979 },
4980 {"profile",
4981#ifdef FEAT_PROFILE
4982 1
4983#else
4984 0
4985#endif
4986 },
4987 {"reltime",
4988#ifdef FEAT_RELTIME
4989 1
4990#else
4991 0
4992#endif
4993 },
4994 {"quickfix",
4995#ifdef FEAT_QUICKFIX
4996 1
4997#else
4998 0
4999#endif
5000 },
5001 {"rightleft",
5002#ifdef FEAT_RIGHTLEFT
5003 1
5004#else
5005 0
5006#endif
5007 },
5008 {"ruby",
5009#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5010 1
5011#else
5012 0
5013#endif
5014 },
5015 {"scrollbind", 1},
5016 {"showcmd",
5017#ifdef FEAT_CMDL_INFO
5018 1
5019#else
5020 0
5021#endif
5022 },
5023 {"cmdline_info",
5024#ifdef FEAT_CMDL_INFO
5025 1
5026#else
5027 0
5028#endif
5029 },
5030 {"signs",
5031#ifdef FEAT_SIGNS
5032 1
5033#else
5034 0
5035#endif
5036 },
5037 {"smartindent",
5038#ifdef FEAT_SMARTINDENT
5039 1
5040#else
5041 0
5042#endif
5043 },
5044 {"startuptime",
5045#ifdef STARTUPTIME
5046 1
5047#else
5048 0
5049#endif
5050 },
5051 {"statusline",
5052#ifdef FEAT_STL_OPT
5053 1
5054#else
5055 0
5056#endif
5057 },
5058 {"netbeans_intg",
5059#ifdef FEAT_NETBEANS_INTG
5060 1
5061#else
5062 0
5063#endif
5064 },
5065 {"sound",
5066#ifdef FEAT_SOUND
5067 1
5068#else
5069 0
5070#endif
5071 },
5072 {"spell",
5073#ifdef FEAT_SPELL
5074 1
5075#else
5076 0
5077#endif
5078 },
5079 {"syntax",
5080#ifdef FEAT_SYN_HL
5081 1
5082#else
5083 0
5084#endif
5085 },
5086 {"system",
5087#if defined(USE_SYSTEM) || !defined(UNIX)
5088 1
5089#else
5090 0
5091#endif
5092 },
5093 {"tag_binary",
5094#ifdef FEAT_TAG_BINS
5095 1
5096#else
5097 0
5098#endif
5099 },
5100 {"tcl",
5101#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
5102 1
5103#else
5104 0
5105#endif
5106 },
5107 {"termguicolors",
5108#ifdef FEAT_TERMGUICOLORS
5109 1
5110#else
5111 0
5112#endif
5113 },
5114 {"terminal",
5115#if defined(FEAT_TERMINAL) && !defined(MSWIN)
5116 1
5117#else
5118 0
5119#endif
5120 },
5121 {"terminfo",
5122#ifdef TERMINFO
5123 1
5124#else
5125 0
5126#endif
5127 },
5128 {"termresponse",
5129#ifdef FEAT_TERMRESPONSE
5130 1
5131#else
5132 0
5133#endif
5134 },
5135 {"textobjects",
5136#ifdef FEAT_TEXTOBJ
5137 1
5138#else
5139 0
5140#endif
5141 },
5142 {"textprop",
5143#ifdef FEAT_PROP_POPUP
5144 1
5145#else
5146 0
5147#endif
5148 },
5149 {"tgetent",
5150#ifdef HAVE_TGETENT
5151 1
5152#else
5153 0
5154#endif
5155 },
5156 {"timers",
5157#ifdef FEAT_TIMERS
5158 1
5159#else
5160 0
5161#endif
5162 },
5163 {"title",
5164#ifdef FEAT_TITLE
5165 1
5166#else
5167 0
5168#endif
5169 },
5170 {"toolbar",
5171#ifdef FEAT_TOOLBAR
5172 1
5173#else
5174 0
5175#endif
5176 },
5177 {"unnamedplus",
5178#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5179 1
5180#else
5181 0
5182#endif
5183 },
5184 {"user-commands", 1}, // was accidentally included in 5.4
5185 {"user_commands", 1},
5186 {"vartabs",
5187#ifdef FEAT_VARTABS
5188 1
5189#else
5190 0
5191#endif
5192 },
5193 {"vertsplit", 1},
5194 {"viminfo",
5195#ifdef FEAT_VIMINFO
5196 1
5197#else
5198 0
5199#endif
5200 },
5201 {"vimscript-1", 1},
5202 {"vimscript-2", 1},
5203 {"vimscript-3", 1},
5204 {"vimscript-4", 1},
5205 {"virtualedit", 1},
5206 {"visual", 1},
5207 {"visualextra", 1},
5208 {"vreplace", 1},
5209 {"vtp",
5210#ifdef FEAT_VTP
5211 1
5212#else
5213 0
5214#endif
5215 },
5216 {"wildignore",
5217#ifdef FEAT_WILDIGN
5218 1
5219#else
5220 0
5221#endif
5222 },
5223 {"wildmenu",
5224#ifdef FEAT_WILDMENU
5225 1
5226#else
5227 0
5228#endif
5229 },
5230 {"windows", 1},
5231 {"winaltkeys",
5232#ifdef FEAT_WAK
5233 1
5234#else
5235 0
5236#endif
5237 },
5238 {"writebackup",
5239#ifdef FEAT_WRITEBACKUP
5240 1
5241#else
5242 0
5243#endif
5244 },
5245 {"xim",
5246#ifdef FEAT_XIM
5247 1
5248#else
5249 0
5250#endif
5251 },
5252 {"xfontset",
5253#ifdef FEAT_XFONTSET
5254 1
5255#else
5256 0
5257#endif
5258 },
5259 {"xpm",
5260#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
5261 1
5262#else
5263 0
5264#endif
5265 },
5266 {"xpm_w32", // for backward compatibility
5267#ifdef FEAT_XPM_W32
5268 1
5269#else
5270 0
5271#endif
5272 },
5273 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005274#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01005275 1
5276#else
5277 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005278#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005279 },
5280 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005281#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01005282 1
5283#else
5284 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005285#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005286 },
5287 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01005289 1
5290#else
5291 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005293 },
5294 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005295#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01005296 1
5297#else
5298 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005299#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005300 },
5301 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005302#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01005303 1
5304#else
5305 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005307 },
5308 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005309 };
5310
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005311 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01005312 for (i = 0; has_list[i].name != NULL; ++i)
5313 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005314 {
Bram Moolenaar79296512020-03-22 16:17:14 +01005315 x = TRUE;
5316 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005317 break;
5318 }
5319
Bram Moolenaar79296512020-03-22 16:17:14 +01005320 // features also in has_list[] but sometimes enabled at runtime
5321 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005322 {
Bram Moolenaar79296512020-03-22 16:17:14 +01005323 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02005324 {
5325 // intentionally empty
5326 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005327#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005328 else if (STRICMP(name, "balloon_multiline") == 0)
5329 n = multiline_balloon_available();
5330#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005331#ifdef VIMDLL
5332 else if (STRICMP(name, "filterpipe") == 0)
5333 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005334#endif
5335#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5336 else if (STRICMP(name, "iconv") == 0)
5337 n = iconv_enabled(FALSE);
5338#endif
5339#ifdef DYNAMIC_LUA
5340 else if (STRICMP(name, "lua") == 0)
5341 n = lua_enabled(FALSE);
5342#endif
5343#ifdef DYNAMIC_MZSCHEME
5344 else if (STRICMP(name, "mzscheme") == 0)
5345 n = mzscheme_enabled(FALSE);
5346#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005347#ifdef DYNAMIC_PERL
5348 else if (STRICMP(name, "perl") == 0)
5349 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005350#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005351#ifdef DYNAMIC_PYTHON
5352 else if (STRICMP(name, "python") == 0)
5353 n = python_enabled(FALSE);
5354#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005355#ifdef DYNAMIC_PYTHON3
5356 else if (STRICMP(name, "python3") == 0)
5357 n = python3_enabled(FALSE);
5358#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005359#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5360 else if (STRICMP(name, "pythonx") == 0)
5361 {
5362# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
5363 if (p_pyx == 0)
5364 n = python3_enabled(FALSE) || python_enabled(FALSE);
5365 else if (p_pyx == 3)
5366 n = python3_enabled(FALSE);
5367 else if (p_pyx == 2)
5368 n = python_enabled(FALSE);
5369# elif defined(DYNAMIC_PYTHON)
5370 n = python_enabled(FALSE);
5371# elif defined(DYNAMIC_PYTHON3)
5372 n = python3_enabled(FALSE);
5373# endif
5374 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005375#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005376#ifdef DYNAMIC_RUBY
5377 else if (STRICMP(name, "ruby") == 0)
5378 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005380#ifdef DYNAMIC_TCL
5381 else if (STRICMP(name, "tcl") == 0)
5382 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02005383#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005384#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02005385 else if (STRICMP(name, "terminal") == 0)
5386 n = terminal_enabled();
5387#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005388 }
5389
Bram Moolenaar79296512020-03-22 16:17:14 +01005390 // features not in has_list[]
5391 if (x == FALSE)
5392 {
5393 if (STRNICMP(name, "patch", 5) == 0)
5394 {
5395 x = TRUE;
5396 if (name[5] == '-'
5397 && STRLEN(name) >= 11
5398 && vim_isdigit(name[6])
5399 && vim_isdigit(name[8])
5400 && vim_isdigit(name[10]))
5401 {
5402 int major = atoi((char *)name + 6);
5403 int minor = atoi((char *)name + 8);
5404
5405 // Expect "patch-9.9.01234".
5406 n = (major < VIM_VERSION_MAJOR
5407 || (major == VIM_VERSION_MAJOR
5408 && (minor < VIM_VERSION_MINOR
5409 || (minor == VIM_VERSION_MINOR
5410 && has_patch(atoi((char *)name + 10))))));
5411 }
5412 else
5413 n = has_patch(atoi((char *)name + 5));
5414 }
5415 else if (STRICMP(name, "vim_starting") == 0)
5416 {
5417 x = TRUE;
5418 n = (starting != 0);
5419 }
5420 else if (STRICMP(name, "ttyin") == 0)
5421 {
5422 x = TRUE;
5423 n = mch_input_isatty();
5424 }
5425 else if (STRICMP(name, "ttyout") == 0)
5426 {
5427 x = TRUE;
5428 n = stdout_isatty;
5429 }
5430 else if (STRICMP(name, "multi_byte_encoding") == 0)
5431 {
5432 x = TRUE;
5433 n = has_mbyte;
5434 }
5435 else if (STRICMP(name, "gui_running") == 0)
5436 {
5437 x = TRUE;
5438#ifdef FEAT_GUI
5439 n = (gui.in_use || gui.starting);
5440#endif
5441 }
5442 else if (STRICMP(name, "browse") == 0)
5443 {
5444 x = TRUE;
5445#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
5446 n = gui.in_use; // gui_mch_browse() works when GUI is running
5447#endif
5448 }
5449 else if (STRICMP(name, "syntax_items") == 0)
5450 {
5451 x = TRUE;
5452#ifdef FEAT_SYN_HL
5453 n = syntax_present(curwin);
5454#endif
5455 }
5456 else if (STRICMP(name, "vcon") == 0)
5457 {
5458 x = TRUE;
5459#ifdef FEAT_VTP
5460 n = is_term_win32() && has_vtp_working();
5461#endif
5462 }
5463 else if (STRICMP(name, "netbeans_enabled") == 0)
5464 {
5465 x = TRUE;
5466#ifdef FEAT_NETBEANS_INTG
5467 n = netbeans_active();
5468#endif
5469 }
5470 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
5471 {
5472 x = TRUE;
5473#ifdef FEAT_MOUSE_GPM
5474 n = gpm_enabled();
5475#endif
5476 }
5477 else if (STRICMP(name, "conpty") == 0)
5478 {
5479 x = TRUE;
5480#if defined(FEAT_TERMINAL) && defined(MSWIN)
5481 n = use_conpty();
5482#endif
5483 }
5484 else if (STRICMP(name, "clipboard_working") == 0)
5485 {
5486 x = TRUE;
5487#ifdef FEAT_CLIPBOARD
5488 n = clip_star.available;
5489#endif
5490 }
5491 }
5492
Bram Moolenaar04637e22020-09-05 18:45:29 +02005493 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]))
Bram Moolenaar79296512020-03-22 16:17:14 +01005494 // return whether feature could ever be enabled
5495 rettv->vval.v_number = x;
5496 else
5497 // return whether feature is enabled
5498 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005499}
5500
5501/*
Bram Moolenaar8cebd432020-11-08 12:49:47 +01005502 * Return TRUE if "feature" can change later.
5503 * Also when checking for the feature has side effects, such as loading a DLL.
5504 */
5505 int
5506dynamic_feature(char_u *feature)
5507{
5508 return (feature == NULL
5509#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
5510 || STRICMP(feature, "balloon_multiline") == 0
5511#endif
5512#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
5513 || (STRICMP(feature, "browse") == 0 && !gui.in_use)
5514#endif
5515#ifdef VIMDLL
5516 || STRICMP(feature, "filterpipe") == 0
5517#endif
Bram Moolenaar29b281b2020-11-10 20:58:00 +01005518#if defined(FEAT_GUI) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL)
Bram Moolenaar8cebd432020-11-08 12:49:47 +01005519 // this can only change on Unix where the ":gui" command could be
5520 // used.
5521 || (STRICMP(feature, "gui_running") == 0 && !gui.in_use)
5522#endif
5523#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5524 || STRICMP(feature, "iconv") == 0
5525#endif
5526#ifdef DYNAMIC_LUA
5527 || STRICMP(feature, "lua") == 0
5528#endif
5529#ifdef FEAT_MOUSE_GPM
5530 || (STRICMP(feature, "mouse_gpm_enabled") == 0 && !gpm_enabled())
5531#endif
5532#ifdef DYNAMIC_MZSCHEME
5533 || STRICMP(feature, "mzscheme") == 0
5534#endif
5535#ifdef FEAT_NETBEANS_INTG
5536 || STRICMP(feature, "netbeans_enabled") == 0
5537#endif
5538#ifdef DYNAMIC_PERL
5539 || STRICMP(feature, "perl") == 0
5540#endif
5541#ifdef DYNAMIC_PYTHON
5542 || STRICMP(feature, "python") == 0
5543#endif
5544#ifdef DYNAMIC_PYTHON3
5545 || STRICMP(feature, "python3") == 0
5546#endif
5547#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5548 || STRICMP(feature, "pythonx") == 0
5549#endif
5550#ifdef DYNAMIC_RUBY
5551 || STRICMP(feature, "ruby") == 0
5552#endif
5553#ifdef FEAT_SYN_HL
5554 || STRICMP(feature, "syntax_items") == 0
5555#endif
5556#ifdef DYNAMIC_TCL
5557 || STRICMP(feature, "tcl") == 0
5558#endif
5559 // once "starting" is zero it will stay that way
5560 || (STRICMP(feature, "vim_starting") == 0 && starting != 0)
5561 || STRICMP(feature, "multi_byte_encoding") == 0
5562#if defined(FEAT_TERMINAL) && defined(MSWIN)
5563 || STRICMP(feature, "conpty") == 0
5564#endif
5565 );
5566}
5567
5568/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005569 * "haslocaldir()" function
5570 */
5571 static void
5572f_haslocaldir(typval_T *argvars, typval_T *rettv)
5573{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005574 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005575 win_T *wp = NULL;
5576
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005577 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
5578
5579 // Check for window-local and tab-local directories
5580 if (wp != NULL && wp->w_localdir != NULL)
5581 rettv->vval.v_number = 1;
5582 else if (tp != NULL && tp->tp_localdir != NULL)
5583 rettv->vval.v_number = 2;
5584 else
5585 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005586}
5587
5588/*
5589 * "hasmapto()" function
5590 */
5591 static void
5592f_hasmapto(typval_T *argvars, typval_T *rettv)
5593{
5594 char_u *name;
5595 char_u *mode;
5596 char_u buf[NUMBUFLEN];
5597 int abbr = FALSE;
5598
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005599 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005600 if (argvars[1].v_type == VAR_UNKNOWN)
5601 mode = (char_u *)"nvo";
5602 else
5603 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005604 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar04d594b2020-09-02 22:25:35 +02005606 abbr = (int)tv_get_bool(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005607 }
5608
5609 if (map_to_exists(name, mode, abbr))
5610 rettv->vval.v_number = TRUE;
5611 else
5612 rettv->vval.v_number = FALSE;
5613}
5614
5615/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005616 * "highlightID(name)" function
5617 */
5618 static void
5619f_hlID(typval_T *argvars, typval_T *rettv)
5620{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005621 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005622}
5623
5624/*
5625 * "highlight_exists()" function
5626 */
5627 static void
5628f_hlexists(typval_T *argvars, typval_T *rettv)
5629{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005630 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631}
5632
5633/*
5634 * "hostname()" function
5635 */
5636 static void
5637f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5638{
5639 char_u hostname[256];
5640
5641 mch_get_host_name(hostname, 256);
5642 rettv->v_type = VAR_STRING;
5643 rettv->vval.v_string = vim_strsave(hostname);
5644}
5645
5646/*
5647 * iconv() function
5648 */
5649 static void
5650f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5651{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005652 char_u buf1[NUMBUFLEN];
5653 char_u buf2[NUMBUFLEN];
5654 char_u *from, *to, *str;
5655 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005656
5657 rettv->v_type = VAR_STRING;
5658 rettv->vval.v_string = NULL;
5659
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005660 str = tv_get_string(&argvars[0]);
5661 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
5662 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005663 vimconv.vc_type = CONV_NONE;
5664 convert_setup(&vimconv, from, to);
5665
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005666 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005667 if (vimconv.vc_type == CONV_NONE)
5668 rettv->vval.v_string = vim_strsave(str);
5669 else
5670 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5671
5672 convert_setup(&vimconv, NULL, NULL);
5673 vim_free(from);
5674 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005675}
5676
5677/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005678 * "index()" function
5679 */
5680 static void
5681f_index(typval_T *argvars, typval_T *rettv)
5682{
5683 list_T *l;
5684 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005685 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005686 long idx = 0;
5687 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005688 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005689
5690 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005691 if (argvars[0].v_type == VAR_BLOB)
5692 {
5693 typval_T tv;
5694 int start = 0;
5695
5696 if (argvars[2].v_type != VAR_UNKNOWN)
5697 {
5698 start = tv_get_number_chk(&argvars[2], &error);
5699 if (error)
5700 return;
5701 }
5702 b = argvars[0].vval.v_blob;
5703 if (b == NULL)
5704 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01005705 if (start < 0)
5706 {
5707 start = blob_len(b) + start;
5708 if (start < 0)
5709 start = 0;
5710 }
5711
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005712 for (idx = start; idx < blob_len(b); ++idx)
5713 {
5714 tv.v_type = VAR_NUMBER;
5715 tv.vval.v_number = blob_get(b, idx);
5716 if (tv_equal(&tv, &argvars[1], ic, FALSE))
5717 {
5718 rettv->vval.v_number = idx;
5719 return;
5720 }
5721 }
5722 return;
5723 }
5724 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005725 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01005726 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005727 return;
5728 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005729
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005730 l = argvars[0].vval.v_list;
5731 if (l != NULL)
5732 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005733 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734 item = l->lv_first;
5735 if (argvars[2].v_type != VAR_UNKNOWN)
5736 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005737 // Start at specified item. Use the cached index that list_find()
5738 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005739 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005740 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005741 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaar6c553f92020-09-02 22:10:34 +02005742 ic = (int)tv_get_bool_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743 if (error)
5744 item = NULL;
5745 }
5746
5747 for ( ; item != NULL; item = item->li_next, ++idx)
5748 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
5749 {
5750 rettv->vval.v_number = idx;
5751 break;
5752 }
5753 }
5754}
5755
5756static int inputsecret_flag = 0;
5757
5758/*
5759 * "input()" function
5760 * Also handles inputsecret() when inputsecret is set.
5761 */
5762 static void
5763f_input(typval_T *argvars, typval_T *rettv)
5764{
5765 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5766}
5767
5768/*
5769 * "inputdialog()" function
5770 */
5771 static void
5772f_inputdialog(typval_T *argvars, typval_T *rettv)
5773{
5774#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005775 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005776 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5777 {
5778 char_u *message;
5779 char_u buf[NUMBUFLEN];
5780 char_u *defstr = (char_u *)"";
5781
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005782 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005784 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005785 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5786 else
5787 IObuff[0] = NUL;
5788 if (message != NULL && defstr != NULL
5789 && do_dialog(VIM_QUESTION, NULL, message,
5790 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5791 rettv->vval.v_string = vim_strsave(IObuff);
5792 else
5793 {
5794 if (message != NULL && defstr != NULL
5795 && argvars[1].v_type != VAR_UNKNOWN
5796 && argvars[2].v_type != VAR_UNKNOWN)
5797 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005798 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 else
5800 rettv->vval.v_string = NULL;
5801 }
5802 rettv->v_type = VAR_STRING;
5803 }
5804 else
5805#endif
5806 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5807}
5808
5809/*
5810 * "inputlist()" function
5811 */
5812 static void
5813f_inputlist(typval_T *argvars, typval_T *rettv)
5814{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005815 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005816 listitem_T *li;
5817 int selected;
5818 int mouse_used;
5819
5820#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005821 // While starting up, there is no place to enter text. When running tests
5822 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02005823 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005824 return;
5825#endif
5826 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5827 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005828 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829 return;
5830 }
5831
5832 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005833 msg_row = Rows - 1; // for when 'cmdheight' > 1
5834 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005835 msg_scroll = TRUE;
5836 msg_clr_eos();
5837
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005838 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005839 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02005840 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005841 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005842 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005843 msg_putchar('\n');
5844 }
5845
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005846 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005847 selected = prompt_for_number(&mouse_used);
5848 if (mouse_used)
5849 selected -= lines_left;
5850
5851 rettv->vval.v_number = selected;
5852}
5853
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005854static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5855
5856/*
5857 * "inputrestore()" function
5858 */
5859 static void
5860f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5861{
5862 if (ga_userinput.ga_len > 0)
5863 {
5864 --ga_userinput.ga_len;
5865 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5866 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005867 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 }
5869 else if (p_verbose > 1)
5870 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005871 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005872 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005873 }
5874}
5875
5876/*
5877 * "inputsave()" function
5878 */
5879 static void
5880f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5881{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005882 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005883 if (ga_grow(&ga_userinput, 1) == OK)
5884 {
5885 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5886 + ga_userinput.ga_len);
5887 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005888 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005889 }
5890 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005891 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005892}
5893
5894/*
5895 * "inputsecret()" function
5896 */
5897 static void
5898f_inputsecret(typval_T *argvars, typval_T *rettv)
5899{
5900 ++cmdline_star;
5901 ++inputsecret_flag;
5902 f_input(argvars, rettv);
5903 --cmdline_star;
5904 --inputsecret_flag;
5905}
5906
5907/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005908 * "interrupt()" function
5909 */
5910 static void
5911f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5912{
5913 got_int = TRUE;
5914}
5915
5916/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005917 * "invert(expr)" function
5918 */
5919 static void
5920f_invert(typval_T *argvars, typval_T *rettv)
5921{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005922 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005923}
5924
5925/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005926 * "islocked()" function
5927 */
5928 static void
5929f_islocked(typval_T *argvars, typval_T *rettv)
5930{
5931 lval_T lv;
5932 char_u *end;
5933 dictitem_T *di;
5934
5935 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005936 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005937 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005938 if (end != NULL && lv.ll_name != NULL)
5939 {
5940 if (*end != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02005941 semsg(_(e_trailing_arg), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005942 else
5943 {
5944 if (lv.ll_tv == NULL)
5945 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005946 di = find_var(lv.ll_name, NULL, TRUE);
5947 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005948 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005949 // Consider a variable locked when:
5950 // 1. the variable itself is locked
5951 // 2. the value of the variable is locked.
5952 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005953 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5954 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005955 }
5956 }
5957 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005958 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005959 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005960 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005961 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005962 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005963 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5964 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005965 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005966 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5967 }
5968 }
5969
5970 clear_lval(&lv);
5971}
5972
5973#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5974/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005975 * "isinf()" function
5976 */
5977 static void
5978f_isinf(typval_T *argvars, typval_T *rettv)
5979{
5980 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5981 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5982}
5983
5984/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005985 * "isnan()" function
5986 */
5987 static void
5988f_isnan(typval_T *argvars, typval_T *rettv)
5989{
5990 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5991 && isnan(argvars[0].vval.v_float);
5992}
5993#endif
5994
5995/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005996 * "last_buffer_nr()" function.
5997 */
5998 static void
5999f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6000{
6001 int n = 0;
6002 buf_T *buf;
6003
Bram Moolenaar29323592016-07-24 22:04:11 +02006004 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006005 if (n < buf->b_fnum)
6006 n = buf->b_fnum;
6007
6008 rettv->vval.v_number = n;
6009}
6010
6011/*
6012 * "len()" function
6013 */
6014 static void
6015f_len(typval_T *argvars, typval_T *rettv)
6016{
6017 switch (argvars[0].v_type)
6018 {
6019 case VAR_STRING:
6020 case VAR_NUMBER:
6021 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006022 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006024 case VAR_BLOB:
6025 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6026 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006027 case VAR_LIST:
6028 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6029 break;
6030 case VAR_DICT:
6031 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6032 break;
6033 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02006034 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006035 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01006036 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006037 case VAR_SPECIAL:
6038 case VAR_FLOAT:
6039 case VAR_FUNC:
6040 case VAR_PARTIAL:
6041 case VAR_JOB:
6042 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006043 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006044 break;
6045 }
6046}
6047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006048 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006049libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050{
6051#ifdef FEAT_LIBCALL
6052 char_u *string_in;
6053 char_u **string_result;
6054 int nr_result;
6055#endif
6056
6057 rettv->v_type = type;
6058 if (type != VAR_NUMBER)
6059 rettv->vval.v_string = NULL;
6060
6061 if (check_restricted() || check_secure())
6062 return;
6063
6064#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006065 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006066 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6067 {
6068 string_in = NULL;
6069 if (argvars[2].v_type == VAR_STRING)
6070 string_in = argvars[2].vval.v_string;
6071 if (type == VAR_NUMBER)
6072 string_result = NULL;
6073 else
6074 string_result = &rettv->vval.v_string;
6075 if (mch_libcall(argvars[0].vval.v_string,
6076 argvars[1].vval.v_string,
6077 string_in,
6078 argvars[2].vval.v_number,
6079 string_result,
6080 &nr_result) == OK
6081 && type == VAR_NUMBER)
6082 rettv->vval.v_number = nr_result;
6083 }
6084#endif
6085}
6086
6087/*
6088 * "libcall()" function
6089 */
6090 static void
6091f_libcall(typval_T *argvars, typval_T *rettv)
6092{
6093 libcall_common(argvars, rettv, VAR_STRING);
6094}
6095
6096/*
6097 * "libcallnr()" function
6098 */
6099 static void
6100f_libcallnr(typval_T *argvars, typval_T *rettv)
6101{
6102 libcall_common(argvars, rettv, VAR_NUMBER);
6103}
6104
6105/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006106 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006107 */
6108 static void
6109f_line(typval_T *argvars, typval_T *rettv)
6110{
6111 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006112 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006113 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006114 int id;
6115 tabpage_T *tp;
6116 win_T *wp;
6117 win_T *save_curwin;
6118 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006119
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006120 if (argvars[1].v_type != VAR_UNKNOWN)
6121 {
6122 // use window specified in the second argument
6123 id = (int)tv_get_number(&argvars[1]);
6124 wp = win_id2wp_tp(id, &tp);
6125 if (wp != NULL && tp != NULL)
6126 {
6127 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
6128 == OK)
6129 {
6130 check_cursor();
6131 fp = var2fpos(&argvars[0], TRUE, &fnum);
6132 }
6133 restore_win_noblock(save_curwin, save_curtab, TRUE);
6134 }
6135 }
6136 else
6137 // use current window
6138 fp = var2fpos(&argvars[0], TRUE, &fnum);
6139
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006140 if (fp != NULL)
6141 lnum = fp->lnum;
6142 rettv->vval.v_number = lnum;
6143}
6144
6145/*
6146 * "line2byte(lnum)" function
6147 */
6148 static void
6149f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6150{
6151#ifndef FEAT_BYTEOFF
6152 rettv->vval.v_number = -1;
6153#else
6154 linenr_T lnum;
6155
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006156 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006157 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6158 rettv->vval.v_number = -1;
6159 else
6160 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6161 if (rettv->vval.v_number >= 0)
6162 ++rettv->vval.v_number;
6163#endif
6164}
6165
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166#ifdef FEAT_FLOAT
6167/*
6168 * "log()" function
6169 */
6170 static void
6171f_log(typval_T *argvars, typval_T *rettv)
6172{
6173 float_T f = 0.0;
6174
6175 rettv->v_type = VAR_FLOAT;
6176 if (get_float_arg(argvars, &f) == OK)
6177 rettv->vval.v_float = log(f);
6178 else
6179 rettv->vval.v_float = 0.0;
6180}
6181
6182/*
6183 * "log10()" function
6184 */
6185 static void
6186f_log10(typval_T *argvars, typval_T *rettv)
6187{
6188 float_T f = 0.0;
6189
6190 rettv->v_type = VAR_FLOAT;
6191 if (get_float_arg(argvars, &f) == OK)
6192 rettv->vval.v_float = log10(f);
6193 else
6194 rettv->vval.v_float = 0.0;
6195}
6196#endif
6197
6198#ifdef FEAT_LUA
6199/*
6200 * "luaeval()" function
6201 */
6202 static void
6203f_luaeval(typval_T *argvars, typval_T *rettv)
6204{
6205 char_u *str;
6206 char_u buf[NUMBUFLEN];
6207
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006208 if (check_restricted() || check_secure())
6209 return;
6210
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006211 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212 do_luaeval(str, argvars + 1, rettv);
6213}
6214#endif
6215
6216/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006217 * "maparg()" function
6218 */
6219 static void
6220f_maparg(typval_T *argvars, typval_T *rettv)
6221{
6222 get_maparg(argvars, rettv, TRUE);
6223}
6224
6225/*
6226 * "mapcheck()" function
6227 */
6228 static void
6229f_mapcheck(typval_T *argvars, typval_T *rettv)
6230{
6231 get_maparg(argvars, rettv, FALSE);
6232}
6233
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006234typedef enum
6235{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006236 MATCH_END, // matchend()
6237 MATCH_MATCH, // match()
6238 MATCH_STR, // matchstr()
6239 MATCH_LIST, // matchlist()
6240 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006241} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006242
6243 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006244find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006245{
6246 char_u *str = NULL;
6247 long len = 0;
6248 char_u *expr = NULL;
6249 char_u *pat;
6250 regmatch_T regmatch;
6251 char_u patbuf[NUMBUFLEN];
6252 char_u strbuf[NUMBUFLEN];
6253 char_u *save_cpo;
6254 long start = 0;
6255 long nth = 1;
6256 colnr_T startcol = 0;
6257 int match = 0;
6258 list_T *l = NULL;
6259 listitem_T *li = NULL;
6260 long idx = 0;
6261 char_u *tofree = NULL;
6262
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006263 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264 save_cpo = p_cpo;
6265 p_cpo = (char_u *)"";
6266
6267 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006268 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006269 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006270 // type MATCH_LIST: return empty list when there are no matches.
6271 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 if (rettv_list_alloc(rettv) == FAIL)
6273 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006274 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006275 && (list_append_string(rettv->vval.v_list,
6276 (char_u *)"", 0) == FAIL
6277 || list_append_number(rettv->vval.v_list,
6278 (varnumber_T)-1) == FAIL
6279 || list_append_number(rettv->vval.v_list,
6280 (varnumber_T)-1) == FAIL
6281 || list_append_number(rettv->vval.v_list,
6282 (varnumber_T)-1) == FAIL))
6283 {
6284 list_free(rettv->vval.v_list);
6285 rettv->vval.v_list = NULL;
6286 goto theend;
6287 }
6288 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006289 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 {
6291 rettv->v_type = VAR_STRING;
6292 rettv->vval.v_string = NULL;
6293 }
6294
6295 if (argvars[0].v_type == VAR_LIST)
6296 {
6297 if ((l = argvars[0].vval.v_list) == NULL)
6298 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006299 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300 li = l->lv_first;
6301 }
6302 else
6303 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006304 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006305 len = (long)STRLEN(str);
6306 }
6307
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006308 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006309 if (pat == NULL)
6310 goto theend;
6311
6312 if (argvars[2].v_type != VAR_UNKNOWN)
6313 {
6314 int error = FALSE;
6315
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006316 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006317 if (error)
6318 goto theend;
6319 if (l != NULL)
6320 {
6321 li = list_find(l, start);
6322 if (li == NULL)
6323 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006324 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325 }
6326 else
6327 {
6328 if (start < 0)
6329 start = 0;
6330 if (start > len)
6331 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006332 // When "count" argument is there ignore matches before "start",
6333 // otherwise skip part of the string. Differs when pattern is "^"
6334 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335 if (argvars[3].v_type != VAR_UNKNOWN)
6336 startcol = start;
6337 else
6338 {
6339 str += start;
6340 len -= start;
6341 }
6342 }
6343
6344 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006345 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006346 if (error)
6347 goto theend;
6348 }
6349
6350 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6351 if (regmatch.regprog != NULL)
6352 {
6353 regmatch.rm_ic = p_ic;
6354
6355 for (;;)
6356 {
6357 if (l != NULL)
6358 {
6359 if (li == NULL)
6360 {
6361 match = FALSE;
6362 break;
6363 }
6364 vim_free(tofree);
6365 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6366 if (str == NULL)
6367 break;
6368 }
6369
6370 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6371
6372 if (match && --nth <= 0)
6373 break;
6374 if (l == NULL && !match)
6375 break;
6376
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006377 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006378 if (l != NULL)
6379 {
6380 li = li->li_next;
6381 ++idx;
6382 }
6383 else
6384 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385 startcol = (colnr_T)(regmatch.startp[0]
6386 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006387 if (startcol > (colnr_T)len
6388 || str + startcol <= regmatch.startp[0])
6389 {
6390 match = FALSE;
6391 break;
6392 }
6393 }
6394 }
6395
6396 if (match)
6397 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006398 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006399 {
6400 listitem_T *li1 = rettv->vval.v_list->lv_first;
6401 listitem_T *li2 = li1->li_next;
6402 listitem_T *li3 = li2->li_next;
6403 listitem_T *li4 = li3->li_next;
6404
6405 vim_free(li1->li_tv.vval.v_string);
6406 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02006407 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006408 li3->li_tv.vval.v_number =
6409 (varnumber_T)(regmatch.startp[0] - expr);
6410 li4->li_tv.vval.v_number =
6411 (varnumber_T)(regmatch.endp[0] - expr);
6412 if (l != NULL)
6413 li2->li_tv.vval.v_number = (varnumber_T)idx;
6414 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006415 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 {
6417 int i;
6418
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006419 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420 for (i = 0; i < NSUBEXP; ++i)
6421 {
6422 if (regmatch.endp[i] == NULL)
6423 {
6424 if (list_append_string(rettv->vval.v_list,
6425 (char_u *)"", 0) == FAIL)
6426 break;
6427 }
6428 else if (list_append_string(rettv->vval.v_list,
6429 regmatch.startp[i],
6430 (int)(regmatch.endp[i] - regmatch.startp[i]))
6431 == FAIL)
6432 break;
6433 }
6434 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006435 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006436 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006437 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006438 if (l != NULL)
6439 copy_tv(&li->li_tv, rettv);
6440 else
6441 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02006442 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443 }
6444 else if (l != NULL)
6445 rettv->vval.v_number = idx;
6446 else
6447 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006448 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006449 rettv->vval.v_number =
6450 (varnumber_T)(regmatch.startp[0] - str);
6451 else
6452 rettv->vval.v_number =
6453 (varnumber_T)(regmatch.endp[0] - str);
6454 rettv->vval.v_number += (varnumber_T)(str - expr);
6455 }
6456 }
6457 vim_regfree(regmatch.regprog);
6458 }
6459
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006460theend:
6461 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006462 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006463 listitem_remove(rettv->vval.v_list,
6464 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465 vim_free(tofree);
6466 p_cpo = save_cpo;
6467}
6468
6469/*
6470 * "match()" function
6471 */
6472 static void
6473f_match(typval_T *argvars, typval_T *rettv)
6474{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006475 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476}
6477
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478/*
6479 * "matchend()" function
6480 */
6481 static void
6482f_matchend(typval_T *argvars, typval_T *rettv)
6483{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006484 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485}
6486
6487/*
6488 * "matchlist()" function
6489 */
6490 static void
6491f_matchlist(typval_T *argvars, typval_T *rettv)
6492{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006493 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006494}
6495
6496/*
6497 * "matchstr()" function
6498 */
6499 static void
6500f_matchstr(typval_T *argvars, typval_T *rettv)
6501{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006502 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503}
6504
6505/*
6506 * "matchstrpos()" function
6507 */
6508 static void
6509f_matchstrpos(typval_T *argvars, typval_T *rettv)
6510{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006511 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006512}
6513
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514 static void
6515max_min(typval_T *argvars, typval_T *rettv, int domax)
6516{
6517 varnumber_T n = 0;
6518 varnumber_T i;
6519 int error = FALSE;
6520
6521 if (argvars[0].v_type == VAR_LIST)
6522 {
6523 list_T *l;
6524 listitem_T *li;
6525
6526 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006527 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006528 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006529 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006530 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006531 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
6532 n = l->lv_u.nonmat.lv_start;
6533 else
6534 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
6535 * l->lv_u.nonmat.lv_stride;
6536 }
6537 else
6538 {
6539 li = l->lv_first;
6540 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006542 n = tv_get_number_chk(&li->li_tv, &error);
6543 for (;;)
6544 {
6545 li = li->li_next;
6546 if (li == NULL)
6547 break;
6548 i = tv_get_number_chk(&li->li_tv, &error);
6549 if (domax ? i > n : i < n)
6550 n = i;
6551 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006552 }
6553 }
6554 }
6555 }
6556 else if (argvars[0].v_type == VAR_DICT)
6557 {
6558 dict_T *d;
6559 int first = TRUE;
6560 hashitem_T *hi;
6561 int todo;
6562
6563 d = argvars[0].vval.v_dict;
6564 if (d != NULL)
6565 {
6566 todo = (int)d->dv_hashtab.ht_used;
6567 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
6568 {
6569 if (!HASHITEM_EMPTY(hi))
6570 {
6571 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006572 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006573 if (first)
6574 {
6575 n = i;
6576 first = FALSE;
6577 }
6578 else if (domax ? i > n : i < n)
6579 n = i;
6580 }
6581 }
6582 }
6583 }
6584 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006585 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 rettv->vval.v_number = error ? 0 : n;
6587}
6588
6589/*
6590 * "max()" function
6591 */
6592 static void
6593f_max(typval_T *argvars, typval_T *rettv)
6594{
6595 max_min(argvars, rettv, TRUE);
6596}
6597
6598/*
6599 * "min()" function
6600 */
6601 static void
6602f_min(typval_T *argvars, typval_T *rettv)
6603{
6604 max_min(argvars, rettv, FALSE);
6605}
6606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006607#if defined(FEAT_MZSCHEME) || defined(PROTO)
6608/*
6609 * "mzeval()" function
6610 */
6611 static void
6612f_mzeval(typval_T *argvars, typval_T *rettv)
6613{
6614 char_u *str;
6615 char_u buf[NUMBUFLEN];
6616
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006617 if (check_restricted() || check_secure())
6618 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006619 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620 do_mzeval(str, rettv);
6621}
6622
6623 void
6624mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
6625{
6626 typval_T argvars[3];
6627
6628 argvars[0].v_type = VAR_STRING;
6629 argvars[0].vval.v_string = name;
6630 copy_tv(args, &argvars[1]);
6631 argvars[2].v_type = VAR_UNKNOWN;
6632 f_call(argvars, rettv);
6633 clear_tv(&argvars[1]);
6634}
6635#endif
6636
6637/*
6638 * "nextnonblank()" function
6639 */
6640 static void
6641f_nextnonblank(typval_T *argvars, typval_T *rettv)
6642{
6643 linenr_T lnum;
6644
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006645 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006646 {
6647 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
6648 {
6649 lnum = 0;
6650 break;
6651 }
6652 if (*skipwhite(ml_get(lnum)) != NUL)
6653 break;
6654 }
6655 rettv->vval.v_number = lnum;
6656}
6657
6658/*
6659 * "nr2char()" function
6660 */
6661 static void
6662f_nr2char(typval_T *argvars, typval_T *rettv)
6663{
6664 char_u buf[NUMBUFLEN];
6665
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006666 if (has_mbyte)
6667 {
6668 int utf8 = 0;
6669
6670 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaared6a4302020-09-05 20:29:41 +02006671 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006672 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01006673 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006674 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006675 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006676 }
6677 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006678 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006679 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006680 buf[1] = NUL;
6681 }
6682 rettv->v_type = VAR_STRING;
6683 rettv->vval.v_string = vim_strsave(buf);
6684}
6685
6686/*
6687 * "or(expr, expr)" function
6688 */
6689 static void
6690f_or(typval_T *argvars, typval_T *rettv)
6691{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006692 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
6693 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006694}
6695
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006696#ifdef FEAT_PERL
6697/*
6698 * "perleval()" function
6699 */
6700 static void
6701f_perleval(typval_T *argvars, typval_T *rettv)
6702{
6703 char_u *str;
6704 char_u buf[NUMBUFLEN];
6705
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006706 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006707 do_perleval(str, rettv);
6708}
6709#endif
6710
6711#ifdef FEAT_FLOAT
6712/*
6713 * "pow()" function
6714 */
6715 static void
6716f_pow(typval_T *argvars, typval_T *rettv)
6717{
6718 float_T fx = 0.0, fy = 0.0;
6719
6720 rettv->v_type = VAR_FLOAT;
6721 if (get_float_arg(argvars, &fx) == OK
6722 && get_float_arg(&argvars[1], &fy) == OK)
6723 rettv->vval.v_float = pow(fx, fy);
6724 else
6725 rettv->vval.v_float = 0.0;
6726}
6727#endif
6728
6729/*
6730 * "prevnonblank()" function
6731 */
6732 static void
6733f_prevnonblank(typval_T *argvars, typval_T *rettv)
6734{
6735 linenr_T lnum;
6736
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006737 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006738 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
6739 lnum = 0;
6740 else
6741 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
6742 --lnum;
6743 rettv->vval.v_number = lnum;
6744}
6745
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006746// This dummy va_list is here because:
6747// - passing a NULL pointer doesn't work when va_list isn't a pointer
6748// - locally in the function results in a "used before set" warning
6749// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006750static va_list ap;
6751
6752/*
6753 * "printf()" function
6754 */
6755 static void
6756f_printf(typval_T *argvars, typval_T *rettv)
6757{
6758 char_u buf[NUMBUFLEN];
6759 int len;
6760 char_u *s;
6761 int saved_did_emsg = did_emsg;
6762 char *fmt;
6763
6764 rettv->v_type = VAR_STRING;
6765 rettv->vval.v_string = NULL;
6766
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006767 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006769 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006770 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006771 if (!did_emsg)
6772 {
6773 s = alloc(len + 1);
6774 if (s != NULL)
6775 {
6776 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006777 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
6778 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 }
6780 }
6781 did_emsg |= saved_did_emsg;
6782}
6783
6784/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006785 * "pum_getpos()" function
6786 */
6787 static void
6788f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6789{
6790 if (rettv_dict_alloc(rettv) != OK)
6791 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006792 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006793}
6794
6795/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 * "pumvisible()" function
6797 */
6798 static void
6799f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6800{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006801 if (pum_visible())
6802 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006803}
6804
6805#ifdef FEAT_PYTHON3
6806/*
6807 * "py3eval()" function
6808 */
6809 static void
6810f_py3eval(typval_T *argvars, typval_T *rettv)
6811{
6812 char_u *str;
6813 char_u buf[NUMBUFLEN];
6814
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006815 if (check_restricted() || check_secure())
6816 return;
6817
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006818 if (p_pyx == 0)
6819 p_pyx = 3;
6820
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006821 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006822 do_py3eval(str, rettv);
6823}
6824#endif
6825
6826#ifdef FEAT_PYTHON
6827/*
6828 * "pyeval()" function
6829 */
6830 static void
6831f_pyeval(typval_T *argvars, typval_T *rettv)
6832{
6833 char_u *str;
6834 char_u buf[NUMBUFLEN];
6835
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006836 if (check_restricted() || check_secure())
6837 return;
6838
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006839 if (p_pyx == 0)
6840 p_pyx = 2;
6841
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006842 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006843 do_pyeval(str, rettv);
6844}
6845#endif
6846
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006847#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
6848/*
6849 * "pyxeval()" function
6850 */
6851 static void
6852f_pyxeval(typval_T *argvars, typval_T *rettv)
6853{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006854 if (check_restricted() || check_secure())
6855 return;
6856
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006857# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
6858 init_pyxversion();
6859 if (p_pyx == 2)
6860 f_pyeval(argvars, rettv);
6861 else
6862 f_py3eval(argvars, rettv);
6863# elif defined(FEAT_PYTHON)
6864 f_pyeval(argvars, rettv);
6865# elif defined(FEAT_PYTHON3)
6866 f_py3eval(argvars, rettv);
6867# endif
6868}
6869#endif
6870
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006871static UINT32_T srand_seed_for_testing = 0;
6872static int srand_seed_for_testing_is_used = FALSE;
6873
6874 static void
6875f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
6876{
6877 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006878 srand_seed_for_testing_is_used = FALSE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006879 else
6880 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006881 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
6882 srand_seed_for_testing_is_used = TRUE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006883 }
6884}
6885
6886 static void
6887init_srand(UINT32_T *x)
6888{
6889#ifndef MSWIN
6890 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6891#endif
6892
6893 if (srand_seed_for_testing_is_used)
6894 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006895 *x = srand_seed_for_testing;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006896 return;
6897 }
6898#ifndef MSWIN
6899 if (dev_urandom_state != FAIL)
6900 {
6901 int fd = open("/dev/urandom", O_RDONLY);
6902 struct {
6903 union {
6904 UINT32_T number;
6905 char bytes[sizeof(UINT32_T)];
6906 } contents;
6907 } buf;
6908
6909 // Attempt reading /dev/urandom.
6910 if (fd == -1)
6911 dev_urandom_state = FAIL;
6912 else
6913 {
6914 buf.contents.number = 0;
6915 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6916 != sizeof(UINT32_T))
6917 dev_urandom_state = FAIL;
6918 else
6919 {
6920 dev_urandom_state = OK;
6921 *x = buf.contents.number;
6922 }
6923 close(fd);
6924 }
6925 }
6926 if (dev_urandom_state != OK)
6927 // Reading /dev/urandom doesn't work, fall back to time().
6928#endif
6929 *x = vim_time();
6930}
6931
6932#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6933#define SPLITMIX32(x, z) ( \
6934 z = (x += 0x9e3779b9), \
6935 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6936 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6937 z ^ (z >> 16) \
6938 )
6939#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6940 result = ROTL(y * 5, 7) * 9; \
6941 t = y << 9; \
6942 z ^= x; \
6943 w ^= y; \
6944 y ^= z, x ^= w; \
6945 z ^= t; \
6946 w = ROTL(w, 11);
6947
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006949 * "rand()" function
6950 */
6951 static void
6952f_rand(typval_T *argvars, typval_T *rettv)
6953{
6954 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006955 static UINT32_T gx, gy, gz, gw;
6956 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006957 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar0fd797e2020-11-05 20:46:32 +01006958 UINT32_T x = 0, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006959
6960 if (argvars[0].v_type == VAR_UNKNOWN)
6961 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006962 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006963 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006964 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006965 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006966 init_srand(&x);
6967
6968 gx = SPLITMIX32(x, z);
6969 gy = SPLITMIX32(x, z);
6970 gz = SPLITMIX32(x, z);
6971 gw = SPLITMIX32(x, z);
6972 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006973 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006974
6975 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006976 }
6977 else if (argvars[0].v_type == VAR_LIST)
6978 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006979 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006980 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006981 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006982
6983 lx = list_find(l, 0L);
6984 ly = list_find(l, 1L);
6985 lz = list_find(l, 2L);
6986 lw = list_find(l, 3L);
6987 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6988 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6989 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6990 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6991 x = (UINT32_T)lx->li_tv.vval.v_number;
6992 y = (UINT32_T)ly->li_tv.vval.v_number;
6993 z = (UINT32_T)lz->li_tv.vval.v_number;
6994 w = (UINT32_T)lw->li_tv.vval.v_number;
6995
6996 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6997
6998 lx->li_tv.vval.v_number = (varnumber_T)x;
6999 ly->li_tv.vval.v_number = (varnumber_T)y;
7000 lz->li_tv.vval.v_number = (varnumber_T)z;
7001 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007002 }
7003 else
7004 goto theend;
7005
7006 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007007 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007008 return;
7009
7010theend:
7011 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007012 rettv->v_type = VAR_NUMBER;
7013 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007014}
7015
7016/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007017 * "srand()" function
7018 */
7019 static void
7020f_srand(typval_T *argvars, typval_T *rettv)
7021{
7022 UINT32_T x = 0, z;
7023
7024 if (rettv_list_alloc(rettv) == FAIL)
7025 return;
7026 if (argvars[0].v_type == VAR_UNKNOWN)
7027 {
7028 init_srand(&x);
7029 }
7030 else
7031 {
7032 int error = FALSE;
7033
7034 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
7035 if (error)
7036 return;
7037 }
7038
7039 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7040 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7041 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7042 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7043}
7044
7045#undef ROTL
7046#undef SPLITMIX32
7047#undef SHUFFLE_XOSHIRO128STARSTAR
7048
7049/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007050 * "range()" function
7051 */
7052 static void
7053f_range(typval_T *argvars, typval_T *rettv)
7054{
7055 varnumber_T start;
7056 varnumber_T end;
7057 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007058 int error = FALSE;
7059
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007060 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007061 if (argvars[1].v_type == VAR_UNKNOWN)
7062 {
7063 end = start - 1;
7064 start = 0;
7065 }
7066 else
7067 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007068 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007070 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 }
7072
7073 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007074 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007076 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007077 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007078 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007079 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007081 list_T *list = rettv->vval.v_list;
7082
7083 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007084 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007085 // be called.
7086 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01007087 list->lv_u.nonmat.lv_start = start;
7088 list->lv_u.nonmat.lv_end = end;
7089 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007090 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007091 }
7092}
7093
7094/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007095 * Materialize "list".
7096 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007097 */
7098 void
7099range_list_materialize(list_T *list)
7100{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007101 varnumber_T start = list->lv_u.nonmat.lv_start;
7102 varnumber_T end = list->lv_u.nonmat.lv_end;
7103 int stride = list->lv_u.nonmat.lv_stride;
7104 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007105
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007106 list->lv_first = NULL;
7107 list->lv_u.mat.lv_last = NULL;
7108 list->lv_len = 0;
7109 list->lv_u.mat.lv_idx_item = NULL;
7110 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7111 if (list_append_number(list, (varnumber_T)i) == FAIL)
7112 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007113}
7114
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007115/*
7116 * "getreginfo()" function
7117 */
7118 static void
7119f_getreginfo(typval_T *argvars, typval_T *rettv)
7120{
7121 char_u *strregname;
7122 int regname;
7123 char_u buf[NUMBUFLEN + 2];
7124 long reglen = 0;
7125 dict_T *dict;
7126 list_T *list;
7127
7128 if (argvars[0].v_type != VAR_UNKNOWN)
7129 {
7130 strregname = tv_get_string_chk(&argvars[0]);
7131 if (strregname == NULL)
7132 return;
7133 }
7134 else
7135 strregname = get_vim_var_str(VV_REG);
7136
7137 regname = (strregname == NULL ? '"' : *strregname);
7138 if (regname == 0 || regname == '@')
7139 regname = '"';
7140
7141 if (rettv_dict_alloc(rettv) == FAIL)
7142 return;
7143 dict = rettv->vval.v_dict;
7144
7145 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
7146 if (list == NULL)
7147 return;
Bram Moolenaar91639192020-06-29 19:55:58 +02007148 (void)dict_add_list(dict, "regcontents", list);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007149
7150 buf[0] = NUL;
7151 buf[1] = NUL;
7152 switch (get_reg_type(regname, &reglen))
7153 {
7154 case MLINE: buf[0] = 'V'; break;
7155 case MCHAR: buf[0] = 'v'; break;
7156 case MBLOCK:
7157 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
7158 reglen + 1);
7159 break;
7160 }
Bram Moolenaar91639192020-06-29 19:55:58 +02007161 (void)dict_add_string(dict, (char *)"regtype", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007162
7163 buf[0] = get_register_name(get_unname_register());
7164 buf[1] = NUL;
7165 if (regname == '"')
Bram Moolenaar91639192020-06-29 19:55:58 +02007166 (void)dict_add_string(dict, (char *)"points_to", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007167 else
7168 {
7169 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
7170
7171 if (item != NULL)
7172 {
7173 item->di_tv.v_type = VAR_SPECIAL;
7174 item->di_tv.vval.v_number = regname == buf[0]
7175 ? VVAL_TRUE : VVAL_FALSE;
Bram Moolenaar91639192020-06-29 19:55:58 +02007176 (void)dict_add(dict, item);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007177 }
7178 }
7179}
7180
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02007181 static void
7182return_register(int regname, typval_T *rettv)
7183{
7184 char_u buf[2] = {0, 0};
7185
7186 buf[0] = (char_u)regname;
7187 rettv->v_type = VAR_STRING;
7188 rettv->vval.v_string = vim_strsave(buf);
7189}
7190
7191/*
7192 * "reg_executing()" function
7193 */
7194 static void
7195f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
7196{
7197 return_register(reg_executing, rettv);
7198}
7199
7200/*
7201 * "reg_recording()" function
7202 */
7203 static void
7204f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
7205{
7206 return_register(reg_recording, rettv);
7207}
7208
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01007209/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007210 * "rename({from}, {to})" function
7211 */
7212 static void
7213f_rename(typval_T *argvars, typval_T *rettv)
7214{
7215 char_u buf[NUMBUFLEN];
7216
7217 if (check_restricted() || check_secure())
7218 rettv->vval.v_number = -1;
7219 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007220 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
7221 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007222}
7223
7224/*
7225 * "repeat()" function
7226 */
7227 static void
7228f_repeat(typval_T *argvars, typval_T *rettv)
7229{
7230 char_u *p;
7231 int n;
7232 int slen;
7233 int len;
7234 char_u *r;
7235 int i;
7236
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007237 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238 if (argvars[0].v_type == VAR_LIST)
7239 {
7240 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
7241 while (n-- > 0)
7242 if (list_extend(rettv->vval.v_list,
7243 argvars[0].vval.v_list, NULL) == FAIL)
7244 break;
7245 }
7246 else
7247 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007248 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007249 rettv->v_type = VAR_STRING;
7250 rettv->vval.v_string = NULL;
7251
7252 slen = (int)STRLEN(p);
7253 len = slen * n;
7254 if (len <= 0)
7255 return;
7256
7257 r = alloc(len + 1);
7258 if (r != NULL)
7259 {
7260 for (i = 0; i < n; i++)
7261 mch_memmove(r + i * slen, p, (size_t)slen);
7262 r[len] = NUL;
7263 }
7264
7265 rettv->vval.v_string = r;
7266 }
7267}
7268
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007269#define SP_NOMOVE 0x01 // don't move cursor
7270#define SP_REPEAT 0x02 // repeat to find outer pair
7271#define SP_RETCOUNT 0x04 // return matchcount
7272#define SP_SETPCMARK 0x08 // set previous context mark
7273#define SP_START 0x10 // accept match at start position
7274#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
7275#define SP_END 0x40 // leave cursor at end of match
7276#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007277
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007278/*
7279 * Get flags for a search function.
7280 * Possibly sets "p_ws".
7281 * Returns BACKWARD, FORWARD or zero (for an error).
7282 */
7283 static int
7284get_search_arg(typval_T *varp, int *flagsp)
7285{
7286 int dir = FORWARD;
7287 char_u *flags;
7288 char_u nbuf[NUMBUFLEN];
7289 int mask;
7290
7291 if (varp->v_type != VAR_UNKNOWN)
7292 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007293 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007295 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007296 while (*flags != NUL)
7297 {
7298 switch (*flags)
7299 {
7300 case 'b': dir = BACKWARD; break;
7301 case 'w': p_ws = TRUE; break;
7302 case 'W': p_ws = FALSE; break;
7303 default: mask = 0;
7304 if (flagsp != NULL)
7305 switch (*flags)
7306 {
7307 case 'c': mask = SP_START; break;
7308 case 'e': mask = SP_END; break;
7309 case 'm': mask = SP_RETCOUNT; break;
7310 case 'n': mask = SP_NOMOVE; break;
7311 case 'p': mask = SP_SUBPAT; break;
7312 case 'r': mask = SP_REPEAT; break;
7313 case 's': mask = SP_SETPCMARK; break;
7314 case 'z': mask = SP_COLUMN; break;
7315 }
7316 if (mask == 0)
7317 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007318 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319 dir = 0;
7320 }
7321 else
7322 *flagsp |= mask;
7323 }
7324 if (dir == 0)
7325 break;
7326 ++flags;
7327 }
7328 }
7329 return dir;
7330}
7331
7332/*
7333 * Shared by search() and searchpos() functions.
7334 */
7335 static int
7336search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
7337{
7338 int flags;
7339 char_u *pat;
7340 pos_T pos;
7341 pos_T save_cursor;
7342 int save_p_ws = p_ws;
7343 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007344 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007347 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007348 long time_limit = 0;
7349#endif
7350 int options = SEARCH_KEEP;
7351 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007352 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02007353 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007354 pos_T firstpos;
7355
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007356 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007357 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358 if (dir == 0)
7359 goto theend;
7360 flags = *flagsp;
7361 if (flags & SP_START)
7362 options |= SEARCH_START;
7363 if (flags & SP_END)
7364 options |= SEARCH_END;
7365 if (flags & SP_COLUMN)
7366 options |= SEARCH_COL;
7367
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007368 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007369 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
7370 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007371 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007372 if (lnum_stop < 0)
7373 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 if (argvars[3].v_type != VAR_UNKNOWN)
7375 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007376#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007378 if (time_limit < 0)
7379 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007380#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02007381 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007382 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383 }
7384
7385#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007386 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 profile_setlimit(time_limit, &tm);
7388#endif
7389
7390 /*
7391 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
7392 * Check to make sure only those flags are set.
7393 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
7394 * flags cannot be set. Check for that condition also.
7395 */
7396 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
7397 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7398 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007399 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007400 goto theend;
7401 }
7402
7403 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007404 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02007405 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007406 sia.sa_stop_lnum = (linenr_T)lnum_stop;
7407#ifdef FEAT_RELTIME
7408 sia.sa_tm = &tm;
7409#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007410
7411 // Repeat until {skip} returns FALSE.
7412 for (;;)
7413 {
7414 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007415 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007416 // finding the first match again means there is no match where {skip}
7417 // evaluates to zero.
7418 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
7419 subpatnum = FAIL;
7420
Bram Moolenaara9c01042020-06-07 14:50:50 +02007421 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007422 // didn't find it or no skip argument
7423 break;
7424 firstpos = pos;
7425
Bram Moolenaara9c01042020-06-07 14:50:50 +02007426 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007427 {
7428 int do_skip;
7429 int err;
7430 pos_T save_pos = curwin->w_cursor;
7431
7432 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02007433 err = FALSE;
7434 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007435 curwin->w_cursor = save_pos;
7436 if (err)
7437 {
7438 // Evaluating {skip} caused an error, break here.
7439 subpatnum = FAIL;
7440 break;
7441 }
7442 if (!do_skip)
7443 break;
7444 }
7445 }
7446
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007447 if (subpatnum != FAIL)
7448 {
7449 if (flags & SP_SUBPAT)
7450 retval = subpatnum;
7451 else
7452 retval = pos.lnum;
7453 if (flags & SP_SETPCMARK)
7454 setpcmark();
7455 curwin->w_cursor = pos;
7456 if (match_pos != NULL)
7457 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007458 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007459 match_pos->lnum = pos.lnum;
7460 match_pos->col = pos.col + 1;
7461 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007462 // "/$" will put the cursor after the end of the line, may need to
7463 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464 check_cursor();
7465 }
7466
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007467 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007468 if (flags & SP_NOMOVE)
7469 curwin->w_cursor = save_cursor;
7470 else
7471 curwin->w_set_curswant = TRUE;
7472theend:
7473 p_ws = save_p_ws;
7474
7475 return retval;
7476}
7477
7478#ifdef FEAT_FLOAT
7479
7480/*
7481 * round() is not in C90, use ceil() or floor() instead.
7482 */
7483 float_T
7484vim_round(float_T f)
7485{
7486 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
7487}
7488
7489/*
7490 * "round({float})" function
7491 */
7492 static void
7493f_round(typval_T *argvars, typval_T *rettv)
7494{
7495 float_T f = 0.0;
7496
7497 rettv->v_type = VAR_FLOAT;
7498 if (get_float_arg(argvars, &f) == OK)
7499 rettv->vval.v_float = vim_round(f);
7500 else
7501 rettv->vval.v_float = 0.0;
7502}
7503#endif
7504
Bram Moolenaare99be0e2019-03-26 22:51:09 +01007505#ifdef FEAT_RUBY
7506/*
7507 * "rubyeval()" function
7508 */
7509 static void
7510f_rubyeval(typval_T *argvars, typval_T *rettv)
7511{
7512 char_u *str;
7513 char_u buf[NUMBUFLEN];
7514
7515 str = tv_get_string_buf(&argvars[0], buf);
7516 do_rubyeval(str, rettv);
7517}
7518#endif
7519
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007520/*
7521 * "screenattr()" function
7522 */
7523 static void
7524f_screenattr(typval_T *argvars, typval_T *rettv)
7525{
7526 int row;
7527 int col;
7528 int c;
7529
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007530 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7531 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 if (row < 0 || row >= screen_Rows
7533 || col < 0 || col >= screen_Columns)
7534 c = -1;
7535 else
7536 c = ScreenAttrs[LineOffset[row] + col];
7537 rettv->vval.v_number = c;
7538}
7539
7540/*
7541 * "screenchar()" function
7542 */
7543 static void
7544f_screenchar(typval_T *argvars, typval_T *rettv)
7545{
7546 int row;
7547 int col;
7548 int off;
7549 int c;
7550
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007551 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7552 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007553 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554 c = -1;
7555 else
7556 {
7557 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558 if (enc_utf8 && ScreenLinesUC[off] != 0)
7559 c = ScreenLinesUC[off];
7560 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007561 c = ScreenLines[off];
7562 }
7563 rettv->vval.v_number = c;
7564}
7565
7566/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007567 * "screenchars()" function
7568 */
7569 static void
7570f_screenchars(typval_T *argvars, typval_T *rettv)
7571{
7572 int row;
7573 int col;
7574 int off;
7575 int c;
7576 int i;
7577
7578 if (rettv_list_alloc(rettv) == FAIL)
7579 return;
7580 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7581 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7582 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7583 return;
7584
7585 off = LineOffset[row] + col;
7586 if (enc_utf8 && ScreenLinesUC[off] != 0)
7587 c = ScreenLinesUC[off];
7588 else
7589 c = ScreenLines[off];
7590 list_append_number(rettv->vval.v_list, (varnumber_T)c);
7591
7592 if (enc_utf8)
7593
7594 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7595 list_append_number(rettv->vval.v_list,
7596 (varnumber_T)ScreenLinesC[i][off]);
7597}
7598
7599/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600 * "screencol()" function
7601 *
7602 * First column is 1 to be consistent with virtcol().
7603 */
7604 static void
7605f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
7606{
7607 rettv->vval.v_number = screen_screencol() + 1;
7608}
7609
7610/*
7611 * "screenrow()" function
7612 */
7613 static void
7614f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
7615{
7616 rettv->vval.v_number = screen_screenrow() + 1;
7617}
7618
7619/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007620 * "screenstring()" function
7621 */
7622 static void
7623f_screenstring(typval_T *argvars, typval_T *rettv)
7624{
7625 int row;
7626 int col;
7627 int off;
7628 int c;
7629 int i;
7630 char_u buf[MB_MAXBYTES + 1];
7631 int buflen = 0;
7632
7633 rettv->vval.v_string = NULL;
7634 rettv->v_type = VAR_STRING;
7635
7636 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7637 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7638 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7639 return;
7640
7641 off = LineOffset[row] + col;
7642 if (enc_utf8 && ScreenLinesUC[off] != 0)
7643 c = ScreenLinesUC[off];
7644 else
7645 c = ScreenLines[off];
7646 buflen += mb_char2bytes(c, buf);
7647
7648 if (enc_utf8)
7649 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7650 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
7651
7652 buf[buflen] = NUL;
7653 rettv->vval.v_string = vim_strsave(buf);
7654}
7655
7656/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657 * "search()" function
7658 */
7659 static void
7660f_search(typval_T *argvars, typval_T *rettv)
7661{
7662 int flags = 0;
7663
7664 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
7665}
7666
7667/*
7668 * "searchdecl()" function
7669 */
7670 static void
7671f_searchdecl(typval_T *argvars, typval_T *rettv)
7672{
Bram Moolenaar30788d32020-09-05 21:35:16 +02007673 int locally = TRUE;
7674 int thisblock = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007675 int error = FALSE;
7676 char_u *name;
7677
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007678 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007679
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007680 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007681 if (argvars[1].v_type != VAR_UNKNOWN)
7682 {
Bram Moolenaar30788d32020-09-05 21:35:16 +02007683 locally = !(int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007684 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar30788d32020-09-05 21:35:16 +02007685 thisblock = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007686 }
7687 if (!error && name != NULL)
7688 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
7689 locally, thisblock, SEARCH_KEEP) == FAIL;
7690}
7691
7692/*
7693 * Used by searchpair() and searchpairpos()
7694 */
7695 static int
7696searchpair_cmn(typval_T *argvars, pos_T *match_pos)
7697{
7698 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01007699 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007700 int save_p_ws = p_ws;
7701 int dir;
7702 int flags = 0;
7703 char_u nbuf1[NUMBUFLEN];
7704 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007705 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007706 long lnum_stop = 0;
7707 long time_limit = 0;
7708
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007709 // Get the three pattern arguments: start, middle, end. Will result in an
7710 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007711 spat = tv_get_string_chk(&argvars[0]);
7712 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
7713 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007715 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007717 // Handle the optional fourth argument: flags
7718 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007719 if (dir == 0)
7720 goto theend;
7721
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007722 // Don't accept SP_END or SP_SUBPAT.
7723 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007724 if ((flags & (SP_END | SP_SUBPAT)) != 0
7725 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7726 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007727 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728 goto theend;
7729 }
7730
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007731 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007732 if (flags & SP_REPEAT)
7733 p_ws = FALSE;
7734
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007735 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007736 if (argvars[3].v_type == VAR_UNKNOWN
7737 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01007738 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007739 else
7740 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02007741 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01007742 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02007743
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 if (argvars[5].v_type != VAR_UNKNOWN)
7745 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007746 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007748 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007749 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007751 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007752#ifdef FEAT_RELTIME
7753 if (argvars[6].v_type != VAR_UNKNOWN)
7754 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007755 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007757 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007758 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007760 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007761 }
7762#endif
7763 }
7764 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765
7766 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
7767 match_pos, lnum_stop, time_limit);
7768
7769theend:
7770 p_ws = save_p_ws;
7771
7772 return retval;
7773}
7774
7775/*
7776 * "searchpair()" function
7777 */
7778 static void
7779f_searchpair(typval_T *argvars, typval_T *rettv)
7780{
7781 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
7782}
7783
7784/*
7785 * "searchpairpos()" function
7786 */
7787 static void
7788f_searchpairpos(typval_T *argvars, typval_T *rettv)
7789{
7790 pos_T match_pos;
7791 int lnum = 0;
7792 int col = 0;
7793
7794 if (rettv_list_alloc(rettv) == FAIL)
7795 return;
7796
7797 if (searchpair_cmn(argvars, &match_pos) > 0)
7798 {
7799 lnum = match_pos.lnum;
7800 col = match_pos.col;
7801 }
7802
7803 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7804 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7805}
7806
7807/*
7808 * Search for a start/middle/end thing.
7809 * Used by searchpair(), see its documentation for the details.
7810 * Returns 0 or -1 for no match,
7811 */
7812 long
7813do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007814 char_u *spat, // start pattern
7815 char_u *mpat, // middle pattern
7816 char_u *epat, // end pattern
7817 int dir, // BACKWARD or FORWARD
7818 typval_T *skip, // skip expression
7819 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007820 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007821 linenr_T lnum_stop, // stop at this line if not zero
7822 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007823{
7824 char_u *save_cpo;
7825 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7826 long retval = 0;
7827 pos_T pos;
7828 pos_T firstpos;
7829 pos_T foundpos;
7830 pos_T save_cursor;
7831 pos_T save_pos;
7832 int n;
7833 int r;
7834 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007835 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007836 int err;
7837 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007838#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007839 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007840#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007842 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843 save_cpo = p_cpo;
7844 p_cpo = empty_option;
7845
7846#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007847 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848 profile_setlimit(time_limit, &tm);
7849#endif
7850
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007851 // Make two search patterns: start/end (pat2, for in nested pairs) and
7852 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02007853 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7854 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007855 if (pat2 == NULL || pat3 == NULL)
7856 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007857 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858 if (*mpat == NUL)
7859 STRCPY(pat3, pat2);
7860 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007861 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007862 spat, epat, mpat);
7863 if (flags & SP_START)
7864 options |= SEARCH_START;
7865
Bram Moolenaar48570482017-10-30 21:48:41 +01007866 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02007867 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01007868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007869 save_cursor = curwin->w_cursor;
7870 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007871 CLEAR_POS(&firstpos);
7872 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007873 pat = pat3;
7874 for (;;)
7875 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007876 searchit_arg_T sia;
7877
Bram Moolenaara80faa82020-04-12 19:37:17 +02007878 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007879 sia.sa_stop_lnum = lnum_stop;
7880#ifdef FEAT_RELTIME
7881 sia.sa_tm = &tm;
7882#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007883 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007884 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007885 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007886 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 break;
7888
7889 if (firstpos.lnum == 0)
7890 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007891 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007893 // Found the same position again. Can happen with a pattern that
7894 // has "\zs" at the end and searching backwards. Advance one
7895 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007896 if (dir == BACKWARD)
7897 decl(&pos);
7898 else
7899 incl(&pos);
7900 }
7901 foundpos = pos;
7902
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007903 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 options &= ~SEARCH_START;
7905
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007906 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007907 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908 {
7909 save_pos = curwin->w_cursor;
7910 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007911 err = FALSE;
7912 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007913 curwin->w_cursor = save_pos;
7914 if (err)
7915 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007916 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007917 curwin->w_cursor = save_cursor;
7918 retval = -1;
7919 break;
7920 }
7921 if (r)
7922 continue;
7923 }
7924
7925 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7926 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007927 // Found end when searching backwards or start when searching
7928 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007929 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007930 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931 }
7932 else
7933 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007934 // Found end when searching forward or start when searching
7935 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007937 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007938 }
7939
7940 if (nest == 0)
7941 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007942 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007943 if (flags & SP_RETCOUNT)
7944 ++retval;
7945 else
7946 retval = pos.lnum;
7947 if (flags & SP_SETPCMARK)
7948 setpcmark();
7949 curwin->w_cursor = pos;
7950 if (!(flags & SP_REPEAT))
7951 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007952 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007953 }
7954 }
7955
7956 if (match_pos != NULL)
7957 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007958 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007959 match_pos->lnum = curwin->w_cursor.lnum;
7960 match_pos->col = curwin->w_cursor.col + 1;
7961 }
7962
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007963 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007964 if ((flags & SP_NOMOVE) || retval == 0)
7965 curwin->w_cursor = save_cursor;
7966
7967theend:
7968 vim_free(pat2);
7969 vim_free(pat3);
7970 if (p_cpo == empty_option)
7971 p_cpo = save_cpo;
7972 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007973 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007974 free_string_option(save_cpo);
7975
7976 return retval;
7977}
7978
7979/*
7980 * "searchpos()" function
7981 */
7982 static void
7983f_searchpos(typval_T *argvars, typval_T *rettv)
7984{
7985 pos_T match_pos;
7986 int lnum = 0;
7987 int col = 0;
7988 int n;
7989 int flags = 0;
7990
7991 if (rettv_list_alloc(rettv) == FAIL)
7992 return;
7993
7994 n = search_cmn(argvars, &match_pos, &flags);
7995 if (n > 0)
7996 {
7997 lnum = match_pos.lnum;
7998 col = match_pos.col;
7999 }
8000
8001 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8002 list_append_number(rettv->vval.v_list, (varnumber_T)col);
8003 if (flags & SP_SUBPAT)
8004 list_append_number(rettv->vval.v_list, (varnumber_T)n);
8005}
8006
8007 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
8009{
8010 dict_T *d;
8011 dictitem_T *di;
8012 char_u *csearch;
8013
8014 if (argvars[0].v_type != VAR_DICT)
8015 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008016 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008017 return;
8018 }
8019
8020 if ((d = argvars[0].vval.v_dict) != NULL)
8021 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01008022 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023 if (csearch != NULL)
8024 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008025 if (enc_utf8)
8026 {
8027 int pcc[MAX_MCO];
8028 int c = utfc_ptr2char(csearch, pcc);
8029
8030 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
8031 }
8032 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02008034 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008035 }
8036
8037 di = dict_find(d, (char_u *)"forward", -1);
8038 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008039 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008040 ? FORWARD : BACKWARD);
8041
8042 di = dict_find(d, (char_u *)"until", -1);
8043 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008044 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008045 }
8046}
8047
8048/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02008049 * "setenv()" function
8050 */
8051 static void
8052f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
8053{
8054 char_u namebuf[NUMBUFLEN];
8055 char_u valbuf[NUMBUFLEN];
8056 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
8057
8058 if (argvars[1].v_type == VAR_SPECIAL
8059 && argvars[1].vval.v_number == VVAL_NULL)
8060 vim_unsetenv(name);
8061 else
8062 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
8063}
8064
8065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 * "setfperm({fname}, {mode})" function
8067 */
8068 static void
8069f_setfperm(typval_T *argvars, typval_T *rettv)
8070{
8071 char_u *fname;
8072 char_u modebuf[NUMBUFLEN];
8073 char_u *mode_str;
8074 int i;
8075 int mask;
8076 int mode = 0;
8077
8078 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008079 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008080 if (fname == NULL)
8081 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008082 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083 if (mode_str == NULL)
8084 return;
8085 if (STRLEN(mode_str) != 9)
8086 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008087 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008088 return;
8089 }
8090
8091 mask = 1;
8092 for (i = 8; i >= 0; --i)
8093 {
8094 if (mode_str[i] != '-')
8095 mode |= mask;
8096 mask = mask << 1;
8097 }
8098 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
8099}
8100
8101/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102 * "setpos()" function
8103 */
8104 static void
8105f_setpos(typval_T *argvars, typval_T *rettv)
8106{
8107 pos_T pos;
8108 int fnum;
8109 char_u *name;
8110 colnr_T curswant = -1;
8111
8112 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008113 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008114 if (name != NULL)
8115 {
8116 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
8117 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008118 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119 pos.col = 0;
8120 if (name[0] == '.' && name[1] == NUL)
8121 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008122 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01008123 curwin->w_cursor = pos;
8124 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008125 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01008126 curwin->w_curswant = curswant - 1;
8127 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01008129 check_cursor();
8130 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008131 }
8132 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
8133 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008134 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008135 if (setmark_pos(name[1], &pos, fnum) == OK)
8136 rettv->vval.v_number = 0;
8137 }
8138 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008139 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140 }
8141 }
8142}
8143
8144/*
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008145 * Translate a register type string to the yank type and block length
8146 */
8147 static int
8148get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
8149{
8150 char_u *stropt = *pp;
8151 switch (*stropt)
8152 {
8153 case 'v': case 'c': // character-wise selection
8154 *yank_type = MCHAR;
8155 break;
8156 case 'V': case 'l': // line-wise selection
8157 *yank_type = MLINE;
8158 break;
8159 case 'b': case Ctrl_V: // block-wise selection
8160 *yank_type = MBLOCK;
8161 if (VIM_ISDIGIT(stropt[1]))
8162 {
8163 ++stropt;
8164 *block_len = getdigits(&stropt) - 1;
8165 --stropt;
8166 }
8167 break;
8168 default:
8169 return FAIL;
8170 }
8171 *pp = stropt;
8172 return OK;
8173}
8174
8175/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 * "setreg()" function
8177 */
8178 static void
8179f_setreg(typval_T *argvars, typval_T *rettv)
8180{
8181 int regname;
8182 char_u *strregname;
8183 char_u *stropt;
8184 char_u *strval;
8185 int append;
8186 char_u yank_type;
8187 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008188 typval_T *regcontents;
8189 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008191 pointreg = 0;
8192 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008193 block_len = -1;
8194 yank_type = MAUTO;
8195 append = FALSE;
8196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008197 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008198 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008199
8200 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008201 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008202 regname = *strregname;
8203 if (regname == 0 || regname == '@')
8204 regname = '"';
8205
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008206 if (argvars[1].v_type == VAR_DICT)
8207 {
8208 dict_T *d = argvars[1].vval.v_dict;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008209 dictitem_T *di;
8210
8211 if (d == NULL || d->dv_hashtab.ht_used == 0)
8212 {
8213 // Empty dict, clear the register (like setreg(0, []))
8214 char_u *lstval[2] = {NULL, NULL};
8215 write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
8216 return;
8217 }
8218
8219 di = dict_find(d, (char_u *)"regcontents", -1);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008220 if (di != NULL)
8221 regcontents = &di->di_tv;
8222
8223 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
8224 if (stropt != NULL)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008225 {
8226 int ret = get_yank_type(&stropt, &yank_type, &block_len);
8227
8228 if (ret == FAIL || *++stropt != NUL)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008229 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008230 semsg(_(e_invargval), "value");
8231 return;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008232 }
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008233 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008234
8235 if (regname == '"')
8236 {
8237 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
8238 if (stropt != NULL)
8239 {
8240 pointreg = *stropt;
8241 regname = pointreg;
8242 }
8243 }
Bram Moolenaar6a950582020-08-28 16:39:33 +02008244 else if (dict_get_bool(d, (char_u *)"isunnamed", -1) > 0)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008245 pointreg = regname;
8246 }
8247 else
8248 regcontents = &argvars[1];
8249
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008250 if (argvars[2].v_type != VAR_UNKNOWN)
8251 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008252 if (yank_type != MAUTO)
8253 {
8254 semsg(_(e_toomanyarg), "setreg");
8255 return;
8256 }
8257
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008258 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008260 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008261 for (; *stropt != NUL; ++stropt)
8262 switch (*stropt)
8263 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008264 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 append = TRUE;
8266 break;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008267 default:
8268 get_yank_type(&stropt, &yank_type, &block_len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008269 }
8270 }
8271
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008272 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008273 {
8274 char_u **lstval;
8275 char_u **allocval;
8276 char_u buf[NUMBUFLEN];
8277 char_u **curval;
8278 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008279 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008280 listitem_T *li;
8281 int len;
8282
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008283 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008284 len = ll == NULL ? 0 : ll->lv_len;
8285
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008286 // First half: use for pointers to result lines; second half: use for
8287 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008288 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008289 if (lstval == NULL)
8290 return;
8291 curval = lstval;
8292 allocval = lstval + len + 2;
8293 curallocval = allocval;
8294
Bram Moolenaar50985eb2020-01-27 22:09:39 +01008295 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008296 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02008297 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02008298 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008299 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01008300 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008301 if (strval == NULL)
8302 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01008303 if (strval == buf)
8304 {
8305 // Need to make a copy, next tv_get_string_buf_chk() will
8306 // overwrite the string.
8307 strval = vim_strsave(buf);
8308 if (strval == NULL)
8309 goto free_lstval;
8310 *curallocval++ = strval;
8311 }
8312 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008313 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314 }
8315 *curval++ = NULL;
8316
8317 write_reg_contents_lst(regname, lstval, -1,
8318 append, yank_type, block_len);
8319free_lstval:
8320 while (curallocval > allocval)
8321 vim_free(*--curallocval);
8322 vim_free(lstval);
8323 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008324 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008325 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008326 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008327 if (strval == NULL)
8328 return;
8329 write_reg_contents_ex(regname, strval, -1,
8330 append, yank_type, block_len);
8331 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008332 if (pointreg != 0)
8333 get_yank_register(pointreg, TRUE);
8334
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008335 rettv->vval.v_number = 0;
8336}
8337
8338/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008339 * "settagstack()" function
8340 */
8341 static void
8342f_settagstack(typval_T *argvars, typval_T *rettv)
8343{
8344 static char *e_invact2 = N_("E962: Invalid action: '%s'");
8345 win_T *wp;
8346 dict_T *d;
8347 int action = 'r';
8348
8349 rettv->vval.v_number = -1;
8350
8351 // first argument: window number or id
8352 wp = find_win_by_nr_or_id(&argvars[0]);
8353 if (wp == NULL)
8354 return;
8355
8356 // second argument: dict with items to set in the tag stack
8357 if (argvars[1].v_type != VAR_DICT)
8358 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008359 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008360 return;
8361 }
8362 d = argvars[1].vval.v_dict;
8363 if (d == NULL)
8364 return;
8365
8366 // third argument: action - 'a' for append and 'r' for replace.
8367 // default is to replace the stack.
8368 if (argvars[2].v_type == VAR_UNKNOWN)
8369 action = 'r';
8370 else if (argvars[2].v_type == VAR_STRING)
8371 {
8372 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008373 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008374 if (actstr == NULL)
8375 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01008376 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
8377 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008378 action = *actstr;
8379 else
8380 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008381 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008382 return;
8383 }
8384 }
8385 else
8386 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008387 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008388 return;
8389 }
8390
8391 if (set_tagstack(wp, d, action) == OK)
8392 rettv->vval.v_number = 0;
8393}
8394
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008395#ifdef FEAT_CRYPT
8396/*
8397 * "sha256({string})" function
8398 */
8399 static void
8400f_sha256(typval_T *argvars, typval_T *rettv)
8401{
8402 char_u *p;
8403
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008404 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008405 rettv->vval.v_string = vim_strsave(
8406 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
8407 rettv->v_type = VAR_STRING;
8408}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008409#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008410
8411/*
8412 * "shellescape({string})" function
8413 */
8414 static void
8415f_shellescape(typval_T *argvars, typval_T *rettv)
8416{
Bram Moolenaar20615522017-06-05 18:46:26 +02008417 int do_special = non_zero_arg(&argvars[1]);
8418
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008419 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008420 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008421 rettv->v_type = VAR_STRING;
8422}
8423
8424/*
8425 * shiftwidth() function
8426 */
8427 static void
8428f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
8429{
Bram Moolenaarf9514162018-11-22 03:08:29 +01008430 rettv->vval.v_number = 0;
8431
8432 if (argvars[0].v_type != VAR_UNKNOWN)
8433 {
8434 long col;
8435
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008436 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01008437 if (col < 0)
8438 return; // type error; errmsg already given
8439#ifdef FEAT_VARTABS
8440 rettv->vval.v_number = get_sw_value_col(curbuf, col);
8441 return;
8442#endif
8443 }
8444
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008445 rettv->vval.v_number = get_sw_value(curbuf);
8446}
8447
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448#ifdef FEAT_FLOAT
8449/*
8450 * "sin()" function
8451 */
8452 static void
8453f_sin(typval_T *argvars, typval_T *rettv)
8454{
8455 float_T f = 0.0;
8456
8457 rettv->v_type = VAR_FLOAT;
8458 if (get_float_arg(argvars, &f) == OK)
8459 rettv->vval.v_float = sin(f);
8460 else
8461 rettv->vval.v_float = 0.0;
8462}
8463
8464/*
8465 * "sinh()" function
8466 */
8467 static void
8468f_sinh(typval_T *argvars, typval_T *rettv)
8469{
8470 float_T f = 0.0;
8471
8472 rettv->v_type = VAR_FLOAT;
8473 if (get_float_arg(argvars, &f) == OK)
8474 rettv->vval.v_float = sinh(f);
8475 else
8476 rettv->vval.v_float = 0.0;
8477}
8478#endif
8479
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480/*
8481 * "soundfold({word})" function
8482 */
8483 static void
8484f_soundfold(typval_T *argvars, typval_T *rettv)
8485{
8486 char_u *s;
8487
8488 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008489 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490#ifdef FEAT_SPELL
8491 rettv->vval.v_string = eval_soundfold(s);
8492#else
8493 rettv->vval.v_string = vim_strsave(s);
8494#endif
8495}
8496
8497/*
8498 * "spellbadword()" function
8499 */
8500 static void
8501f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
8502{
8503 char_u *word = (char_u *)"";
8504 hlf_T attr = HLF_COUNT;
8505 int len = 0;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008506#ifdef FEAT_SPELL
8507 int wo_spell_save = curwin->w_p_spell;
8508
8509 if (!curwin->w_p_spell)
8510 {
8511 did_set_spelllang(curwin);
8512 curwin->w_p_spell = TRUE;
8513 }
8514
8515 if (*curwin->w_s->b_p_spl == NUL)
8516 {
8517 emsg(_(e_no_spell));
8518 curwin->w_p_spell = wo_spell_save;
8519 return;
8520 }
8521#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008522
8523 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008524 {
8525#ifdef FEAT_SPELL
8526 curwin->w_p_spell = wo_spell_save;
8527#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008528 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008529 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530
8531#ifdef FEAT_SPELL
8532 if (argvars[0].v_type == VAR_UNKNOWN)
8533 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008534 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008535 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
8536 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008537 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008538 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008539 curwin->w_set_curswant = TRUE;
8540 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008541 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008542 else if (*curbuf->b_s.b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008543 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008544 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008545 int capcol = -1;
8546
8547 if (str != NULL)
8548 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008549 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008550 while (*str != NUL)
8551 {
8552 len = spell_check(curwin, str, &attr, &capcol, FALSE);
8553 if (attr != HLF_COUNT)
8554 {
8555 word = str;
8556 break;
8557 }
8558 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02008559 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02008560 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008561 }
8562 }
8563 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008564 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008565#endif
8566
8567 list_append_string(rettv->vval.v_list, word, len);
8568 list_append_string(rettv->vval.v_list, (char_u *)(
8569 attr == HLF_SPB ? "bad" :
8570 attr == HLF_SPR ? "rare" :
8571 attr == HLF_SPL ? "local" :
8572 attr == HLF_SPC ? "caps" :
8573 ""), -1);
8574}
8575
8576/*
8577 * "spellsuggest()" function
8578 */
8579 static void
8580f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
8581{
8582#ifdef FEAT_SPELL
8583 char_u *str;
8584 int typeerr = FALSE;
8585 int maxcount;
8586 garray_T ga;
8587 int i;
8588 listitem_T *li;
8589 int need_capital = FALSE;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008590 int wo_spell_save = curwin->w_p_spell;
8591
8592 if (!curwin->w_p_spell)
8593 {
8594 did_set_spelllang(curwin);
8595 curwin->w_p_spell = TRUE;
8596 }
8597
8598 if (*curwin->w_s->b_p_spl == NUL)
8599 {
8600 emsg(_(e_no_spell));
8601 curwin->w_p_spell = wo_spell_save;
8602 return;
8603 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008604#endif
8605
8606 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008607 {
8608#ifdef FEAT_SPELL
8609 curwin->w_p_spell = wo_spell_save;
8610#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008611 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008612 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008613
8614#ifdef FEAT_SPELL
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008615 if (*curwin->w_s->b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008616 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008617 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008618 if (argvars[1].v_type != VAR_UNKNOWN)
8619 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008620 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008621 if (maxcount <= 0)
8622 return;
8623 if (argvars[2].v_type != VAR_UNKNOWN)
8624 {
Bram Moolenaar7c27f332020-09-05 22:45:55 +02008625 need_capital = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008626 if (typeerr)
8627 return;
8628 }
8629 }
8630 else
8631 maxcount = 25;
8632
8633 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
8634
8635 for (i = 0; i < ga.ga_len; ++i)
8636 {
8637 str = ((char_u **)ga.ga_data)[i];
8638
8639 li = listitem_alloc();
8640 if (li == NULL)
8641 vim_free(str);
8642 else
8643 {
8644 li->li_tv.v_type = VAR_STRING;
8645 li->li_tv.v_lock = 0;
8646 li->li_tv.vval.v_string = str;
8647 list_append(rettv->vval.v_list, li);
8648 }
8649 }
8650 ga_clear(&ga);
8651 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008652 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008653#endif
8654}
8655
8656 static void
8657f_split(typval_T *argvars, typval_T *rettv)
8658{
8659 char_u *str;
8660 char_u *end;
8661 char_u *pat = NULL;
8662 regmatch_T regmatch;
8663 char_u patbuf[NUMBUFLEN];
8664 char_u *save_cpo;
8665 int match;
8666 colnr_T col = 0;
8667 int keepempty = FALSE;
8668 int typeerr = FALSE;
8669
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008670 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008671 save_cpo = p_cpo;
8672 p_cpo = (char_u *)"";
8673
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008674 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008675 if (argvars[1].v_type != VAR_UNKNOWN)
8676 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008677 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008678 if (pat == NULL)
8679 typeerr = TRUE;
8680 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar3986b942020-09-06 16:09:04 +02008681 keepempty = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008682 }
8683 if (pat == NULL || *pat == NUL)
8684 pat = (char_u *)"[\\x01- ]\\+";
8685
8686 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02008687 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008688 if (typeerr)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02008689 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008690
8691 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8692 if (regmatch.regprog != NULL)
8693 {
8694 regmatch.rm_ic = FALSE;
8695 while (*str != NUL || keepempty)
8696 {
8697 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008698 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008699 else
8700 match = vim_regexec_nl(&regmatch, str, col);
8701 if (match)
8702 end = regmatch.startp[0];
8703 else
8704 end = str + STRLEN(str);
8705 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
8706 && *str != NUL && match && end < regmatch.endp[0]))
8707 {
8708 if (list_append_string(rettv->vval.v_list, str,
8709 (int)(end - str)) == FAIL)
8710 break;
8711 }
8712 if (!match)
8713 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01008714 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008715 if (regmatch.endp[0] > str)
8716 col = 0;
8717 else
Bram Moolenaar13505972019-01-24 15:04:48 +01008718 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008719 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 str = regmatch.endp[0];
8721 }
8722
8723 vim_regfree(regmatch.regprog);
8724 }
8725
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02008726theend:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008727 p_cpo = save_cpo;
8728}
8729
8730#ifdef FEAT_FLOAT
8731/*
8732 * "sqrt()" function
8733 */
8734 static void
8735f_sqrt(typval_T *argvars, typval_T *rettv)
8736{
8737 float_T f = 0.0;
8738
8739 rettv->v_type = VAR_FLOAT;
8740 if (get_float_arg(argvars, &f) == OK)
8741 rettv->vval.v_float = sqrt(f);
8742 else
8743 rettv->vval.v_float = 0.0;
8744}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01008745#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008746
Bram Moolenaar0387cae2019-11-29 21:07:58 +01008747#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01008748/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008749 * "str2float()" function
8750 */
8751 static void
8752f_str2float(typval_T *argvars, typval_T *rettv)
8753{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008754 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008755 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008756
Bram Moolenaar08243d22017-01-10 16:12:29 +01008757 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008758 p = skipwhite(p + 1);
8759 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01008760 if (isneg)
8761 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008762 rettv->v_type = VAR_FLOAT;
8763}
8764#endif
8765
8766/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02008767 * "str2list()" function
8768 */
8769 static void
8770f_str2list(typval_T *argvars, typval_T *rettv)
8771{
8772 char_u *p;
8773 int utf8 = FALSE;
8774
8775 if (rettv_list_alloc(rettv) == FAIL)
8776 return;
8777
8778 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaara48f7862020-09-05 20:16:57 +02008779 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar9d401282019-04-06 13:18:12 +02008780
8781 p = tv_get_string(&argvars[0]);
8782
8783 if (has_mbyte || utf8)
8784 {
8785 int (*ptr2len)(char_u *);
8786 int (*ptr2char)(char_u *);
8787
8788 if (utf8 || enc_utf8)
8789 {
8790 ptr2len = utf_ptr2len;
8791 ptr2char = utf_ptr2char;
8792 }
8793 else
8794 {
8795 ptr2len = mb_ptr2len;
8796 ptr2char = mb_ptr2char;
8797 }
8798
8799 for ( ; *p != NUL; p += (*ptr2len)(p))
8800 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8801 }
8802 else
8803 for ( ; *p != NUL; ++p)
8804 list_append_number(rettv->vval.v_list, *p);
8805}
8806
8807/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008808 * "str2nr()" function
8809 */
8810 static void
8811f_str2nr(typval_T *argvars, typval_T *rettv)
8812{
8813 int base = 10;
8814 char_u *p;
8815 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008816 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008817 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008818
8819 if (argvars[1].v_type != VAR_UNKNOWN)
8820 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008821 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008822 if (base != 2 && base != 8 && base != 10 && base != 16)
8823 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008824 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008825 return;
8826 }
Bram Moolenaar3986b942020-09-06 16:09:04 +02008827 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2]))
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008828 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008829 }
8830
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008831 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008832 isneg = (*p == '-');
8833 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008834 p = skipwhite(p + 1);
8835 switch (base)
8836 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008837 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02008838 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008839 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008840 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008841 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8842 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008843 if (isneg)
8844 rettv->vval.v_number = -n;
8845 else
8846 rettv->vval.v_number = n;
8847
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008848}
8849
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008850/*
8851 * "strgetchar()" function
8852 */
8853 static void
8854f_strgetchar(typval_T *argvars, typval_T *rettv)
8855{
8856 char_u *str;
8857 int len;
8858 int error = FALSE;
8859 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008860 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008861
8862 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008863 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008864 if (str == NULL)
8865 return;
8866 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008867 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008868 if (error)
8869 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008870
Bram Moolenaar13505972019-01-24 15:04:48 +01008871 while (charidx >= 0 && byteidx < len)
8872 {
8873 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008874 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008875 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8876 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008877 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008878 --charidx;
8879 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008880 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008881}
8882
8883/*
8884 * "stridx()" function
8885 */
8886 static void
8887f_stridx(typval_T *argvars, typval_T *rettv)
8888{
8889 char_u buf[NUMBUFLEN];
8890 char_u *needle;
8891 char_u *haystack;
8892 char_u *save_haystack;
8893 char_u *pos;
8894 int start_idx;
8895
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008896 needle = tv_get_string_chk(&argvars[1]);
8897 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008898 rettv->vval.v_number = -1;
8899 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008900 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008901
8902 if (argvars[2].v_type != VAR_UNKNOWN)
8903 {
8904 int error = FALSE;
8905
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008906 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008907 if (error || start_idx >= (int)STRLEN(haystack))
8908 return;
8909 if (start_idx >= 0)
8910 haystack += start_idx;
8911 }
8912
8913 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8914 if (pos != NULL)
8915 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8916}
8917
8918/*
8919 * "string()" function
8920 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008921 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008922f_string(typval_T *argvars, typval_T *rettv)
8923{
8924 char_u *tofree;
8925 char_u numbuf[NUMBUFLEN];
8926
8927 rettv->v_type = VAR_STRING;
8928 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8929 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008930 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008931 if (rettv->vval.v_string != NULL && tofree == NULL)
8932 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8933}
8934
8935/*
8936 * "strlen()" function
8937 */
8938 static void
8939f_strlen(typval_T *argvars, typval_T *rettv)
8940{
8941 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008942 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008943}
8944
8945/*
8946 * "strchars()" function
8947 */
8948 static void
8949f_strchars(typval_T *argvars, typval_T *rettv)
8950{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008951 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar3986b942020-09-06 16:09:04 +02008952 int skipcc = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008953 varnumber_T len = 0;
8954 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008955
8956 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar3986b942020-09-06 16:09:04 +02008957 skipcc = (int)tv_get_bool(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008958 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarbade44e2020-09-26 22:39:24 +02008959 semsg(_(e_using_number_as_bool_nr), skipcc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008960 else
8961 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008962 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8963 while (*s != NUL)
8964 {
8965 func_mb_ptr2char_adv(&s);
8966 ++len;
8967 }
8968 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008969 }
8970}
8971
8972/*
8973 * "strdisplaywidth()" function
8974 */
8975 static void
8976f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8977{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008978 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008979 int col = 0;
8980
8981 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008982 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008983
8984 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8985}
8986
8987/*
8988 * "strwidth()" function
8989 */
8990 static void
8991f_strwidth(typval_T *argvars, typval_T *rettv)
8992{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008993 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008994
Bram Moolenaar13505972019-01-24 15:04:48 +01008995 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008996}
8997
8998/*
8999 * "strcharpart()" function
9000 */
9001 static void
9002f_strcharpart(typval_T *argvars, typval_T *rettv)
9003{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009004 char_u *p;
9005 int nchar;
9006 int nbyte = 0;
9007 int charlen;
9008 int len = 0;
9009 int slen;
9010 int error = FALSE;
9011
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009012 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009013 slen = (int)STRLEN(p);
9014
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009015 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009016 if (!error)
9017 {
9018 if (nchar > 0)
9019 while (nchar > 0 && nbyte < slen)
9020 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02009021 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009022 --nchar;
9023 }
9024 else
9025 nbyte = nchar;
9026 if (argvars[2].v_type != VAR_UNKNOWN)
9027 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009028 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009029 while (charlen > 0 && nbyte + len < slen)
9030 {
9031 int off = nbyte + len;
9032
9033 if (off < 0)
9034 len += 1;
9035 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02009036 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009037 --charlen;
9038 }
9039 }
9040 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009041 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009042 }
9043
9044 /*
9045 * Only return the overlap between the specified part and the actual
9046 * string.
9047 */
9048 if (nbyte < 0)
9049 {
9050 len += nbyte;
9051 nbyte = 0;
9052 }
9053 else if (nbyte > slen)
9054 nbyte = slen;
9055 if (len < 0)
9056 len = 0;
9057 else if (nbyte + len > slen)
9058 len = slen - nbyte;
9059
9060 rettv->v_type = VAR_STRING;
9061 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009062}
9063
9064/*
9065 * "strpart()" function
9066 */
9067 static void
9068f_strpart(typval_T *argvars, typval_T *rettv)
9069{
9070 char_u *p;
9071 int n;
9072 int len;
9073 int slen;
9074 int error = FALSE;
9075
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009076 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009077 slen = (int)STRLEN(p);
9078
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009079 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009080 if (error)
9081 len = 0;
9082 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009083 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009084 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009085 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009086
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02009087 // Only return the overlap between the specified part and the actual
9088 // string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009089 if (n < 0)
9090 {
9091 len += n;
9092 n = 0;
9093 }
9094 else if (n > slen)
9095 n = slen;
9096 if (len < 0)
9097 len = 0;
9098 else if (n + len > slen)
9099 len = slen - n;
9100
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02009101 if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN)
9102 {
9103 int off;
9104
9105 // length in characters
9106 for (off = n; off < slen && len > 0; --len)
9107 off += mb_ptr2len(p + off);
9108 len = off - n;
9109 }
9110
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009111 rettv->v_type = VAR_STRING;
9112 rettv->vval.v_string = vim_strnsave(p + n, len);
9113}
9114
9115/*
9116 * "strridx()" function
9117 */
9118 static void
9119f_strridx(typval_T *argvars, typval_T *rettv)
9120{
9121 char_u buf[NUMBUFLEN];
9122 char_u *needle;
9123 char_u *haystack;
9124 char_u *rest;
9125 char_u *lastmatch = NULL;
9126 int haystack_len, end_idx;
9127
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009128 needle = tv_get_string_chk(&argvars[1]);
9129 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009130
9131 rettv->vval.v_number = -1;
9132 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009133 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009134
9135 haystack_len = (int)STRLEN(haystack);
9136 if (argvars[2].v_type != VAR_UNKNOWN)
9137 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009138 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009139 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009140 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009141 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009142 }
9143 else
9144 end_idx = haystack_len;
9145
9146 if (*needle == NUL)
9147 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009148 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009149 lastmatch = haystack + end_idx;
9150 }
9151 else
9152 {
9153 for (rest = haystack; *rest != '\0'; ++rest)
9154 {
9155 rest = (char_u *)strstr((char *)rest, (char *)needle);
9156 if (rest == NULL || rest > haystack + end_idx)
9157 break;
9158 lastmatch = rest;
9159 }
9160 }
9161
9162 if (lastmatch == NULL)
9163 rettv->vval.v_number = -1;
9164 else
9165 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
9166}
9167
9168/*
9169 * "strtrans()" function
9170 */
9171 static void
9172f_strtrans(typval_T *argvars, typval_T *rettv)
9173{
9174 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009175 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009176}
9177
9178/*
9179 * "submatch()" function
9180 */
9181 static void
9182f_submatch(typval_T *argvars, typval_T *rettv)
9183{
9184 int error = FALSE;
9185 int no;
9186 int retList = 0;
9187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009188 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009189 if (error)
9190 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02009191 if (no < 0 || no >= NSUBEXP)
9192 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009193 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01009194 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02009195 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009196 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaarad304702020-09-06 18:22:53 +02009197 retList = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009198 if (error)
9199 return;
9200
9201 if (retList == 0)
9202 {
9203 rettv->v_type = VAR_STRING;
9204 rettv->vval.v_string = reg_submatch(no);
9205 }
9206 else
9207 {
9208 rettv->v_type = VAR_LIST;
9209 rettv->vval.v_list = reg_submatch_list(no);
9210 }
9211}
9212
9213/*
9214 * "substitute()" function
9215 */
9216 static void
9217f_substitute(typval_T *argvars, typval_T *rettv)
9218{
9219 char_u patbuf[NUMBUFLEN];
9220 char_u subbuf[NUMBUFLEN];
9221 char_u flagsbuf[NUMBUFLEN];
9222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009223 char_u *str = tv_get_string_chk(&argvars[0]);
9224 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009225 char_u *sub = NULL;
9226 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009227 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009228
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009229 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
9230 expr = &argvars[2];
9231 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009232 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009233
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009234 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009235 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
9236 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009237 rettv->vval.v_string = NULL;
9238 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009239 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009240}
9241
9242/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02009243 * "swapinfo(swap_filename)" function
9244 */
9245 static void
9246f_swapinfo(typval_T *argvars, typval_T *rettv)
9247{
9248 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009249 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02009250}
9251
9252/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02009253 * "swapname(expr)" function
9254 */
9255 static void
9256f_swapname(typval_T *argvars, typval_T *rettv)
9257{
9258 buf_T *buf;
9259
9260 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009261 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02009262 if (buf == NULL || buf->b_ml.ml_mfp == NULL
9263 || buf->b_ml.ml_mfp->mf_fname == NULL)
9264 rettv->vval.v_string = NULL;
9265 else
9266 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
9267}
9268
9269/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009270 * "synID(lnum, col, trans)" function
9271 */
9272 static void
9273f_synID(typval_T *argvars UNUSED, typval_T *rettv)
9274{
9275 int id = 0;
9276#ifdef FEAT_SYN_HL
9277 linenr_T lnum;
9278 colnr_T col;
9279 int trans;
9280 int transerr = FALSE;
9281
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009282 lnum = tv_get_lnum(argvars); // -1 on type error
9283 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaarfcb6d702020-09-05 21:41:56 +02009284 trans = (int)tv_get_bool_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009285
9286 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9287 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
9288 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
9289#endif
9290
9291 rettv->vval.v_number = id;
9292}
9293
9294/*
9295 * "synIDattr(id, what [, mode])" function
9296 */
9297 static void
9298f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
9299{
9300 char_u *p = NULL;
9301#ifdef FEAT_SYN_HL
9302 int id;
9303 char_u *what;
9304 char_u *mode;
9305 char_u modebuf[NUMBUFLEN];
9306 int modec;
9307
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009308 id = (int)tv_get_number(&argvars[0]);
9309 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009310 if (argvars[2].v_type != VAR_UNKNOWN)
9311 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009312 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009313 modec = TOLOWER_ASC(mode[0]);
9314 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009315 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009316 }
9317 else
9318 {
9319#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
9320 if (USE_24BIT)
9321 modec = 'g';
9322 else
9323#endif
9324 if (t_colors > 1)
9325 modec = 'c';
9326 else
9327 modec = 't';
9328 }
9329
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009330 switch (TOLOWER_ASC(what[0]))
9331 {
9332 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009333 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009334 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009335 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009336 p = highlight_has_attr(id, HL_BOLD, modec);
9337 break;
9338
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009339 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009340 p = highlight_color(id, what, modec);
9341 break;
9342
9343 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009344 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009345 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009346 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009347 p = highlight_has_attr(id, HL_ITALIC, modec);
9348 break;
9349
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009350 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02009351 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009352 break;
9353
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009354 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009355 p = highlight_has_attr(id, HL_INVERSE, modec);
9356 break;
9357
9358 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009359 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009360 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009361 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02009362 else if (TOLOWER_ASC(what[1]) == 't' &&
9363 TOLOWER_ASC(what[2]) == 'r')
9364 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009365 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009366 p = highlight_has_attr(id, HL_STANDOUT, modec);
9367 break;
9368
9369 case 'u':
Bram Moolenaar391c3622020-09-29 20:59:17 +02009370 if (TOLOWER_ASC(what[1]) == 'l') // ul
9371 p = highlight_color(id, what, modec);
9372 else if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009373 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009374 p = highlight_has_attr(id, HL_UNDERLINE, modec);
9375 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009376 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009377 p = highlight_has_attr(id, HL_UNDERCURL, modec);
9378 break;
9379 }
9380
9381 if (p != NULL)
9382 p = vim_strsave(p);
9383#endif
9384 rettv->v_type = VAR_STRING;
9385 rettv->vval.v_string = p;
9386}
9387
9388/*
9389 * "synIDtrans(id)" function
9390 */
9391 static void
9392f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
9393{
9394 int id;
9395
9396#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009397 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009398
9399 if (id > 0)
9400 id = syn_get_final_id(id);
9401 else
9402#endif
9403 id = 0;
9404
9405 rettv->vval.v_number = id;
9406}
9407
9408/*
9409 * "synconcealed(lnum, col)" function
9410 */
9411 static void
9412f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
9413{
9414#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9415 linenr_T lnum;
9416 colnr_T col;
9417 int syntax_flags = 0;
9418 int cchar;
9419 int matchid = 0;
9420 char_u str[NUMBUFLEN];
9421#endif
9422
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009423 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009424
9425#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009426 lnum = tv_get_lnum(argvars); // -1 on type error
9427 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009428
Bram Moolenaara80faa82020-04-12 19:37:17 +02009429 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009430
9431 if (rettv_list_alloc(rettv) != FAIL)
9432 {
9433 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9434 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9435 && curwin->w_p_cole > 0)
9436 {
9437 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
9438 syntax_flags = get_syntax_info(&matchid);
9439
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009440 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009441 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
9442 {
9443 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02009444 if (cchar == NUL && curwin->w_p_cole == 1)
9445 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009446 if (cchar != NUL)
9447 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009448 if (has_mbyte)
9449 (*mb_char2bytes)(cchar, str);
9450 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009451 str[0] = cchar;
9452 }
9453 }
9454 }
9455
9456 list_append_number(rettv->vval.v_list,
9457 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009458 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009459 list_append_string(rettv->vval.v_list, str, -1);
9460 list_append_number(rettv->vval.v_list, matchid);
9461 }
9462#endif
9463}
9464
9465/*
9466 * "synstack(lnum, col)" function
9467 */
9468 static void
9469f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
9470{
9471#ifdef FEAT_SYN_HL
9472 linenr_T lnum;
9473 colnr_T col;
9474 int i;
9475 int id;
9476#endif
9477
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009478 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009479
9480#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009481 lnum = tv_get_lnum(argvars); // -1 on type error
9482 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009483
9484 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9485 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9486 && rettv_list_alloc(rettv) != FAIL)
9487 {
9488 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
9489 for (i = 0; ; ++i)
9490 {
9491 id = syn_get_stack_item(i);
9492 if (id < 0)
9493 break;
9494 if (list_append_number(rettv->vval.v_list, id) == FAIL)
9495 break;
9496 }
9497 }
9498#endif
9499}
9500
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009501/*
9502 * "tabpagebuflist()" function
9503 */
9504 static void
9505f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9506{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009507 tabpage_T *tp;
9508 win_T *wp = NULL;
9509
9510 if (argvars[0].v_type == VAR_UNKNOWN)
9511 wp = firstwin;
9512 else
9513 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009514 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009515 if (tp != NULL)
9516 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9517 }
9518 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
9519 {
9520 for (; wp != NULL; wp = wp->w_next)
9521 if (list_append_number(rettv->vval.v_list,
9522 wp->w_buffer->b_fnum) == FAIL)
9523 break;
9524 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009525}
9526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009527/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009528 * "tagfiles()" function
9529 */
9530 static void
9531f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
9532{
9533 char_u *fname;
9534 tagname_T tn;
9535 int first;
9536
9537 if (rettv_list_alloc(rettv) == FAIL)
9538 return;
9539 fname = alloc(MAXPATHL);
9540 if (fname == NULL)
9541 return;
9542
9543 for (first = TRUE; ; first = FALSE)
9544 if (get_tagfname(&tn, first, fname) == FAIL
9545 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
9546 break;
9547 tagname_free(&tn);
9548 vim_free(fname);
9549}
9550
9551/*
9552 * "taglist()" function
9553 */
9554 static void
9555f_taglist(typval_T *argvars, typval_T *rettv)
9556{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009557 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009558 char_u *tag_pattern;
9559
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009560 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009561
9562 rettv->vval.v_number = FALSE;
9563 if (*tag_pattern == NUL)
9564 return;
9565
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009566 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009567 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009568 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009569 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009570}
9571
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009572#ifdef FEAT_FLOAT
9573/*
9574 * "tan()" function
9575 */
9576 static void
9577f_tan(typval_T *argvars, typval_T *rettv)
9578{
9579 float_T f = 0.0;
9580
9581 rettv->v_type = VAR_FLOAT;
9582 if (get_float_arg(argvars, &f) == OK)
9583 rettv->vval.v_float = tan(f);
9584 else
9585 rettv->vval.v_float = 0.0;
9586}
9587
9588/*
9589 * "tanh()" function
9590 */
9591 static void
9592f_tanh(typval_T *argvars, typval_T *rettv)
9593{
9594 float_T f = 0.0;
9595
9596 rettv->v_type = VAR_FLOAT;
9597 if (get_float_arg(argvars, &f) == OK)
9598 rettv->vval.v_float = tanh(f);
9599 else
9600 rettv->vval.v_float = 0.0;
9601}
9602#endif
9603
9604/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009605 * "tolower(string)" function
9606 */
9607 static void
9608f_tolower(typval_T *argvars, typval_T *rettv)
9609{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009610 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009611 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009612}
9613
9614/*
9615 * "toupper(string)" function
9616 */
9617 static void
9618f_toupper(typval_T *argvars, typval_T *rettv)
9619{
9620 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009621 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009622}
9623
9624/*
9625 * "tr(string, fromstr, tostr)" function
9626 */
9627 static void
9628f_tr(typval_T *argvars, typval_T *rettv)
9629{
9630 char_u *in_str;
9631 char_u *fromstr;
9632 char_u *tostr;
9633 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009634 int inlen;
9635 int fromlen;
9636 int tolen;
9637 int idx;
9638 char_u *cpstr;
9639 int cplen;
9640 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009641 char_u buf[NUMBUFLEN];
9642 char_u buf2[NUMBUFLEN];
9643 garray_T ga;
9644
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009645 in_str = tv_get_string(&argvars[0]);
9646 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
9647 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009648
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009649 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009650 rettv->v_type = VAR_STRING;
9651 rettv->vval.v_string = NULL;
9652 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009653 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009654 ga_init2(&ga, (int)sizeof(char), 80);
9655
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009656 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009657 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009658 if (STRLEN(fromstr) != STRLEN(tostr))
9659 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009660error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009661 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009662 ga_clear(&ga);
9663 return;
9664 }
9665
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009666 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009667 while (*in_str != NUL)
9668 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009669 if (has_mbyte)
9670 {
9671 inlen = (*mb_ptr2len)(in_str);
9672 cpstr = in_str;
9673 cplen = inlen;
9674 idx = 0;
9675 for (p = fromstr; *p != NUL; p += fromlen)
9676 {
9677 fromlen = (*mb_ptr2len)(p);
9678 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
9679 {
9680 for (p = tostr; *p != NUL; p += tolen)
9681 {
9682 tolen = (*mb_ptr2len)(p);
9683 if (idx-- == 0)
9684 {
9685 cplen = tolen;
9686 cpstr = p;
9687 break;
9688 }
9689 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009690 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009691 goto error;
9692 break;
9693 }
9694 ++idx;
9695 }
9696
9697 if (first && cpstr == in_str)
9698 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009699 // Check that fromstr and tostr have the same number of
9700 // (multi-byte) characters. Done only once when a character
9701 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009702 first = FALSE;
9703 for (p = tostr; *p != NUL; p += tolen)
9704 {
9705 tolen = (*mb_ptr2len)(p);
9706 --idx;
9707 }
9708 if (idx != 0)
9709 goto error;
9710 }
9711
9712 (void)ga_grow(&ga, cplen);
9713 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
9714 ga.ga_len += cplen;
9715
9716 in_str += inlen;
9717 }
9718 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009719 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009720 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009721 p = vim_strchr(fromstr, *in_str);
9722 if (p != NULL)
9723 ga_append(&ga, tostr[p - fromstr]);
9724 else
9725 ga_append(&ga, *in_str);
9726 ++in_str;
9727 }
9728 }
9729
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009730 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009731 (void)ga_grow(&ga, 1);
9732 ga_append(&ga, NUL);
9733
9734 rettv->vval.v_string = ga.ga_data;
9735}
9736
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009737/*
9738 * "trim({expr})" function
9739 */
9740 static void
9741f_trim(typval_T *argvars, typval_T *rettv)
9742{
9743 char_u buf1[NUMBUFLEN];
9744 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009745 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009746 char_u *mask = NULL;
9747 char_u *tail;
9748 char_u *prev;
9749 char_u *p;
9750 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009751 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009752
9753 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009754 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009755 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009756 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009757
9758 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009759 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009760 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009761
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009762 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009763 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009764 int error = 0;
9765
9766 // leading or trailing characters to trim
9767 dir = (int)tv_get_number_chk(&argvars[2], &error);
9768 if (error)
9769 return;
9770 if (dir < 0 || dir > 2)
9771 {
9772 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
9773 return;
9774 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009775 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009776 }
9777
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009778 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009779 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009780 // Trim leading characters
9781 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009782 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009783 c1 = PTR2CHAR(head);
9784 if (mask == NULL)
9785 {
9786 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009787 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009788 }
9789 else
9790 {
9791 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9792 if (c1 == PTR2CHAR(p))
9793 break;
9794 if (*p == NUL)
9795 break;
9796 }
9797 MB_PTR_ADV(head);
9798 }
9799 }
9800
9801 tail = head + STRLEN(head);
9802 if (dir == 0 || dir == 2)
9803 {
9804 // Trim trailing characters
9805 for (; tail > head; tail = prev)
9806 {
9807 prev = tail;
9808 MB_PTR_BACK(head, prev);
9809 c1 = PTR2CHAR(prev);
9810 if (mask == NULL)
9811 {
9812 if (c1 > ' ' && c1 != 0xa0)
9813 break;
9814 }
9815 else
9816 {
9817 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9818 if (c1 == PTR2CHAR(p))
9819 break;
9820 if (*p == NUL)
9821 break;
9822 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009823 }
9824 }
Bram Moolenaardf44a272020-06-07 20:49:05 +02009825 rettv->vval.v_string = vim_strnsave(head, tail - head);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009826}
9827
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009828#ifdef FEAT_FLOAT
9829/*
9830 * "trunc({float})" function
9831 */
9832 static void
9833f_trunc(typval_T *argvars, typval_T *rettv)
9834{
9835 float_T f = 0.0;
9836
9837 rettv->v_type = VAR_FLOAT;
9838 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009839 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009840 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
9841 else
9842 rettv->vval.v_float = 0.0;
9843}
9844#endif
9845
9846/*
9847 * "type(expr)" function
9848 */
9849 static void
9850f_type(typval_T *argvars, typval_T *rettv)
9851{
9852 int n = -1;
9853
9854 switch (argvars[0].v_type)
9855 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009856 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
9857 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009858 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009859 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
9860 case VAR_LIST: n = VAR_TYPE_LIST; break;
9861 case VAR_DICT: n = VAR_TYPE_DICT; break;
9862 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
9863 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
9864 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02009865 case VAR_JOB: n = VAR_TYPE_JOB; break;
9866 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009867 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009868 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02009869 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01009870 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01009871 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009872 n = -1;
9873 break;
9874 }
9875 rettv->vval.v_number = n;
9876}
9877
9878/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009879 * "virtcol(string)" function
9880 */
9881 static void
9882f_virtcol(typval_T *argvars, typval_T *rettv)
9883{
9884 colnr_T vcol = 0;
9885 pos_T *fp;
9886 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009887 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009888
9889 fp = var2fpos(&argvars[0], FALSE, &fnum);
9890 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9891 && fnum == curbuf->b_fnum)
9892 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009893 // Limit the column to a valid value, getvvcol() doesn't check.
9894 if (fp->col < 0)
9895 fp->col = 0;
9896 else
9897 {
9898 len = (int)STRLEN(ml_get(fp->lnum));
9899 if (fp->col > len)
9900 fp->col = len;
9901 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009902 getvvcol(curwin, fp, NULL, NULL, &vcol);
9903 ++vcol;
9904 }
9905
9906 rettv->vval.v_number = vcol;
9907}
9908
9909/*
9910 * "visualmode()" function
9911 */
9912 static void
9913f_visualmode(typval_T *argvars, typval_T *rettv)
9914{
9915 char_u str[2];
9916
9917 rettv->v_type = VAR_STRING;
9918 str[0] = curbuf->b_visual_mode_eval;
9919 str[1] = NUL;
9920 rettv->vval.v_string = vim_strsave(str);
9921
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009922 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009923 if (non_zero_arg(&argvars[0]))
9924 curbuf->b_visual_mode_eval = NUL;
9925}
9926
9927/*
9928 * "wildmenumode()" function
9929 */
9930 static void
9931f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9932{
9933#ifdef FEAT_WILDMENU
9934 if (wild_menu_showing)
9935 rettv->vval.v_number = 1;
9936#endif
9937}
9938
9939/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01009940 * "windowsversion()" function
9941 */
9942 static void
9943f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9944{
9945 rettv->v_type = VAR_STRING;
9946 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
9947}
9948
9949/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009950 * "wordcount()" function
9951 */
9952 static void
9953f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
9954{
9955 if (rettv_dict_alloc(rettv) == FAIL)
9956 return;
9957 cursor_pos_info(rettv->vval.v_dict);
9958}
9959
9960/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009961 * "xor(expr, expr)" function
9962 */
9963 static void
9964f_xor(typval_T *argvars, typval_T *rettv)
9965{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009966 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9967 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009968}
9969
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009970#endif // FEAT_EVAL