blob: fc8b044839fa7cb6ae572a66f9970e9b796ac92c [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020023#ifdef FEAT_FLOAT
24static void f_abs(typval_T *argvars, typval_T *rettv);
25static void f_acos(typval_T *argvars, typval_T *rettv);
26#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028#ifdef FEAT_FLOAT
29static void f_asin(typval_T *argvars, typval_T *rettv);
30static void f_atan(typval_T *argvars, typval_T *rettv);
31static void f_atan2(typval_T *argvars, typval_T *rettv);
32#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010033#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020034static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010035static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010036# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010037static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010038# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020040static void f_byte2line(typval_T *argvars, typval_T *rettv);
41static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
42static void f_byteidx(typval_T *argvars, typval_T *rettv);
43static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
44static void f_call(typval_T *argvars, typval_T *rettv);
45#ifdef FEAT_FLOAT
46static void f_ceil(typval_T *argvars, typval_T *rettv);
47#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_changenr(typval_T *argvars, typval_T *rettv);
49static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_confirm(typval_T *argvars, typval_T *rettv);
52static void f_copy(typval_T *argvars, typval_T *rettv);
53#ifdef FEAT_FLOAT
54static void f_cos(typval_T *argvars, typval_T *rettv);
55static void f_cosh(typval_T *argvars, typval_T *rettv);
56#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010058#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020059static void f_debugbreak(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010063static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020065static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_escape(typval_T *argvars, typval_T *rettv);
67static void f_eval(typval_T *argvars, typval_T *rettv);
68static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_exists(typval_T *argvars, typval_T *rettv);
71#ifdef FEAT_FLOAT
72static void f_exp(typval_T *argvars, typval_T *rettv);
73#endif
74static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020075static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077#ifdef FEAT_FLOAT
78static void f_float2nr(typval_T *argvars, typval_T *rettv);
79static void f_floor(typval_T *argvars, typval_T *rettv);
80static void f_fmod(typval_T *argvars, typval_T *rettv);
81#endif
82static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020084static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_function(typval_T *argvars, typval_T *rettv);
86static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
87static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010088static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020090static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010092static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getpid(typval_T *argvars, typval_T *rettv);
94static void f_getcurpos(typval_T *argvars, typval_T *rettv);
95static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getreg(typval_T *argvars, typval_T *rettv);
97static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010098static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
100static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_hlID(typval_T *argvars, typval_T *rettv);
102static void f_hlexists(typval_T *argvars, typval_T *rettv);
103static void f_hostname(typval_T *argvars, typval_T *rettv);
104static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_index(typval_T *argvars, typval_T *rettv);
106static void f_input(typval_T *argvars, typval_T *rettv);
107static void f_inputdialog(typval_T *argvars, typval_T *rettv);
108static void f_inputlist(typval_T *argvars, typval_T *rettv);
109static void f_inputrestore(typval_T *argvars, typval_T *rettv);
110static void f_inputsave(typval_T *argvars, typval_T *rettv);
111static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100112static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200113static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_islocked(typval_T *argvars, typval_T *rettv);
115#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200116static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_isnan(typval_T *argvars, typval_T *rettv);
118#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
120static void f_len(typval_T *argvars, typval_T *rettv);
121static void f_libcall(typval_T *argvars, typval_T *rettv);
122static void f_libcallnr(typval_T *argvars, typval_T *rettv);
123static void f_line(typval_T *argvars, typval_T *rettv);
124static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125#ifdef FEAT_FLOAT
126static void f_log(typval_T *argvars, typval_T *rettv);
127static void f_log10(typval_T *argvars, typval_T *rettv);
128#endif
129#ifdef FEAT_LUA
130static void f_luaeval(typval_T *argvars, typval_T *rettv);
131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_maparg(typval_T *argvars, typval_T *rettv);
133static void f_mapcheck(typval_T *argvars, typval_T *rettv);
134static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_matchend(typval_T *argvars, typval_T *rettv);
136static void f_matchlist(typval_T *argvars, typval_T *rettv);
137static void f_matchstr(typval_T *argvars, typval_T *rettv);
138static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
139static void f_max(typval_T *argvars, typval_T *rettv);
140static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141#ifdef FEAT_MZSCHEME
142static void f_mzeval(typval_T *argvars, typval_T *rettv);
143#endif
144static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
145static void f_nr2char(typval_T *argvars, typval_T *rettv);
146static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_PERL
148static void f_perleval(typval_T *argvars, typval_T *rettv);
149#endif
150#ifdef FEAT_FLOAT
151static void f_pow(typval_T *argvars, typval_T *rettv);
152#endif
153static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
154static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200155static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_pumvisible(typval_T *argvars, typval_T *rettv);
157#ifdef FEAT_PYTHON3
158static void f_py3eval(typval_T *argvars, typval_T *rettv);
159#endif
160#ifdef FEAT_PYTHON
161static void f_pyeval(typval_T *argvars, typval_T *rettv);
162#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
164static void f_pyxeval(typval_T *argvars, typval_T *rettv);
165#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100166static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100167static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200169static void f_reg_executing(typval_T *argvars, typval_T *rettv);
170static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_rename(typval_T *argvars, typval_T *rettv);
172static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173#ifdef FEAT_FLOAT
174static void f_round(typval_T *argvars, typval_T *rettv);
175#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100176#ifdef FEAT_RUBY
177static void f_rubyeval(typval_T *argvars, typval_T *rettv);
178#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179static void f_screenattr(typval_T *argvars, typval_T *rettv);
180static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100181static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200182static void f_screencol(typval_T *argvars, typval_T *rettv);
183static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100184static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_search(typval_T *argvars, typval_T *rettv);
186static void f_searchdecl(typval_T *argvars, typval_T *rettv);
187static void f_searchpair(typval_T *argvars, typval_T *rettv);
188static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
189static void f_searchpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200190static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200191static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100195static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196#ifdef FEAT_CRYPT
197static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200198#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200199static void f_shellescape(typval_T *argvars, typval_T *rettv);
200static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201#ifdef FEAT_FLOAT
202static void f_sin(typval_T *argvars, typval_T *rettv);
203static void f_sinh(typval_T *argvars, typval_T *rettv);
204#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200205static void f_soundfold(typval_T *argvars, typval_T *rettv);
206static void f_spellbadword(typval_T *argvars, typval_T *rettv);
207static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
208static void f_split(typval_T *argvars, typval_T *rettv);
209#ifdef FEAT_FLOAT
210static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100211#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100212static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100213#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200214static void f_str2float(typval_T *argvars, typval_T *rettv);
215#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200216static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217static void f_str2nr(typval_T *argvars, typval_T *rettv);
218static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219static void f_strgetchar(typval_T *argvars, typval_T *rettv);
220static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_strlen(typval_T *argvars, typval_T *rettv);
222static void f_strcharpart(typval_T *argvars, typval_T *rettv);
223static void f_strpart(typval_T *argvars, typval_T *rettv);
224static void f_strridx(typval_T *argvars, typval_T *rettv);
225static void f_strtrans(typval_T *argvars, typval_T *rettv);
226static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
227static void f_strwidth(typval_T *argvars, typval_T *rettv);
228static void f_submatch(typval_T *argvars, typval_T *rettv);
229static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200230static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200231static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200232static void f_synID(typval_T *argvars, typval_T *rettv);
233static void f_synIDattr(typval_T *argvars, typval_T *rettv);
234static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
235static void f_synstack(typval_T *argvars, typval_T *rettv);
236static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200237static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200238static void f_taglist(typval_T *argvars, typval_T *rettv);
239static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240#ifdef FEAT_FLOAT
241static void f_tan(typval_T *argvars, typval_T *rettv);
242static void f_tanh(typval_T *argvars, typval_T *rettv);
243#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200244static void f_tolower(typval_T *argvars, typval_T *rettv);
245static void f_toupper(typval_T *argvars, typval_T *rettv);
246static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100247static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248#ifdef FEAT_FLOAT
249static void f_trunc(typval_T *argvars, typval_T *rettv);
250#endif
251static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200252static void f_virtcol(typval_T *argvars, typval_T *rettv);
253static void f_visualmode(typval_T *argvars, typval_T *rettv);
254static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100255static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256static void f_wordcount(typval_T *argvars, typval_T *rettv);
257static void f_xor(typval_T *argvars, typval_T *rettv);
258
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100259
260 static type_T *
261ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
262{
263 return &t_void;
264}
265 static type_T *
266ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
267{
268 return &t_any;
269}
270 static type_T *
271ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
272{
273 return &t_number;
274}
275 static type_T *
276ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
277{
278 return &t_float;
279}
280 static type_T *
281ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
282{
283 return &t_string;
284}
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200285 static type_T *
286ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100287{
288 return &t_list_any;
289}
290 static type_T *
291ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
292{
293 return &t_list_number;
294}
295 static type_T *
296ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
297{
298 return &t_list_string;
299}
300 static type_T *
301ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
302{
303 return &t_list_dict_any;
304}
305 static type_T *
306ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
307{
308 return &t_dict_any;
309}
310 static type_T *
311ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
312{
313 return &t_dict_number;
314}
315 static type_T *
316ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
317{
318 return &t_dict_string;
319}
320 static type_T *
321ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
322{
323 return &t_blob;
324}
325 static type_T *
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200326ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100327{
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200328 return &t_func_any;
329}
330 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100331ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
332{
333 return &t_channel;
334}
335 static type_T *
336ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
337{
338 return &t_job;
339}
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100340
341static type_T *ret_f_function(int argcount, type_T **argtypes);
342
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200343/*
344 * Array with names and number of arguments of all internal functions
345 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
346 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200347typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200348{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200349 char *f_name; // function name
350 char f_min_argc; // minimal number of arguments
351 char f_max_argc; // maximal number of arguments
352 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100353 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
354 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200355 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200356 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200357} funcentry_T;
358
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200359// values for f_argtype; zero means it cannot be used as a method
360#define FEARG_1 1 // base is the first argument
361#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200362#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200363#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200364#define FEARG_LAST 9 // base is the last argument
365
Bram Moolenaar15c47602020-03-26 22:16:48 +0100366#ifdef FEAT_FLOAT
367# define FLOAT_FUNC(name) name
368#else
369# define FLOAT_FUNC(name) NULL
370#endif
371#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
372# define MATH_FUNC(name) name
373#else
374# define MATH_FUNC(name) NULL
375#endif
376#ifdef FEAT_TIMERS
377# define TIMER_FUNC(name) name
378#else
379# define TIMER_FUNC(name) NULL
380#endif
381#ifdef FEAT_JOB_CHANNEL
382# define JOB_FUNC(name) name
383#else
384# define JOB_FUNC(name) NULL
385#endif
386#ifdef FEAT_PROP_POPUP
387# define PROP_FUNC(name) name
388#else
389# define PROP_FUNC(name) NULL
390#endif
391#ifdef FEAT_SIGNS
392# define SIGN_FUNC(name) name
393#else
394# define SIGN_FUNC(name) NULL
395#endif
396#ifdef FEAT_SOUND
397# define SOUND_FUNC(name) name
398#else
399# define SOUND_FUNC(name) NULL
400#endif
401#ifdef FEAT_TERMINAL
402# define TERM_FUNC(name) name
403#else
404# define TERM_FUNC(name) NULL
405#endif
406
Bram Moolenaarac92e252019-08-03 21:58:38 +0200407static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200408{
Bram Moolenaar15c47602020-03-26 22:16:48 +0100409 {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)},
410 {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100411 {"add", 2, 2, FEARG_1, ret_any, f_add},
412 {"and", 2, 2, FEARG_1, ret_number, f_and},
413 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
414 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
415 {"argc", 0, 1, 0, ret_number, f_argc},
416 {"argidx", 0, 0, 0, ret_number, f_argidx},
417 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
418 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100419 {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100420 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
421 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
422 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile},
423 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
424 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
425 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
426 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
427 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
428 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
429 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
430 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
431 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100432 {"atan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_atan)},
433 {"atan2", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_atan2)},
434 {"balloon_gettext", 0, 0, 0, ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100435#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100436 f_balloon_gettext
437#else
438 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100439#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100440 },
441 {"balloon_show", 1, 1, FEARG_1, ret_void,
442#ifdef FEAT_BEVAL
443 f_balloon_show
444#else
445 NULL
446#endif
447 },
448 {"balloon_split", 1, 1, FEARG_1, ret_list_string,
449#if defined(FEAT_BEVAL_TERM)
450 f_balloon_split
451#else
452 NULL
453#endif
454 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100455 {"browse", 4, 4, 0, ret_string, f_browse},
456 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
457 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
458 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
459 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
460 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
461 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
462 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
463 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
464 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
465 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
466 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
467 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
468 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
469 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
470 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
471 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
472 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100473 {"ceil", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_ceil)},
474 {"ch_canread", 1, 1, FEARG_1, ret_number, JOB_FUNC(f_ch_canread)},
475 {"ch_close", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close)},
476 {"ch_close_in", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close_in)},
477 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalexpr)},
478 {"ch_evalraw", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalraw)},
479 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, JOB_FUNC(f_ch_getbufnr)},
480 {"ch_getjob", 1, 1, FEARG_1, ret_job, JOB_FUNC(f_ch_getjob)},
481 {"ch_info", 1, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_ch_info)},
482 {"ch_log", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_log)},
483 {"ch_logfile", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_logfile)},
484 {"ch_open", 1, 2, FEARG_1, ret_channel, JOB_FUNC(f_ch_open)},
485 {"ch_read", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_read)},
486 {"ch_readblob", 1, 2, FEARG_1, ret_blob, JOB_FUNC(f_ch_readblob)},
487 {"ch_readraw", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_readraw)},
488 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendexpr)},
489 {"ch_sendraw", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendraw)},
490 {"ch_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_setoptions)},
491 {"ch_status", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_status)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100492 {"changenr", 0, 0, 0, ret_number, f_changenr},
493 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
494 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
495 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
496 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
497 {"col", 1, 1, FEARG_1, ret_number, f_col},
498 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
499 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
500 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
501 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
502 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
503 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100504 {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)},
505 {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100506 {"count", 2, 4, FEARG_1, ret_number, f_count},
507 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
508 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100509 {"debugbreak", 1, 1, FEARG_1, ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100510#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100511 f_debugbreak
512#else
513 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200514#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100515 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100516 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
517 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
518 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
519 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
520 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
521 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
522 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
523 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
524 {"environ", 0, 0, 0, ret_dict_string, f_environ},
525 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
526 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
527 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
528 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
529 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
530 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
531 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100532 {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100533 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
534 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
535 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
536 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
537 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
538 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
539 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
540 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
541 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
542 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100543 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)},
544 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)},
545 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100546 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
547 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
548 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
549 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
550 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
551 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
552 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
553 {"foreground", 0, 0, 0, ret_void, f_foreground},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200554 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100555 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
556 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
557 {"get", 2, 3, FEARG_1, ret_any, f_get},
558 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
559 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
560 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
561 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
562 {"getchar", 0, 1, 0, ret_number, f_getchar},
563 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
564 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
565 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
566 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
567 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
568 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
569 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
570 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
571 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
572 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
573 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
574 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
575 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
576 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
577 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
578 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
579 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
580 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
581 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
582 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
583 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
584 {"getpid", 0, 0, 0, ret_number, f_getpid},
585 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
586 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
587 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
588 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
589 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
590 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
591 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
592 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
593 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
594 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
595 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
596 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
597 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
598 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
599 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
600 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100601 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100602 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
603 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
604 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
605 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
606 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
607 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
608 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
609 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
610 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
611 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
612 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
613 {"hostname", 0, 0, 0, ret_string, f_hostname},
614 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
615 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
616 {"index", 2, 4, FEARG_1, ret_number, f_index},
617 {"input", 1, 3, FEARG_1, ret_string, f_input},
618 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
619 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
620 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
621 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
622 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
623 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
624 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
625 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
626 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100627 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100628 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100629 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100630 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100631 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
632 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
633 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
634 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
635 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
636 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100637 {"join", 1, 2, FEARG_1, ret_string, f_join},
638 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
639 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
640 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
641 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
642 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
643 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
644 {"len", 1, 1, FEARG_1, ret_number, f_len},
645 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
646 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
647 {"line", 1, 2, FEARG_1, ret_number, f_line},
648 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
649 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
650 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
651 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
652 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
653 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
654 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100655 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
656 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
657 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100659 f_luaeval
660#else
661 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100663 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100664 {"map", 2, 2, FEARG_1, ret_any, f_map},
665 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
666 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200667 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100668 {"match", 2, 4, FEARG_1, ret_any, f_match},
669 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
670 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
671 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
672 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
673 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
674 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
675 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
676 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
677 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100678 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100679#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100680 f_menu_info
681#else
682 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100683#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100684 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100685 {"min", 1, 1, FEARG_1, ret_any, f_min},
686 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
687 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100688 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200689#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100690 f_mzeval
691#else
692 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100694 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100695 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
696 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
697 {"or", 2, 2, FEARG_1, ret_number, f_or},
698 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100699 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200700#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100701 f_perleval
702#else
703 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200704#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100705 },
706 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
707 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200708 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100709 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
710 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
711 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
712 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)},
713 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)},
714 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
715 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
716 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
717 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
718 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200719 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100720 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
721 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
722 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
723 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
724 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
725 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
726 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
727 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100728 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
729 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100730 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
731 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
732 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
733 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
734 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
735 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
736 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
737 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
738 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
739 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
740 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
741 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
742 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100743 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
744 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100745 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200746#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100747 f_py3eval
748#else
749 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200750#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100751 },
752 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200753#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100754 f_pyeval
755#else
756 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100758 },
759 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100760#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100761 f_pyxeval
762#else
763 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100764#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100765 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100766 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
767 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
768 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
769 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
770 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
771 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
772 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100773 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100774 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
775 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
776 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
777 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
778 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
779 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
780 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
781 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
782 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
783 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
784 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
785 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100786 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
787 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100788#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100789 f_rubyeval
790#else
791 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100792#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100793 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100794 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
795 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
796 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
797 {"screencol", 0, 0, 0, ret_number, f_screencol},
798 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
799 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
800 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
801 {"search", 1, 4, FEARG_1, ret_number, f_search},
802 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
803 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
804 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
805 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
806 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
807 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
808 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
809 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
810 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
811 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
812 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
813 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
814 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
815 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
816 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
817 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
818 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
819 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
820 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
821 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
822 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
823 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100824 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100826 f_sha256
827#else
828 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200829#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100830 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100831 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
832 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100833 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
834 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
835 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
836 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
837 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
838 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
839 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
840 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
841 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200842 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100843 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
844 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100845 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100846 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
847 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
848 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
849 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100850 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
851 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
852 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
853 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100854 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100855 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
856 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100857 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100858 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
859 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
860 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
861 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
862 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100863 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200864#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100865 f_strftime
866#else
867 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200868#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100869 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100870 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
871 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
872 {"string", 1, 1, FEARG_1, ret_string, f_string},
873 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
874 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100875 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100876#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100877 f_strptime
878#else
879 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100880#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100881 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100882 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
883 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
884 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
885 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
886 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
887 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
888 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
889 {"synID", 3, 3, 0, ret_number, f_synID},
890 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
891 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
892 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
893 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
894 {"system", 1, 2, FEARG_1, ret_string, f_system},
895 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
896 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
897 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
898 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
899 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
900 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100901 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
902 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100903 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100904 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
905 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
906 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
907 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
908 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100909#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100910 f_term_getansicolors
911#else
912 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200913#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100914 },
915 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
916 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
917 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
918 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
919 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
920 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
921 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
922 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
923 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
924 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
925 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
926 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
927 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100928#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100929 f_term_setansicolors
930#else
931 NULL
932#endif
933 },
934 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
935 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
936 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
937 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
938 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
939 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100940 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
941 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
942 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
943 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
944 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
945 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
946 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
947 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100948 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100949 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200950 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100951 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100952 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200953 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100954 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
955 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
956 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
957 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100958 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +0200959#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +0100960 f_test_scrollbar
961#else
962 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +0200963#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100964 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100965 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
966 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
967 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
968 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
969 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100970 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
971 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
972 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
973 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
974 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100975 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
976 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
977 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
978 {"trim", 1, 2, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100979 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100980 {"type", 1, 1, FEARG_1, ret_number, f_type},
981 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
982 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
983 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
984 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
985 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
986 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
987 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
988 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
989 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
990 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
991 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
992 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
993 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
994 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
995 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
996 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
997 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
998 {"wincol", 0, 0, 0, ret_number, f_wincol},
999 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1000 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1001 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1002 {"winline", 0, 0, 0, ret_number, f_winline},
1003 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1004 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1005 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1006 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1007 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1008 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1009 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1010 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001011};
1012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001013/*
1014 * Function given to ExpandGeneric() to obtain the list of internal
1015 * or user defined function names.
1016 */
1017 char_u *
1018get_function_name(expand_T *xp, int idx)
1019{
1020 static int intidx = -1;
1021 char_u *name;
1022
1023 if (idx == 0)
1024 intidx = -1;
1025 if (intidx < 0)
1026 {
1027 name = get_user_func_name(xp, idx);
1028 if (name != NULL)
1029 return name;
1030 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001031 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001032 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001033 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001034 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001035 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001036 STRCAT(IObuff, ")");
1037 return IObuff;
1038 }
1039
1040 return NULL;
1041}
1042
1043/*
1044 * Function given to ExpandGeneric() to obtain the list of internal or
1045 * user defined variable or function names.
1046 */
1047 char_u *
1048get_expr_name(expand_T *xp, int idx)
1049{
1050 static int intidx = -1;
1051 char_u *name;
1052
1053 if (idx == 0)
1054 intidx = -1;
1055 if (intidx < 0)
1056 {
1057 name = get_function_name(xp, idx);
1058 if (name != NULL)
1059 return name;
1060 }
1061 return get_user_var_name(xp, ++intidx);
1062}
1063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001064/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001065 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001066 * Return index, or -1 if not found or "implemented" is TRUE and the function
1067 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001068 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001069 static int
1070find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001071{
1072 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001073 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001074 int cmp;
1075 int x;
1076
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001077 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001078
1079 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080 while (first <= last)
1081 {
1082 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001083 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001084 if (cmp < 0)
1085 last = x - 1;
1086 else if (cmp > 0)
1087 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001088 else if (implemented && global_functions[x].f_func == NULL)
1089 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001090 else
1091 return x;
1092 }
1093 return -1;
1094}
1095
Bram Moolenaar15c47602020-03-26 22:16:48 +01001096/*
1097 * Find internal function "name" in table "global_functions".
1098 * Return index, or -1 if not found or the function is not implemented.
1099 */
1100 int
1101find_internal_func(char_u *name)
1102{
1103 return find_internal_func_opt(name, TRUE);
1104}
1105
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001106 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001107has_internal_func(char_u *name)
1108{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001109 return find_internal_func_opt(name, TRUE) >= 0;
1110}
1111
1112 static int
1113has_internal_func_name(char_u *name)
1114{
1115 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001116}
1117
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001118 char *
1119internal_func_name(int idx)
1120{
1121 return global_functions[idx].f_name;
1122}
1123
1124 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001125internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001126{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001127 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001128}
1129
1130/*
1131 * Check the argument count to use for internal function "idx".
1132 * Returns OK or FAIL;
1133 */
1134 int
1135check_internal_func(int idx, int argcount)
1136{
1137 int res;
1138 char *name;
1139
1140 if (argcount < global_functions[idx].f_min_argc)
1141 res = FCERR_TOOFEW;
1142 else if (argcount > global_functions[idx].f_max_argc)
1143 res = FCERR_TOOMANY;
1144 else
1145 return OK;
1146
1147 name = internal_func_name(idx);
1148 if (res == FCERR_TOOMANY)
1149 semsg(_(e_toomanyarg), name);
1150 else
1151 semsg(_(e_toofewarg), name);
1152 return FAIL;
1153}
1154
Bram Moolenaarac92e252019-08-03 21:58:38 +02001155 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001156call_internal_func(
1157 char_u *name,
1158 int argcount,
1159 typval_T *argvars,
1160 typval_T *rettv)
1161{
1162 int i;
1163
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001164 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001165 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001166 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001167 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001168 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001169 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001170 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001171 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001172 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001173 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001174}
1175
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001176 void
1177call_internal_func_by_idx(
1178 int idx,
1179 typval_T *argvars,
1180 typval_T *rettv)
1181{
1182 global_functions[idx].f_func(argvars, rettv);
1183}
1184
Bram Moolenaarac92e252019-08-03 21:58:38 +02001185/*
1186 * Invoke a method for base->method().
1187 */
1188 int
1189call_internal_method(
1190 char_u *name,
1191 int argcount,
1192 typval_T *argvars,
1193 typval_T *rettv,
1194 typval_T *basetv)
1195{
1196 int i;
1197 int fi;
1198 typval_T argv[MAX_FUNC_ARGS + 1];
1199
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001200 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001201 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001202 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001203 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001204 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001205 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001206 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001207 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001208 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001209
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001210 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001211 {
1212 // base value goes last
1213 for (i = 0; i < argcount; ++i)
1214 argv[i] = argvars[i];
1215 argv[argcount] = *basetv;
1216 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001217 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001218 {
1219 // base value goes second
1220 argv[0] = argvars[0];
1221 argv[1] = *basetv;
1222 for (i = 1; i < argcount; ++i)
1223 argv[i + 1] = argvars[i];
1224 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001225 else if (global_functions[fi].f_argtype == FEARG_3)
1226 {
1227 // base value goes third
1228 argv[0] = argvars[0];
1229 argv[1] = argvars[1];
1230 argv[2] = *basetv;
1231 for (i = 2; i < argcount; ++i)
1232 argv[i + 1] = argvars[i];
1233 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001234 else if (global_functions[fi].f_argtype == FEARG_4)
1235 {
1236 // base value goes fourth
1237 argv[0] = argvars[0];
1238 argv[1] = argvars[1];
1239 argv[2] = argvars[2];
1240 argv[3] = *basetv;
1241 for (i = 3; i < argcount; ++i)
1242 argv[i + 1] = argvars[i];
1243 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001244 else
1245 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001246 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001247 argv[0] = *basetv;
1248 for (i = 0; i < argcount; ++i)
1249 argv[i + 1] = argvars[i];
1250 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001251 argv[argcount + 1].v_type = VAR_UNKNOWN;
1252
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001253 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001254 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001255}
1256
1257/*
1258 * Return TRUE for a non-zero Number and a non-empty String.
1259 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001260 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001261non_zero_arg(typval_T *argvars)
1262{
1263 return ((argvars[0].v_type == VAR_NUMBER
1264 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001265 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001266 && argvars[0].vval.v_number == VVAL_TRUE)
1267 || (argvars[0].v_type == VAR_STRING
1268 && argvars[0].vval.v_string != NULL
1269 && *argvars[0].vval.v_string != NUL));
1270}
1271
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001272#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001273/*
1274 * Get the float value of "argvars[0]" into "f".
1275 * Returns FAIL when the argument is not a Number or Float.
1276 */
1277 static int
1278get_float_arg(typval_T *argvars, float_T *f)
1279{
1280 if (argvars[0].v_type == VAR_FLOAT)
1281 {
1282 *f = argvars[0].vval.v_float;
1283 return OK;
1284 }
1285 if (argvars[0].v_type == VAR_NUMBER)
1286 {
1287 *f = (float_T)argvars[0].vval.v_number;
1288 return OK;
1289 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001290 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001291 return FAIL;
1292}
1293
1294/*
1295 * "abs(expr)" function
1296 */
1297 static void
1298f_abs(typval_T *argvars, typval_T *rettv)
1299{
1300 if (argvars[0].v_type == VAR_FLOAT)
1301 {
1302 rettv->v_type = VAR_FLOAT;
1303 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1304 }
1305 else
1306 {
1307 varnumber_T n;
1308 int error = FALSE;
1309
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001310 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001311 if (error)
1312 rettv->vval.v_number = -1;
1313 else if (n > 0)
1314 rettv->vval.v_number = n;
1315 else
1316 rettv->vval.v_number = -n;
1317 }
1318}
1319
1320/*
1321 * "acos()" function
1322 */
1323 static void
1324f_acos(typval_T *argvars, typval_T *rettv)
1325{
1326 float_T f = 0.0;
1327
1328 rettv->v_type = VAR_FLOAT;
1329 if (get_float_arg(argvars, &f) == OK)
1330 rettv->vval.v_float = acos(f);
1331 else
1332 rettv->vval.v_float = 0.0;
1333}
1334#endif
1335
1336/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001337 * "and(expr, expr)" function
1338 */
1339 static void
1340f_and(typval_T *argvars, typval_T *rettv)
1341{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001342 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1343 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001344}
1345
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001346#ifdef FEAT_FLOAT
1347/*
1348 * "asin()" function
1349 */
1350 static void
1351f_asin(typval_T *argvars, typval_T *rettv)
1352{
1353 float_T f = 0.0;
1354
1355 rettv->v_type = VAR_FLOAT;
1356 if (get_float_arg(argvars, &f) == OK)
1357 rettv->vval.v_float = asin(f);
1358 else
1359 rettv->vval.v_float = 0.0;
1360}
1361
1362/*
1363 * "atan()" function
1364 */
1365 static void
1366f_atan(typval_T *argvars, typval_T *rettv)
1367{
1368 float_T f = 0.0;
1369
1370 rettv->v_type = VAR_FLOAT;
1371 if (get_float_arg(argvars, &f) == OK)
1372 rettv->vval.v_float = atan(f);
1373 else
1374 rettv->vval.v_float = 0.0;
1375}
1376
1377/*
1378 * "atan2()" function
1379 */
1380 static void
1381f_atan2(typval_T *argvars, typval_T *rettv)
1382{
1383 float_T fx = 0.0, fy = 0.0;
1384
1385 rettv->v_type = VAR_FLOAT;
1386 if (get_float_arg(argvars, &fx) == OK
1387 && get_float_arg(&argvars[1], &fy) == OK)
1388 rettv->vval.v_float = atan2(fx, fy);
1389 else
1390 rettv->vval.v_float = 0.0;
1391}
1392#endif
1393
1394/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001395 * "balloon_show()" function
1396 */
1397#ifdef FEAT_BEVAL
1398 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001399f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1400{
1401 rettv->v_type = VAR_STRING;
1402 if (balloonEval != NULL)
1403 {
1404 if (balloonEval->msg == NULL)
1405 rettv->vval.v_string = NULL;
1406 else
1407 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1408 }
1409}
1410
1411 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001412f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1413{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001414 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001415 {
1416 if (argvars[0].v_type == VAR_LIST
1417# ifdef FEAT_GUI
1418 && !gui.in_use
1419# endif
1420 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001421 {
1422 list_T *l = argvars[0].vval.v_list;
1423
1424 // empty list removes the balloon
1425 post_balloon(balloonEval, NULL,
1426 l == NULL || l->lv_len == 0 ? NULL : l);
1427 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001428 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001429 {
1430 char_u *mesg = tv_get_string_chk(&argvars[0]);
1431
1432 if (mesg != NULL)
1433 // empty string removes the balloon
1434 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1435 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001436 }
1437}
1438
Bram Moolenaar669a8282017-11-19 20:13:05 +01001439# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001440 static void
1441f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1442{
1443 if (rettv_list_alloc(rettv) == OK)
1444 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001445 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001446
1447 if (msg != NULL)
1448 {
1449 pumitem_T *array;
1450 int size = split_message(msg, &array);
1451 int i;
1452
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001453 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001454 for (i = 1; i < size - 1; ++i)
1455 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001456 while (size > 0)
1457 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001458 vim_free(array);
1459 }
1460 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001461}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001462# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001463#endif
1464
1465/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001466 * Get the buffer from "arg" and give an error and return NULL if it is not
1467 * valid.
1468 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001469 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001470get_buf_arg(typval_T *arg)
1471{
1472 buf_T *buf;
1473
1474 ++emsg_off;
1475 buf = tv_get_buf(arg, FALSE);
1476 --emsg_off;
1477 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001478 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001479 return buf;
1480}
1481
1482/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483 * "byte2line(byte)" function
1484 */
1485 static void
1486f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1487{
1488#ifndef FEAT_BYTEOFF
1489 rettv->vval.v_number = -1;
1490#else
1491 long boff = 0;
1492
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001493 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001494 if (boff < 0)
1495 rettv->vval.v_number = -1;
1496 else
1497 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1498 (linenr_T)0, &boff);
1499#endif
1500}
1501
1502 static void
1503byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1504{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001505 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506 char_u *str;
1507 varnumber_T idx;
1508
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001509 str = tv_get_string_chk(&argvars[0]);
1510 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001511 rettv->vval.v_number = -1;
1512 if (str == NULL || idx < 0)
1513 return;
1514
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001515 t = str;
1516 for ( ; idx > 0; idx--)
1517 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001518 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001519 return;
1520 if (enc_utf8 && comp)
1521 t += utf_ptr2len(t);
1522 else
1523 t += (*mb_ptr2len)(t);
1524 }
1525 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001526}
1527
1528/*
1529 * "byteidx()" function
1530 */
1531 static void
1532f_byteidx(typval_T *argvars, typval_T *rettv)
1533{
1534 byteidx(argvars, rettv, FALSE);
1535}
1536
1537/*
1538 * "byteidxcomp()" function
1539 */
1540 static void
1541f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1542{
1543 byteidx(argvars, rettv, TRUE);
1544}
1545
1546/*
1547 * "call(func, arglist [, dict])" function
1548 */
1549 static void
1550f_call(typval_T *argvars, typval_T *rettv)
1551{
1552 char_u *func;
1553 partial_T *partial = NULL;
1554 dict_T *selfdict = NULL;
1555
1556 if (argvars[1].v_type != VAR_LIST)
1557 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001558 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001559 return;
1560 }
1561 if (argvars[1].vval.v_list == NULL)
1562 return;
1563
1564 if (argvars[0].v_type == VAR_FUNC)
1565 func = argvars[0].vval.v_string;
1566 else if (argvars[0].v_type == VAR_PARTIAL)
1567 {
1568 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001569 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 }
1571 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001572 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001573 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001574 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575
1576 if (argvars[2].v_type != VAR_UNKNOWN)
1577 {
1578 if (argvars[2].v_type != VAR_DICT)
1579 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001580 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001581 return;
1582 }
1583 selfdict = argvars[2].vval.v_dict;
1584 }
1585
1586 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1587}
1588
1589#ifdef FEAT_FLOAT
1590/*
1591 * "ceil({float})" function
1592 */
1593 static void
1594f_ceil(typval_T *argvars, typval_T *rettv)
1595{
1596 float_T f = 0.0;
1597
1598 rettv->v_type = VAR_FLOAT;
1599 if (get_float_arg(argvars, &f) == OK)
1600 rettv->vval.v_float = ceil(f);
1601 else
1602 rettv->vval.v_float = 0.0;
1603}
1604#endif
1605
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001606/*
1607 * "changenr()" function
1608 */
1609 static void
1610f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1611{
1612 rettv->vval.v_number = curbuf->b_u_seq_cur;
1613}
1614
1615/*
1616 * "char2nr(string)" function
1617 */
1618 static void
1619f_char2nr(typval_T *argvars, typval_T *rettv)
1620{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001621 if (has_mbyte)
1622 {
1623 int utf8 = 0;
1624
1625 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001626 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627
1628 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001629 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001631 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001632 }
1633 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001634 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635}
1636
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001637 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001638get_optional_window(typval_T *argvars, int idx)
1639{
1640 win_T *win = curwin;
1641
1642 if (argvars[idx].v_type != VAR_UNKNOWN)
1643 {
1644 win = find_win_by_nr_or_id(&argvars[idx]);
1645 if (win == NULL)
1646 {
1647 emsg(_(e_invalwindow));
1648 return NULL;
1649 }
1650 }
1651 return win;
1652}
1653
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001654/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001655 * "col(string)" function
1656 */
1657 static void
1658f_col(typval_T *argvars, typval_T *rettv)
1659{
1660 colnr_T col = 0;
1661 pos_T *fp;
1662 int fnum = curbuf->b_fnum;
1663
1664 fp = var2fpos(&argvars[0], FALSE, &fnum);
1665 if (fp != NULL && fnum == curbuf->b_fnum)
1666 {
1667 if (fp->col == MAXCOL)
1668 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001669 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001670 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1671 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1672 else
1673 col = MAXCOL;
1674 }
1675 else
1676 {
1677 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001678 // col(".") when the cursor is on the NUL at the end of the line
1679 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001680 if (virtual_active() && fp == &curwin->w_cursor)
1681 {
1682 char_u *p = ml_get_cursor();
1683
1684 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1685 curwin->w_virtcol - curwin->w_cursor.coladd))
1686 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 int l;
1688
1689 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1690 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691 }
1692 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693 }
1694 }
1695 rettv->vval.v_number = col;
1696}
1697
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001698/*
1699 * "confirm(message, buttons[, default [, type]])" function
1700 */
1701 static void
1702f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1703{
1704#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1705 char_u *message;
1706 char_u *buttons = NULL;
1707 char_u buf[NUMBUFLEN];
1708 char_u buf2[NUMBUFLEN];
1709 int def = 1;
1710 int type = VIM_GENERIC;
1711 char_u *typestr;
1712 int error = FALSE;
1713
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001714 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001715 if (message == NULL)
1716 error = TRUE;
1717 if (argvars[1].v_type != VAR_UNKNOWN)
1718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001719 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720 if (buttons == NULL)
1721 error = TRUE;
1722 if (argvars[2].v_type != VAR_UNKNOWN)
1723 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001724 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 if (argvars[3].v_type != VAR_UNKNOWN)
1726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001727 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728 if (typestr == NULL)
1729 error = TRUE;
1730 else
1731 {
1732 switch (TOUPPER_ASC(*typestr))
1733 {
1734 case 'E': type = VIM_ERROR; break;
1735 case 'Q': type = VIM_QUESTION; break;
1736 case 'I': type = VIM_INFO; break;
1737 case 'W': type = VIM_WARNING; break;
1738 case 'G': type = VIM_GENERIC; break;
1739 }
1740 }
1741 }
1742 }
1743 }
1744
1745 if (buttons == NULL || *buttons == NUL)
1746 buttons = (char_u *)_("&Ok");
1747
1748 if (!error)
1749 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1750 def, NULL, FALSE);
1751#endif
1752}
1753
1754/*
1755 * "copy()" function
1756 */
1757 static void
1758f_copy(typval_T *argvars, typval_T *rettv)
1759{
1760 item_copy(&argvars[0], rettv, FALSE, 0);
1761}
1762
1763#ifdef FEAT_FLOAT
1764/*
1765 * "cos()" function
1766 */
1767 static void
1768f_cos(typval_T *argvars, typval_T *rettv)
1769{
1770 float_T f = 0.0;
1771
1772 rettv->v_type = VAR_FLOAT;
1773 if (get_float_arg(argvars, &f) == OK)
1774 rettv->vval.v_float = cos(f);
1775 else
1776 rettv->vval.v_float = 0.0;
1777}
1778
1779/*
1780 * "cosh()" function
1781 */
1782 static void
1783f_cosh(typval_T *argvars, typval_T *rettv)
1784{
1785 float_T f = 0.0;
1786
1787 rettv->v_type = VAR_FLOAT;
1788 if (get_float_arg(argvars, &f) == OK)
1789 rettv->vval.v_float = cosh(f);
1790 else
1791 rettv->vval.v_float = 0.0;
1792}
1793#endif
1794
1795/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001796 * "cursor(lnum, col)" function, or
1797 * "cursor(list)"
1798 *
1799 * Moves the cursor to the specified line and column.
1800 * Returns 0 when the position could be set, -1 otherwise.
1801 */
1802 static void
1803f_cursor(typval_T *argvars, typval_T *rettv)
1804{
1805 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001806 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001807 int set_curswant = TRUE;
1808
1809 rettv->vval.v_number = -1;
1810 if (argvars[1].v_type == VAR_UNKNOWN)
1811 {
1812 pos_T pos;
1813 colnr_T curswant = -1;
1814
1815 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1816 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001817 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001818 return;
1819 }
1820 line = pos.lnum;
1821 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001823 if (curswant >= 0)
1824 {
1825 curwin->w_curswant = curswant - 1;
1826 set_curswant = FALSE;
1827 }
1828 }
1829 else
1830 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001831 line = tv_get_lnum(argvars);
1832 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001833 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001834 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001836 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001837 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001838 if (line > 0)
1839 curwin->w_cursor.lnum = line;
1840 if (col > 0)
1841 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001842 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001843
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001844 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001845 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001846 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001847 if (has_mbyte)
1848 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001849
1850 curwin->w_set_curswant = set_curswant;
1851 rettv->vval.v_number = 0;
1852}
1853
Bram Moolenaar4f974752019-02-17 17:44:42 +01001854#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001855/*
1856 * "debugbreak()" function
1857 */
1858 static void
1859f_debugbreak(typval_T *argvars, typval_T *rettv)
1860{
1861 int pid;
1862
1863 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001864 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001865 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001866 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001867 else
1868 {
1869 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1870
1871 if (hProcess != NULL)
1872 {
1873 DebugBreakProcess(hProcess);
1874 CloseHandle(hProcess);
1875 rettv->vval.v_number = OK;
1876 }
1877 }
1878}
1879#endif
1880
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001881/*
1882 * "deepcopy()" function
1883 */
1884 static void
1885f_deepcopy(typval_T *argvars, typval_T *rettv)
1886{
1887 int noref = 0;
1888 int copyID;
1889
1890 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001891 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001892 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001893 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001894 else
1895 {
1896 copyID = get_copyID();
1897 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1898 }
1899}
1900
1901/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902 * "did_filetype()" function
1903 */
1904 static void
1905f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1906{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001907 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908}
1909
1910/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001911 * "echoraw({expr})" function
1912 */
1913 static void
1914f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1915{
1916 char_u *str = tv_get_string_chk(&argvars[0]);
1917
1918 if (str != NULL && *str != NUL)
1919 {
1920 out_str(str);
1921 out_flush();
1922 }
1923}
1924
1925/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001926 * "empty({expr})" function
1927 */
1928 static void
1929f_empty(typval_T *argvars, typval_T *rettv)
1930{
1931 int n = FALSE;
1932
1933 switch (argvars[0].v_type)
1934 {
1935 case VAR_STRING:
1936 case VAR_FUNC:
1937 n = argvars[0].vval.v_string == NULL
1938 || *argvars[0].vval.v_string == NUL;
1939 break;
1940 case VAR_PARTIAL:
1941 n = FALSE;
1942 break;
1943 case VAR_NUMBER:
1944 n = argvars[0].vval.v_number == 0;
1945 break;
1946 case VAR_FLOAT:
1947#ifdef FEAT_FLOAT
1948 n = argvars[0].vval.v_float == 0.0;
1949 break;
1950#endif
1951 case VAR_LIST:
1952 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001953 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001954 break;
1955 case VAR_DICT:
1956 n = argvars[0].vval.v_dict == NULL
1957 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1958 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001959 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001960 case VAR_SPECIAL:
1961 n = argvars[0].vval.v_number != VVAL_TRUE;
1962 break;
1963
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001964 case VAR_BLOB:
1965 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001966 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1967 break;
1968
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001969 case VAR_JOB:
1970#ifdef FEAT_JOB_CHANNEL
1971 n = argvars[0].vval.v_job == NULL
1972 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1973 break;
1974#endif
1975 case VAR_CHANNEL:
1976#ifdef FEAT_JOB_CHANNEL
1977 n = argvars[0].vval.v_channel == NULL
1978 || !channel_is_open(argvars[0].vval.v_channel);
1979 break;
1980#endif
1981 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02001982 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001983 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001984 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985 n = TRUE;
1986 break;
1987 }
1988
1989 rettv->vval.v_number = n;
1990}
1991
1992/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001993 * "environ()" function
1994 */
1995 static void
1996f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1997{
1998#if !defined(AMIGA)
1999 int i = 0;
2000 char_u *entry, *value;
2001# ifdef MSWIN
2002 extern wchar_t **_wenviron;
2003# else
2004 extern char **environ;
2005# endif
2006
2007 if (rettv_dict_alloc(rettv) != OK)
2008 return;
2009
2010# ifdef MSWIN
2011 if (*_wenviron == NULL)
2012 return;
2013# else
2014 if (*environ == NULL)
2015 return;
2016# endif
2017
2018 for (i = 0; ; ++i)
2019 {
2020# ifdef MSWIN
2021 short_u *p;
2022
2023 if ((p = (short_u *)_wenviron[i]) == NULL)
2024 return;
2025 entry = utf16_to_enc(p, NULL);
2026# else
2027 if ((entry = (char_u *)environ[i]) == NULL)
2028 return;
2029 entry = vim_strsave(entry);
2030# endif
2031 if (entry == NULL) // out of memory
2032 return;
2033 if ((value = vim_strchr(entry, '=')) == NULL)
2034 {
2035 vim_free(entry);
2036 continue;
2037 }
2038 *value++ = NUL;
2039 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2040 vim_free(entry);
2041 }
2042#endif
2043}
2044
2045/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002046 * "escape({string}, {chars})" function
2047 */
2048 static void
2049f_escape(typval_T *argvars, typval_T *rettv)
2050{
2051 char_u buf[NUMBUFLEN];
2052
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002053 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2054 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002055 rettv->v_type = VAR_STRING;
2056}
2057
2058/*
2059 * "eval()" function
2060 */
2061 static void
2062f_eval(typval_T *argvars, typval_T *rettv)
2063{
2064 char_u *s, *p;
2065
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002066 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002067 if (s != NULL)
2068 s = skipwhite(s);
2069
2070 p = s;
Bram Moolenaar32e35112020-05-14 22:41:15 +02002071 if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002072 {
2073 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002074 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002075 need_clr_eos = FALSE;
2076 rettv->v_type = VAR_NUMBER;
2077 rettv->vval.v_number = 0;
2078 }
2079 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002080 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002081}
2082
2083/*
2084 * "eventhandler()" function
2085 */
2086 static void
2087f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2088{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002089 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002090}
2091
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002092static garray_T redir_execute_ga;
2093
2094/*
2095 * Append "value[value_len]" to the execute() output.
2096 */
2097 void
2098execute_redir_str(char_u *value, int value_len)
2099{
2100 int len;
2101
2102 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002103 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002104 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002105 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002106 if (ga_grow(&redir_execute_ga, len) == OK)
2107 {
2108 mch_memmove((char *)redir_execute_ga.ga_data
2109 + redir_execute_ga.ga_len, value, len);
2110 redir_execute_ga.ga_len += len;
2111 }
2112}
2113
2114/*
2115 * Get next line from a list.
2116 * Called by do_cmdline() to get the next line.
2117 * Returns allocated string, or NULL for end of function.
2118 */
2119
2120 static char_u *
2121get_list_line(
2122 int c UNUSED,
2123 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002124 int indent UNUSED,
2125 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002126{
2127 listitem_T **p = (listitem_T **)cookie;
2128 listitem_T *item = *p;
2129 char_u buf[NUMBUFLEN];
2130 char_u *s;
2131
2132 if (item == NULL)
2133 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002134 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135 *p = item->li_next;
2136 return s == NULL ? NULL : vim_strsave(s);
2137}
2138
2139/*
2140 * "execute()" function
2141 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002142 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002143execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002144{
2145 char_u *cmd = NULL;
2146 list_T *list = NULL;
2147 int save_msg_silent = msg_silent;
2148 int save_emsg_silent = emsg_silent;
2149 int save_emsg_noredir = emsg_noredir;
2150 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002151 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002152 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002153 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002154 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002155
2156 rettv->vval.v_string = NULL;
2157 rettv->v_type = VAR_STRING;
2158
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002159 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002160 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002161 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002162 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002163 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 return;
2165 ++list->lv_refcount;
2166 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002167 else if (argvars[arg_off].v_type == VAR_JOB
2168 || argvars[arg_off].v_type == VAR_CHANNEL)
2169 {
2170 emsg(_(e_inval_string));
2171 return;
2172 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173 else
2174 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002175 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 if (cmd == NULL)
2177 return;
2178 }
2179
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002180 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002181 {
2182 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002183 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002184
2185 if (s == NULL)
2186 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002187 if (*s == NUL)
2188 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002189 if (STRNCMP(s, "silent", 6) == 0)
2190 ++msg_silent;
2191 if (STRCMP(s, "silent!") == 0)
2192 {
2193 emsg_silent = TRUE;
2194 emsg_noredir = TRUE;
2195 }
2196 }
2197 else
2198 ++msg_silent;
2199
2200 if (redir_execute)
2201 save_ga = redir_execute_ga;
2202 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2203 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002204 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002205 if (!echo_output)
2206 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207
2208 if (cmd != NULL)
2209 do_cmdline_cmd(cmd);
2210 else
2211 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002212 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002213
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002214 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002215 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216 do_cmdline(NULL, get_list_line, (void *)&item,
2217 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2218 --list->lv_refcount;
2219 }
2220
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002221 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002222 if (ga_grow(&redir_execute_ga, 1) == OK)
2223 {
2224 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2225 rettv->vval.v_string = redir_execute_ga.ga_data;
2226 }
2227 else
2228 {
2229 ga_clear(&redir_execute_ga);
2230 rettv->vval.v_string = NULL;
2231 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002232 msg_silent = save_msg_silent;
2233 emsg_silent = save_emsg_silent;
2234 emsg_noredir = save_emsg_noredir;
2235
2236 redir_execute = save_redir_execute;
2237 if (redir_execute)
2238 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002239 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002240
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002241 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002242 if (echo_output)
2243 // When not working silently: put it in column zero. A following
2244 // "echon" will overwrite the message, unavoidably.
2245 msg_col = 0;
2246 else
2247 // When working silently: Put it back where it was, since nothing
2248 // should have been written.
2249 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002250}
2251
2252/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002253 * "execute()" function
2254 */
2255 static void
2256f_execute(typval_T *argvars, typval_T *rettv)
2257{
2258 execute_common(argvars, rettv, 0);
2259}
2260
2261/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002262 * "exists()" function
2263 */
2264 static void
2265f_exists(typval_T *argvars, typval_T *rettv)
2266{
2267 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002270 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002271 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002272 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002273 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002274 if (mch_getenv(p + 1) != NULL)
2275 n = TRUE;
2276 else
2277 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002278 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002279 p = expand_env_save(p);
2280 if (p != NULL && *p != '$')
2281 n = TRUE;
2282 vim_free(p);
2283 }
2284 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002285 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002286 {
2287 n = (get_option_tv(&p, NULL, TRUE) == OK);
2288 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002289 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002291 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002293 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002294 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002295 else if (*p == '?') // internal function only
2296 {
2297 n = has_internal_func_name(p + 1);
2298 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002299 else if (*p == ':')
2300 {
2301 n = cmd_exists(p + 1);
2302 }
2303 else if (*p == '#')
2304 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002305 if (p[1] == '#')
2306 n = autocmd_supported(p + 2);
2307 else
2308 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002309 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002310 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002311 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002312 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002313 }
2314
2315 rettv->vval.v_number = n;
2316}
2317
2318#ifdef FEAT_FLOAT
2319/*
2320 * "exp()" function
2321 */
2322 static void
2323f_exp(typval_T *argvars, typval_T *rettv)
2324{
2325 float_T f = 0.0;
2326
2327 rettv->v_type = VAR_FLOAT;
2328 if (get_float_arg(argvars, &f) == OK)
2329 rettv->vval.v_float = exp(f);
2330 else
2331 rettv->vval.v_float = 0.0;
2332}
2333#endif
2334
2335/*
2336 * "expand()" function
2337 */
2338 static void
2339f_expand(typval_T *argvars, typval_T *rettv)
2340{
2341 char_u *s;
2342 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002343 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002344 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2345 expand_T xpc;
2346 int error = FALSE;
2347 char_u *result;
2348
2349 rettv->v_type = VAR_STRING;
2350 if (argvars[1].v_type != VAR_UNKNOWN
2351 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002352 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002354 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002355
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002356 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002357 if (*s == '%' || *s == '#' || *s == '<')
2358 {
2359 ++emsg_off;
2360 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2361 --emsg_off;
2362 if (rettv->v_type == VAR_LIST)
2363 {
2364 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2365 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002366 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 }
2368 else
2369 rettv->vval.v_string = result;
2370 }
2371 else
2372 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002373 // When the optional second argument is non-zero, don't remove matches
2374 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002375 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002376 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002377 options |= WILD_KEEP_ALL;
2378 if (!error)
2379 {
2380 ExpandInit(&xpc);
2381 xpc.xp_context = EXPAND_FILES;
2382 if (p_wic)
2383 options += WILD_ICASE;
2384 if (rettv->v_type == VAR_STRING)
2385 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2386 options, WILD_ALL);
2387 else if (rettv_list_alloc(rettv) != FAIL)
2388 {
2389 int i;
2390
2391 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2392 for (i = 0; i < xpc.xp_numfiles; i++)
2393 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2394 ExpandCleanup(&xpc);
2395 }
2396 }
2397 else
2398 rettv->vval.v_string = NULL;
2399 }
2400}
2401
2402/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002403 * "expandcmd()" function
2404 * Expand all the special characters in a command string.
2405 */
2406 static void
2407f_expandcmd(typval_T *argvars, typval_T *rettv)
2408{
2409 exarg_T eap;
2410 char_u *cmdstr;
2411 char *errormsg = NULL;
2412
2413 rettv->v_type = VAR_STRING;
2414 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2415
2416 memset(&eap, 0, sizeof(eap));
2417 eap.cmd = cmdstr;
2418 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002419 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002420 eap.usefilter = FALSE;
2421 eap.nextcmd = NULL;
2422 eap.cmdidx = CMD_USER;
2423
2424 expand_filename(&eap, &cmdstr, &errormsg);
2425 if (errormsg != NULL && *errormsg != NUL)
2426 emsg(errormsg);
2427
2428 rettv->vval.v_string = cmdstr;
2429}
2430
2431/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432 * "feedkeys()" function
2433 */
2434 static void
2435f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2436{
2437 int remap = TRUE;
2438 int insert = FALSE;
2439 char_u *keys, *flags;
2440 char_u nbuf[NUMBUFLEN];
2441 int typed = FALSE;
2442 int execute = FALSE;
2443 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002444 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002445 char_u *keys_esc;
2446
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002447 // This is not allowed in the sandbox. If the commands would still be
2448 // executed in the sandbox it would be OK, but it probably happens later,
2449 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 if (check_secure())
2451 return;
2452
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002453 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002454
2455 if (argvars[1].v_type != VAR_UNKNOWN)
2456 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002457 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458 for ( ; *flags != NUL; ++flags)
2459 {
2460 switch (*flags)
2461 {
2462 case 'n': remap = FALSE; break;
2463 case 'm': remap = TRUE; break;
2464 case 't': typed = TRUE; break;
2465 case 'i': insert = TRUE; break;
2466 case 'x': execute = TRUE; break;
2467 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002468 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 }
2470 }
2471 }
2472
2473 if (*keys != NUL || execute)
2474 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002475 // Need to escape K_SPECIAL and CSI before putting the string in the
2476 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002477 keys_esc = vim_strsave_escape_csi(keys);
2478 if (keys_esc != NULL)
2479 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002480 if (lowlevel)
2481 {
2482#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002483 int idx;
2484 int len = (int)STRLEN(keys);
2485
2486 for (idx = 0; idx < len; ++idx)
2487 {
2488 // if a CTRL-C was typed, set got_int, similar to what
2489 // happens in fill_input_buf()
2490 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2491 got_int = TRUE;
2492 add_to_input_buf(keys + idx, 1);
2493 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002494#else
2495 emsg(_("E980: lowlevel input not supported"));
2496#endif
2497 }
2498 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002499 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002500 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002502 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002503#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002504 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002505#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002506 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002507 typebuf_was_filled = TRUE;
2508 }
2509 vim_free(keys_esc);
2510
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511 if (execute)
2512 {
2513 int save_msg_scroll = msg_scroll;
2514
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002515 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002516 msg_scroll = FALSE;
2517
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002518 if (!dangerous)
2519 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002520 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002521 if (!dangerous)
2522 --ex_normal_busy;
2523
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002524 msg_scroll |= save_msg_scroll;
2525 }
2526 }
2527 }
2528}
2529
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002530#ifdef FEAT_FLOAT
2531/*
2532 * "float2nr({float})" function
2533 */
2534 static void
2535f_float2nr(typval_T *argvars, typval_T *rettv)
2536{
2537 float_T f = 0.0;
2538
2539 if (get_float_arg(argvars, &f) == OK)
2540 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002541 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002542 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002543 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002544 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002545 else
2546 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002547 }
2548}
2549
2550/*
2551 * "floor({float})" function
2552 */
2553 static void
2554f_floor(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 = floor(f);
2561 else
2562 rettv->vval.v_float = 0.0;
2563}
2564
2565/*
2566 * "fmod()" function
2567 */
2568 static void
2569f_fmod(typval_T *argvars, typval_T *rettv)
2570{
2571 float_T fx = 0.0, fy = 0.0;
2572
2573 rettv->v_type = VAR_FLOAT;
2574 if (get_float_arg(argvars, &fx) == OK
2575 && get_float_arg(&argvars[1], &fy) == OK)
2576 rettv->vval.v_float = fmod(fx, fy);
2577 else
2578 rettv->vval.v_float = 0.0;
2579}
2580#endif
2581
2582/*
2583 * "fnameescape({string})" function
2584 */
2585 static void
2586f_fnameescape(typval_T *argvars, typval_T *rettv)
2587{
2588 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002589 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002590 rettv->v_type = VAR_STRING;
2591}
2592
2593/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 * "foreground()" function
2595 */
2596 static void
2597f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2598{
2599#ifdef FEAT_GUI
2600 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002601 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002603 return;
2604 }
2605#endif
2606#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002607 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002608#endif
2609}
2610
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002611 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002612common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002613{
2614 char_u *s;
2615 char_u *name;
2616 int use_string = FALSE;
2617 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002618 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002619 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620
2621 if (argvars[0].v_type == VAR_FUNC)
2622 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002623 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002624 s = argvars[0].vval.v_string;
2625 }
2626 else if (argvars[0].v_type == VAR_PARTIAL
2627 && argvars[0].vval.v_partial != NULL)
2628 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002629 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002630 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002631 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632 }
2633 else
2634 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002635 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002636 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002637 use_string = TRUE;
2638 }
2639
Bram Moolenaar843b8842016-08-21 14:36:15 +02002640 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002641 {
2642 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002643 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2645 if (*name != NUL)
2646 s = NULL;
2647 }
2648
Bram Moolenaar843b8842016-08-21 14:36:15 +02002649 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2650 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002651 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002652 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002653 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002654 ? find_func(trans_name, is_global, NULL) == NULL
2655 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002656 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002657 else
2658 {
2659 int dict_idx = 0;
2660 int arg_idx = 0;
2661 list_T *list = NULL;
2662
2663 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2664 {
2665 char sid_buf[25];
2666 int off = *s == 's' ? 2 : 5;
2667
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002668 // Expand s: and <SID> into <SNR>nr_, so that the function can
2669 // also be called from another script. Using trans_function_name()
2670 // would also work, but some plugins depend on the name being
2671 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002672 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002673 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002674 if (name != NULL)
2675 {
2676 STRCPY(name, sid_buf);
2677 STRCAT(name, s + off);
2678 }
2679 }
2680 else
2681 name = vim_strsave(s);
2682
2683 if (argvars[1].v_type != VAR_UNKNOWN)
2684 {
2685 if (argvars[2].v_type != VAR_UNKNOWN)
2686 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002687 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002688 arg_idx = 1;
2689 dict_idx = 2;
2690 }
2691 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002692 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 dict_idx = 1;
2694 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002695 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002696 arg_idx = 1;
2697 if (dict_idx > 0)
2698 {
2699 if (argvars[dict_idx].v_type != VAR_DICT)
2700 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002701 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002702 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002703 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 }
2705 if (argvars[dict_idx].vval.v_dict == NULL)
2706 dict_idx = 0;
2707 }
2708 if (arg_idx > 0)
2709 {
2710 if (argvars[arg_idx].v_type != VAR_LIST)
2711 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002712 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002714 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002715 }
2716 list = argvars[arg_idx].vval.v_list;
2717 if (list == NULL || list->lv_len == 0)
2718 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002719 else if (list->lv_len > MAX_FUNC_ARGS)
2720 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002721 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002722 vim_free(name);
2723 goto theend;
2724 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002725 }
2726 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002727 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002729 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002730
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002731 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002732 if (pt == NULL)
2733 vim_free(name);
2734 else
2735 {
2736 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2737 {
2738 listitem_T *li;
2739 int i = 0;
2740 int arg_len = 0;
2741 int lv_len = 0;
2742
2743 if (arg_pt != NULL)
2744 arg_len = arg_pt->pt_argc;
2745 if (list != NULL)
2746 lv_len = list->lv_len;
2747 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002748 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002749 if (pt->pt_argv == NULL)
2750 {
2751 vim_free(pt);
2752 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002753 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002754 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002755 for (i = 0; i < arg_len; i++)
2756 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2757 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002758 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002759 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002760 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002761 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002762 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 }
2764
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002765 // For "function(dict.func, [], dict)" and "func" is a partial
2766 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002767 if (dict_idx > 0)
2768 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002769 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2771 ++pt->pt_dict->dv_refcount;
2772 }
2773 else if (arg_pt != NULL)
2774 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002775 // If the dict was bound automatically the result is also
2776 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002777 pt->pt_dict = arg_pt->pt_dict;
2778 pt->pt_auto = arg_pt->pt_auto;
2779 if (pt->pt_dict != NULL)
2780 ++pt->pt_dict->dv_refcount;
2781 }
2782
2783 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002784 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2785 {
2786 pt->pt_func = arg_pt->pt_func;
2787 func_ptr_ref(pt->pt_func);
2788 vim_free(name);
2789 }
2790 else if (is_funcref)
2791 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002792 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002793 func_ptr_ref(pt->pt_func);
2794 vim_free(name);
2795 }
2796 else
2797 {
2798 pt->pt_name = name;
2799 func_ref(name);
2800 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002801 }
2802 rettv->v_type = VAR_PARTIAL;
2803 rettv->vval.v_partial = pt;
2804 }
2805 else
2806 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002807 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002808 rettv->v_type = VAR_FUNC;
2809 rettv->vval.v_string = name;
2810 func_ref(name);
2811 }
2812 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002813theend:
2814 vim_free(trans_name);
2815}
2816
2817/*
2818 * "funcref()" function
2819 */
2820 static void
2821f_funcref(typval_T *argvars, typval_T *rettv)
2822{
2823 common_function(argvars, rettv, TRUE);
2824}
2825
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002826 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002827ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002828{
2829 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2830 return &t_func_any;
Bram Moolenaard77a8522020-04-03 21:59:57 +02002831 return &t_func_void;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002832}
2833
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002834/*
2835 * "function()" function
2836 */
2837 static void
2838f_function(typval_T *argvars, typval_T *rettv)
2839{
2840 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002841}
2842
2843/*
2844 * "garbagecollect()" function
2845 */
2846 static void
2847f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2848{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002849 // This is postponed until we are back at the toplevel, because we may be
2850 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851 want_garbage_collect = TRUE;
2852
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002853 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002854 garbage_collect_at_exit = TRUE;
2855}
2856
2857/*
2858 * "get()" function
2859 */
2860 static void
2861f_get(typval_T *argvars, typval_T *rettv)
2862{
2863 listitem_T *li;
2864 list_T *l;
2865 dictitem_T *di;
2866 dict_T *d;
2867 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002868 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002870 if (argvars[0].v_type == VAR_BLOB)
2871 {
2872 int error = FALSE;
2873 int idx = tv_get_number_chk(&argvars[1], &error);
2874
2875 if (!error)
2876 {
2877 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002878 if (idx < 0)
2879 idx = blob_len(argvars[0].vval.v_blob) + idx;
2880 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2881 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002882 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002883 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002884 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002885 tv = rettv;
2886 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002887 }
2888 }
2889 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002890 {
2891 if ((l = argvars[0].vval.v_list) != NULL)
2892 {
2893 int error = FALSE;
2894
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002895 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002896 if (!error && li != NULL)
2897 tv = &li->li_tv;
2898 }
2899 }
2900 else if (argvars[0].v_type == VAR_DICT)
2901 {
2902 if ((d = argvars[0].vval.v_dict) != NULL)
2903 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002904 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002905 if (di != NULL)
2906 tv = &di->di_tv;
2907 }
2908 }
2909 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2910 {
2911 partial_T *pt;
2912 partial_T fref_pt;
2913
2914 if (argvars[0].v_type == VAR_PARTIAL)
2915 pt = argvars[0].vval.v_partial;
2916 else
2917 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02002918 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002919 fref_pt.pt_name = argvars[0].vval.v_string;
2920 pt = &fref_pt;
2921 }
2922
2923 if (pt != NULL)
2924 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002925 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002926 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002927
2928 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2929 {
2930 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002931 n = partial_name(pt);
2932 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933 rettv->vval.v_string = NULL;
2934 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002935 {
2936 rettv->vval.v_string = vim_strsave(n);
2937 if (rettv->v_type == VAR_FUNC)
2938 func_ref(rettv->vval.v_string);
2939 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940 }
2941 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002942 {
2943 what_is_dict = TRUE;
2944 if (pt->pt_dict != NULL)
2945 rettv_dict_set(rettv, pt->pt_dict);
2946 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002947 else if (STRCMP(what, "args") == 0)
2948 {
2949 rettv->v_type = VAR_LIST;
2950 if (rettv_list_alloc(rettv) == OK)
2951 {
2952 int i;
2953
2954 for (i = 0; i < pt->pt_argc; ++i)
2955 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2956 }
2957 }
2958 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002959 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002960
2961 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2962 // third argument
2963 if (!what_is_dict)
2964 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002965 }
2966 }
2967 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002968 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002969
2970 if (tv == NULL)
2971 {
2972 if (argvars[2].v_type != VAR_UNKNOWN)
2973 copy_tv(&argvars[2], rettv);
2974 }
2975 else
2976 copy_tv(tv, rettv);
2977}
2978
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002979/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002980 * "getchangelist()" function
2981 */
2982 static void
2983f_getchangelist(typval_T *argvars, typval_T *rettv)
2984{
2985#ifdef FEAT_JUMPLIST
2986 buf_T *buf;
2987 int i;
2988 list_T *l;
2989 dict_T *d;
2990#endif
2991
2992 if (rettv_list_alloc(rettv) != OK)
2993 return;
2994
2995#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002996 if (argvars[0].v_type == VAR_UNKNOWN)
2997 buf = curbuf;
2998 else
2999 {
3000 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3001 ++emsg_off;
3002 buf = tv_get_buf(&argvars[0], FALSE);
3003 --emsg_off;
3004 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003005 if (buf == NULL)
3006 return;
3007
3008 l = list_alloc();
3009 if (l == NULL)
3010 return;
3011
3012 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3013 return;
3014 /*
3015 * The current window change list index tracks only the position in the
3016 * current buffer change list. For other buffers, use the change list
3017 * length as the current index.
3018 */
3019 list_append_number(rettv->vval.v_list,
3020 (varnumber_T)((buf == curwin->w_buffer)
3021 ? curwin->w_changelistidx : buf->b_changelistlen));
3022
3023 for (i = 0; i < buf->b_changelistlen; ++i)
3024 {
3025 if (buf->b_changelist[i].lnum == 0)
3026 continue;
3027 if ((d = dict_alloc()) == NULL)
3028 return;
3029 if (list_append_dict(l, d) == FAIL)
3030 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003031 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3032 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003033 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003034 }
3035#endif
3036}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003037
3038/*
3039 * "getcharsearch()" function
3040 */
3041 static void
3042f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3043{
3044 if (rettv_dict_alloc(rettv) != FAIL)
3045 {
3046 dict_T *dict = rettv->vval.v_dict;
3047
Bram Moolenaare0be1672018-07-08 16:50:37 +02003048 dict_add_string(dict, "char", last_csearch());
3049 dict_add_number(dict, "forward", last_csearch_forward());
3050 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003051 }
3052}
3053
3054/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003055 * "getenv()" function
3056 */
3057 static void
3058f_getenv(typval_T *argvars, typval_T *rettv)
3059{
3060 int mustfree = FALSE;
3061 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3062
3063 if (p == NULL)
3064 {
3065 rettv->v_type = VAR_SPECIAL;
3066 rettv->vval.v_number = VVAL_NULL;
3067 return;
3068 }
3069 if (!mustfree)
3070 p = vim_strsave(p);
3071 rettv->vval.v_string = p;
3072 rettv->v_type = VAR_STRING;
3073}
3074
3075/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 * "getfontname()" function
3077 */
3078 static void
3079f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3080{
3081 rettv->v_type = VAR_STRING;
3082 rettv->vval.v_string = NULL;
3083#ifdef FEAT_GUI
3084 if (gui.in_use)
3085 {
3086 GuiFont font;
3087 char_u *name = NULL;
3088
3089 if (argvars[0].v_type == VAR_UNKNOWN)
3090 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003091 // Get the "Normal" font. Either the name saved by
3092 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003093 font = gui.norm_font;
3094 name = hl_get_font_name();
3095 }
3096 else
3097 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003098 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003099 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100 return;
3101 font = gui_mch_get_font(name, FALSE);
3102 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003103 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003104 }
3105 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3106 if (argvars[0].v_type != VAR_UNKNOWN)
3107 gui_mch_free_font(font);
3108 }
3109#endif
3110}
3111
3112/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003113 * "getjumplist()" function
3114 */
3115 static void
3116f_getjumplist(typval_T *argvars, typval_T *rettv)
3117{
3118#ifdef FEAT_JUMPLIST
3119 win_T *wp;
3120 int i;
3121 list_T *l;
3122 dict_T *d;
3123#endif
3124
3125 if (rettv_list_alloc(rettv) != OK)
3126 return;
3127
3128#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003129 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003130 if (wp == NULL)
3131 return;
3132
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003133 cleanup_jumplist(wp, TRUE);
3134
Bram Moolenaar4f505882018-02-10 21:06:32 +01003135 l = list_alloc();
3136 if (l == NULL)
3137 return;
3138
3139 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3140 return;
3141 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3142
3143 for (i = 0; i < wp->w_jumplistlen; ++i)
3144 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003145 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3146 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003147 if ((d = dict_alloc()) == NULL)
3148 return;
3149 if (list_append_dict(l, d) == FAIL)
3150 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003151 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3152 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003153 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003154 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003155 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003156 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003157 }
3158#endif
3159}
3160
3161/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003162 * "getpid()" function
3163 */
3164 static void
3165f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3166{
3167 rettv->vval.v_number = mch_get_pid();
3168}
3169
3170 static void
3171getpos_both(
3172 typval_T *argvars,
3173 typval_T *rettv,
3174 int getcurpos)
3175{
3176 pos_T *fp;
3177 list_T *l;
3178 int fnum = -1;
3179
3180 if (rettv_list_alloc(rettv) == OK)
3181 {
3182 l = rettv->vval.v_list;
3183 if (getcurpos)
3184 fp = &curwin->w_cursor;
3185 else
3186 fp = var2fpos(&argvars[0], TRUE, &fnum);
3187 if (fnum != -1)
3188 list_append_number(l, (varnumber_T)fnum);
3189 else
3190 list_append_number(l, (varnumber_T)0);
3191 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3192 : (varnumber_T)0);
3193 list_append_number(l, (fp != NULL)
3194 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3195 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003196 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003197 (varnumber_T)0);
3198 if (getcurpos)
3199 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003200 int save_set_curswant = curwin->w_set_curswant;
3201 colnr_T save_curswant = curwin->w_curswant;
3202 colnr_T save_virtcol = curwin->w_virtcol;
3203
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003204 update_curswant();
3205 list_append_number(l, curwin->w_curswant == MAXCOL ?
3206 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003207
3208 // Do not change "curswant", as it is unexpected that a get
3209 // function has a side effect.
3210 if (save_set_curswant)
3211 {
3212 curwin->w_set_curswant = save_set_curswant;
3213 curwin->w_curswant = save_curswant;
3214 curwin->w_virtcol = save_virtcol;
3215 curwin->w_valid &= ~VALID_VIRTCOL;
3216 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003217 }
3218 }
3219 else
3220 rettv->vval.v_number = FALSE;
3221}
3222
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003223/*
3224 * "getcurpos()" function
3225 */
3226 static void
3227f_getcurpos(typval_T *argvars, typval_T *rettv)
3228{
3229 getpos_both(argvars, rettv, TRUE);
3230}
3231
3232/*
3233 * "getpos(string)" function
3234 */
3235 static void
3236f_getpos(typval_T *argvars, typval_T *rettv)
3237{
3238 getpos_both(argvars, rettv, FALSE);
3239}
3240
3241/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003242 * "getreg()" function
3243 */
3244 static void
3245f_getreg(typval_T *argvars, typval_T *rettv)
3246{
3247 char_u *strregname;
3248 int regname;
3249 int arg2 = FALSE;
3250 int return_list = FALSE;
3251 int error = FALSE;
3252
3253 if (argvars[0].v_type != VAR_UNKNOWN)
3254 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003255 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003256 error = strregname == NULL;
3257 if (argvars[1].v_type != VAR_UNKNOWN)
3258 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003259 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003260 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003261 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003262 }
3263 }
3264 else
3265 strregname = get_vim_var_str(VV_REG);
3266
3267 if (error)
3268 return;
3269
3270 regname = (strregname == NULL ? '"' : *strregname);
3271 if (regname == 0)
3272 regname = '"';
3273
3274 if (return_list)
3275 {
3276 rettv->v_type = VAR_LIST;
3277 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3278 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3279 if (rettv->vval.v_list == NULL)
3280 (void)rettv_list_alloc(rettv);
3281 else
3282 ++rettv->vval.v_list->lv_refcount;
3283 }
3284 else
3285 {
3286 rettv->v_type = VAR_STRING;
3287 rettv->vval.v_string = get_reg_contents(regname,
3288 arg2 ? GREG_EXPR_SRC : 0);
3289 }
3290}
3291
3292/*
3293 * "getregtype()" function
3294 */
3295 static void
3296f_getregtype(typval_T *argvars, typval_T *rettv)
3297{
3298 char_u *strregname;
3299 int regname;
3300 char_u buf[NUMBUFLEN + 2];
3301 long reglen = 0;
3302
3303 if (argvars[0].v_type != VAR_UNKNOWN)
3304 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003305 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003306 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003307 {
3308 rettv->v_type = VAR_STRING;
3309 rettv->vval.v_string = NULL;
3310 return;
3311 }
3312 }
3313 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003314 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003315 strregname = get_vim_var_str(VV_REG);
3316
3317 regname = (strregname == NULL ? '"' : *strregname);
3318 if (regname == 0)
3319 regname = '"';
3320
3321 buf[0] = NUL;
3322 buf[1] = NUL;
3323 switch (get_reg_type(regname, &reglen))
3324 {
3325 case MLINE: buf[0] = 'V'; break;
3326 case MCHAR: buf[0] = 'v'; break;
3327 case MBLOCK:
3328 buf[0] = Ctrl_V;
3329 sprintf((char *)buf + 1, "%ld", reglen + 1);
3330 break;
3331 }
3332 rettv->v_type = VAR_STRING;
3333 rettv->vval.v_string = vim_strsave(buf);
3334}
3335
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003336/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003337 * "gettagstack()" function
3338 */
3339 static void
3340f_gettagstack(typval_T *argvars, typval_T *rettv)
3341{
3342 win_T *wp = curwin; // default is current window
3343
3344 if (rettv_dict_alloc(rettv) != OK)
3345 return;
3346
3347 if (argvars[0].v_type != VAR_UNKNOWN)
3348 {
3349 wp = find_win_by_nr_or_id(&argvars[0]);
3350 if (wp == NULL)
3351 return;
3352 }
3353
3354 get_tagstack(wp, rettv->vval.v_dict);
3355}
3356
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003357// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003358#include "version.h"
3359
3360/*
3361 * "has()" function
3362 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003363 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003364f_has(typval_T *argvars, typval_T *rettv)
3365{
3366 int i;
3367 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003368 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003369 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003370 typedef struct {
3371 char *name;
3372 short present;
3373 } has_item_T;
3374 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003375 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003376 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003378 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003379#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003380 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003381#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003382 },
3383 {"arp",
3384#if defined(AMIGA) && defined(FEAT_ARP)
3385 1
3386#else
3387 0
3388#endif
3389 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003390 {"haiku",
3391#ifdef __HAIKU__
3392 1
3393#else
3394 0
3395#endif
3396 },
3397 {"bsd",
3398#if defined(BSD) && !defined(MACOS_X)
3399 1
3400#else
3401 0
3402#endif
3403 },
3404 {"hpux",
3405#ifdef hpux
3406 1
3407#else
3408 0
3409#endif
3410 },
3411 {"linux",
3412#ifdef __linux__
3413 1
3414#else
3415 0
3416#endif
3417 },
3418 {"mac", // Mac OS X (and, once, Mac OS Classic)
3419#ifdef MACOS_X
3420 1
3421#else
3422 0
3423#endif
3424 },
3425 {"osx", // Mac OS X
3426#ifdef MACOS_X
3427 1
3428#else
3429 0
3430#endif
3431 },
3432 {"macunix", // Mac OS X, with the darwin feature
3433#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3434 1
3435#else
3436 0
3437#endif
3438 },
3439 {"osxdarwin", // synonym for macunix
3440#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3441 1
3442#else
3443 0
3444#endif
3445 },
3446 {"qnx",
3447#ifdef __QNX__
3448 1
3449#else
3450 0
3451#endif
3452 },
3453 {"sun",
3454#ifdef SUN_SYSTEM
3455 1
3456#else
3457 0
3458#endif
3459 },
3460 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003461#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003462 1
3463#else
3464 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003465#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003466 },
3467 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003469 1
3470#else
3471 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003473 },
3474 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003475#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003476 1
3477#else
3478 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003479#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003480 },
3481 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003482#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003483 1
3484#else
3485 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003486#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003487 },
3488 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003489#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003490 1
3491#else
3492 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003493#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003494 },
3495 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003496#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003497 1
3498#else
3499 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003501 },
3502 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003504 1
3505#else
3506 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003507#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003508 },
3509 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003510#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003511 1
3512#else
3513 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003515 },
3516 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003518 1
3519#else
3520 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003521#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003522 },
3523 {"autocmd", 1},
3524 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003525#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003526 1
3527#else
3528 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003529#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003530 },
3531 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003532#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003533 1
3534#else
3535 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003536#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003537 },
3538 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003539#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003540 1
3541#else
3542 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003543#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003544 },
3545 {"balloon_multiline",
3546#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3547 // MS-Windows requires runtime check, see below
3548 1
3549#else
3550 0
3551#endif
3552 },
3553 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003554#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003555 1
3556#else
3557 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003558#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003559 },
3560 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003562 1
3563#else
3564 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003566 },
3567 {"all_builtin_terms",
3568#if defined(ALL_BUILTIN_TCAPS)
3569 1
3570#else
3571 0
3572#endif
3573 },
3574 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003575#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003576 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003577 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003578 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003579#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003580 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003581#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003582 },
3583 {"byte_offset",
3584#ifdef FEAT_BYTEOFF
3585 1
3586#else
3587 0
3588#endif
3589 },
3590 {"channel",
3591#ifdef FEAT_JOB_CHANNEL
3592 1
3593#else
3594 0
3595#endif
3596 },
3597 {"cindent",
3598#ifdef FEAT_CINDENT
3599 1
3600#else
3601 0
3602#endif
3603 },
3604 {"clientserver",
3605#ifdef FEAT_CLIENTSERVER
3606 1
3607#else
3608 0
3609#endif
3610 },
3611 {"clipboard",
3612#ifdef FEAT_CLIPBOARD
3613 1
3614#else
3615 0
3616#endif
3617 },
3618 {"cmdline_compl", 1},
3619 {"cmdline_hist", 1},
3620 {"comments", 1},
3621 {"conceal",
3622#ifdef FEAT_CONCEAL
3623 1
3624#else
3625 0
3626#endif
3627 },
3628 {"cryptv",
3629#ifdef FEAT_CRYPT
3630 1
3631#else
3632 0
3633#endif
3634 },
3635 {"crypt-blowfish",
3636#ifdef FEAT_CRYPT
3637 1
3638#else
3639 0
3640#endif
3641 },
3642 {"crypt-blowfish2",
3643#ifdef FEAT_CRYPT
3644 1
3645#else
3646 0
3647#endif
3648 },
3649 {"cscope",
3650#ifdef FEAT_CSCOPE
3651 1
3652#else
3653 0
3654#endif
3655 },
3656 {"cursorbind", 1},
3657 {"cursorshape",
3658#ifdef CURSOR_SHAPE
3659 1
3660#else
3661 0
3662#endif
3663 },
3664 {"debug",
3665#ifdef DEBUG
3666 1
3667#else
3668 0
3669#endif
3670 },
3671 {"dialog_con",
3672#ifdef FEAT_CON_DIALOG
3673 1
3674#else
3675 0
3676#endif
3677 },
3678 {"dialog_gui",
3679#ifdef FEAT_GUI_DIALOG
3680 1
3681#else
3682 0
3683#endif
3684 },
3685 {"diff",
3686#ifdef FEAT_DIFF
3687 1
3688#else
3689 0
3690#endif
3691 },
3692 {"digraphs",
3693#ifdef FEAT_DIGRAPHS
3694 1
3695#else
3696 0
3697#endif
3698 },
3699 {"directx",
3700#ifdef FEAT_DIRECTX
3701 1
3702#else
3703 0
3704#endif
3705 },
3706 {"dnd",
3707#ifdef FEAT_DND
3708 1
3709#else
3710 0
3711#endif
3712 },
3713 {"emacs_tags",
3714#ifdef FEAT_EMACS_TAGS
3715 1
3716#else
3717 0
3718#endif
3719 },
3720 {"eval", 1}, // always present, of course!
3721 {"ex_extra", 1}, // graduated feature
3722 {"extra_search",
3723#ifdef FEAT_SEARCH_EXTRA
3724 1
3725#else
3726 0
3727#endif
3728 },
3729 {"file_in_path",
3730#ifdef FEAT_SEARCHPATH
3731 1
3732#else
3733 0
3734#endif
3735 },
3736 {"filterpipe",
3737#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3738 1
3739#else
3740 0
3741#endif
3742 },
3743 {"find_in_path",
3744#ifdef FEAT_FIND_ID
3745 1
3746#else
3747 0
3748#endif
3749 },
3750 {"float",
3751#ifdef FEAT_FLOAT
3752 1
3753#else
3754 0
3755#endif
3756 },
3757 {"folding",
3758#ifdef FEAT_FOLDING
3759 1
3760#else
3761 0
3762#endif
3763 },
3764 {"footer",
3765#ifdef FEAT_FOOTER
3766 1
3767#else
3768 0
3769#endif
3770 },
3771 {"fork",
3772#if !defined(USE_SYSTEM) && defined(UNIX)
3773 1
3774#else
3775 0
3776#endif
3777 },
3778 {"gettext",
3779#ifdef FEAT_GETTEXT
3780 1
3781#else
3782 0
3783#endif
3784 },
3785 {"gui",
3786#ifdef FEAT_GUI
3787 1
3788#else
3789 0
3790#endif
3791 },
3792 {"gui_neXtaw",
3793#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3794 1
3795#else
3796 0
3797#endif
3798 },
3799 {"gui_athena",
3800#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3801 1
3802#else
3803 0
3804#endif
3805 },
3806 {"gui_gtk",
3807#ifdef FEAT_GUI_GTK
3808 1
3809#else
3810 0
3811#endif
3812 },
3813 {"gui_gtk2",
3814#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3815 1
3816#else
3817 0
3818#endif
3819 },
3820 {"gui_gtk3",
3821#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3822 1
3823#else
3824 0
3825#endif
3826 },
3827 {"gui_gnome",
3828#ifdef FEAT_GUI_GNOME
3829 1
3830#else
3831 0
3832#endif
3833 },
3834 {"gui_haiku",
3835#ifdef FEAT_GUI_HAIKU
3836 1
3837#else
3838 0
3839#endif
3840 },
3841 {"gui_mac",
3842#ifdef FEAT_GUI_MAC
3843 1
3844#else
3845 0
3846#endif
3847 },
3848 {"gui_motif",
3849#ifdef FEAT_GUI_MOTIF
3850 1
3851#else
3852 0
3853#endif
3854 },
3855 {"gui_photon",
3856#ifdef FEAT_GUI_PHOTON
3857 1
3858#else
3859 0
3860#endif
3861 },
3862 {"gui_win32",
3863#ifdef FEAT_GUI_MSWIN
3864 1
3865#else
3866 0
3867#endif
3868 },
3869 {"iconv",
3870#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3871 1
3872#else
3873 0
3874#endif
3875 },
3876 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003877 {"ipv6",
3878#ifdef FEAT_IPV6
3879 1
3880#else
3881 0
3882#endif
3883 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003884 {"job",
3885#ifdef FEAT_JOB_CHANNEL
3886 1
3887#else
3888 0
3889#endif
3890 },
3891 {"jumplist",
3892#ifdef FEAT_JUMPLIST
3893 1
3894#else
3895 0
3896#endif
3897 },
3898 {"keymap",
3899#ifdef FEAT_KEYMAP
3900 1
3901#else
3902 0
3903#endif
3904 },
3905 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
3906 {"langmap",
3907#ifdef FEAT_LANGMAP
3908 1
3909#else
3910 0
3911#endif
3912 },
3913 {"libcall",
3914#ifdef FEAT_LIBCALL
3915 1
3916#else
3917 0
3918#endif
3919 },
3920 {"linebreak",
3921#ifdef FEAT_LINEBREAK
3922 1
3923#else
3924 0
3925#endif
3926 },
3927 {"lispindent",
3928#ifdef FEAT_LISP
3929 1
3930#else
3931 0
3932#endif
3933 },
3934 {"listcmds", 1},
3935 {"localmap", 1},
3936 {"lua",
3937#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
3938 1
3939#else
3940 0
3941#endif
3942 },
3943 {"menu",
3944#ifdef FEAT_MENU
3945 1
3946#else
3947 0
3948#endif
3949 },
3950 {"mksession",
3951#ifdef FEAT_SESSION
3952 1
3953#else
3954 0
3955#endif
3956 },
3957 {"modify_fname", 1},
3958 {"mouse", 1},
3959 {"mouseshape",
3960#ifdef FEAT_MOUSESHAPE
3961 1
3962#else
3963 0
3964#endif
3965 },
3966 {"mouse_dec",
3967#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
3968 1
3969#else
3970 0
3971#endif
3972 },
3973 {"mouse_gpm",
3974#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
3975 1
3976#else
3977 0
3978#endif
3979 },
3980 {"mouse_jsbterm",
3981#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
3982 1
3983#else
3984 0
3985#endif
3986 },
3987 {"mouse_netterm",
3988#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
3989 1
3990#else
3991 0
3992#endif
3993 },
3994 {"mouse_pterm",
3995#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
3996 1
3997#else
3998 0
3999#endif
4000 },
4001 {"mouse_sgr",
4002#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4003 1
4004#else
4005 0
4006#endif
4007 },
4008 {"mouse_sysmouse",
4009#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4010 1
4011#else
4012 0
4013#endif
4014 },
4015 {"mouse_urxvt",
4016#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4017 1
4018#else
4019 0
4020#endif
4021 },
4022 {"mouse_xterm",
4023#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4024 1
4025#else
4026 0
4027#endif
4028 },
4029 {"multi_byte", 1},
4030 {"multi_byte_ime",
4031#ifdef FEAT_MBYTE_IME
4032 1
4033#else
4034 0
4035#endif
4036 },
4037 {"multi_lang",
4038#ifdef FEAT_MULTI_LANG
4039 1
4040#else
4041 0
4042#endif
4043 },
4044 {"mzscheme",
4045#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4046 1
4047#else
4048 0
4049#endif
4050 },
4051 {"num64", 1},
4052 {"ole",
4053#ifdef FEAT_OLE
4054 1
4055#else
4056 0
4057#endif
4058 },
4059 {"packages",
4060#ifdef FEAT_EVAL
4061 1
4062#else
4063 0
4064#endif
4065 },
4066 {"path_extra",
4067#ifdef FEAT_PATH_EXTRA
4068 1
4069#else
4070 0
4071#endif
4072 },
4073 {"perl",
4074#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4075 1
4076#else
4077 0
4078#endif
4079 },
4080 {"persistent_undo",
4081#ifdef FEAT_PERSISTENT_UNDO
4082 1
4083#else
4084 0
4085#endif
4086 },
4087 {"python_compiled",
4088#if defined(FEAT_PYTHON)
4089 1
4090#else
4091 0
4092#endif
4093 },
4094 {"python_dynamic",
4095#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4096 1
4097#else
4098 0
4099#endif
4100 },
4101 {"python",
4102#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4103 1
4104#else
4105 0
4106#endif
4107 },
4108 {"pythonx",
4109#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4110 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4111 1
4112#else
4113 0
4114#endif
4115 },
4116 {"python3_compiled",
4117#if defined(FEAT_PYTHON3)
4118 1
4119#else
4120 0
4121#endif
4122 },
4123 {"python3_dynamic",
4124#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4125 1
4126#else
4127 0
4128#endif
4129 },
4130 {"python3",
4131#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4132 1
4133#else
4134 0
4135#endif
4136 },
4137 {"popupwin",
4138#ifdef FEAT_PROP_POPUP
4139 1
4140#else
4141 0
4142#endif
4143 },
4144 {"postscript",
4145#ifdef FEAT_POSTSCRIPT
4146 1
4147#else
4148 0
4149#endif
4150 },
4151 {"printer",
4152#ifdef FEAT_PRINTER
4153 1
4154#else
4155 0
4156#endif
4157 },
4158 {"profile",
4159#ifdef FEAT_PROFILE
4160 1
4161#else
4162 0
4163#endif
4164 },
4165 {"reltime",
4166#ifdef FEAT_RELTIME
4167 1
4168#else
4169 0
4170#endif
4171 },
4172 {"quickfix",
4173#ifdef FEAT_QUICKFIX
4174 1
4175#else
4176 0
4177#endif
4178 },
4179 {"rightleft",
4180#ifdef FEAT_RIGHTLEFT
4181 1
4182#else
4183 0
4184#endif
4185 },
4186 {"ruby",
4187#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4188 1
4189#else
4190 0
4191#endif
4192 },
4193 {"scrollbind", 1},
4194 {"showcmd",
4195#ifdef FEAT_CMDL_INFO
4196 1
4197#else
4198 0
4199#endif
4200 },
4201 {"cmdline_info",
4202#ifdef FEAT_CMDL_INFO
4203 1
4204#else
4205 0
4206#endif
4207 },
4208 {"signs",
4209#ifdef FEAT_SIGNS
4210 1
4211#else
4212 0
4213#endif
4214 },
4215 {"smartindent",
4216#ifdef FEAT_SMARTINDENT
4217 1
4218#else
4219 0
4220#endif
4221 },
4222 {"startuptime",
4223#ifdef STARTUPTIME
4224 1
4225#else
4226 0
4227#endif
4228 },
4229 {"statusline",
4230#ifdef FEAT_STL_OPT
4231 1
4232#else
4233 0
4234#endif
4235 },
4236 {"netbeans_intg",
4237#ifdef FEAT_NETBEANS_INTG
4238 1
4239#else
4240 0
4241#endif
4242 },
4243 {"sound",
4244#ifdef FEAT_SOUND
4245 1
4246#else
4247 0
4248#endif
4249 },
4250 {"spell",
4251#ifdef FEAT_SPELL
4252 1
4253#else
4254 0
4255#endif
4256 },
4257 {"syntax",
4258#ifdef FEAT_SYN_HL
4259 1
4260#else
4261 0
4262#endif
4263 },
4264 {"system",
4265#if defined(USE_SYSTEM) || !defined(UNIX)
4266 1
4267#else
4268 0
4269#endif
4270 },
4271 {"tag_binary",
4272#ifdef FEAT_TAG_BINS
4273 1
4274#else
4275 0
4276#endif
4277 },
4278 {"tcl",
4279#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4280 1
4281#else
4282 0
4283#endif
4284 },
4285 {"termguicolors",
4286#ifdef FEAT_TERMGUICOLORS
4287 1
4288#else
4289 0
4290#endif
4291 },
4292 {"terminal",
4293#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4294 1
4295#else
4296 0
4297#endif
4298 },
4299 {"terminfo",
4300#ifdef TERMINFO
4301 1
4302#else
4303 0
4304#endif
4305 },
4306 {"termresponse",
4307#ifdef FEAT_TERMRESPONSE
4308 1
4309#else
4310 0
4311#endif
4312 },
4313 {"textobjects",
4314#ifdef FEAT_TEXTOBJ
4315 1
4316#else
4317 0
4318#endif
4319 },
4320 {"textprop",
4321#ifdef FEAT_PROP_POPUP
4322 1
4323#else
4324 0
4325#endif
4326 },
4327 {"tgetent",
4328#ifdef HAVE_TGETENT
4329 1
4330#else
4331 0
4332#endif
4333 },
4334 {"timers",
4335#ifdef FEAT_TIMERS
4336 1
4337#else
4338 0
4339#endif
4340 },
4341 {"title",
4342#ifdef FEAT_TITLE
4343 1
4344#else
4345 0
4346#endif
4347 },
4348 {"toolbar",
4349#ifdef FEAT_TOOLBAR
4350 1
4351#else
4352 0
4353#endif
4354 },
4355 {"unnamedplus",
4356#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4357 1
4358#else
4359 0
4360#endif
4361 },
4362 {"user-commands", 1}, // was accidentally included in 5.4
4363 {"user_commands", 1},
4364 {"vartabs",
4365#ifdef FEAT_VARTABS
4366 1
4367#else
4368 0
4369#endif
4370 },
4371 {"vertsplit", 1},
4372 {"viminfo",
4373#ifdef FEAT_VIMINFO
4374 1
4375#else
4376 0
4377#endif
4378 },
4379 {"vimscript-1", 1},
4380 {"vimscript-2", 1},
4381 {"vimscript-3", 1},
4382 {"vimscript-4", 1},
4383 {"virtualedit", 1},
4384 {"visual", 1},
4385 {"visualextra", 1},
4386 {"vreplace", 1},
4387 {"vtp",
4388#ifdef FEAT_VTP
4389 1
4390#else
4391 0
4392#endif
4393 },
4394 {"wildignore",
4395#ifdef FEAT_WILDIGN
4396 1
4397#else
4398 0
4399#endif
4400 },
4401 {"wildmenu",
4402#ifdef FEAT_WILDMENU
4403 1
4404#else
4405 0
4406#endif
4407 },
4408 {"windows", 1},
4409 {"winaltkeys",
4410#ifdef FEAT_WAK
4411 1
4412#else
4413 0
4414#endif
4415 },
4416 {"writebackup",
4417#ifdef FEAT_WRITEBACKUP
4418 1
4419#else
4420 0
4421#endif
4422 },
4423 {"xim",
4424#ifdef FEAT_XIM
4425 1
4426#else
4427 0
4428#endif
4429 },
4430 {"xfontset",
4431#ifdef FEAT_XFONTSET
4432 1
4433#else
4434 0
4435#endif
4436 },
4437 {"xpm",
4438#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4439 1
4440#else
4441 0
4442#endif
4443 },
4444 {"xpm_w32", // for backward compatibility
4445#ifdef FEAT_XPM_W32
4446 1
4447#else
4448 0
4449#endif
4450 },
4451 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004452#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004453 1
4454#else
4455 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004456#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004457 },
4458 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004460 1
4461#else
4462 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004463#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004464 },
4465 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004467 1
4468#else
4469 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004470#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004471 },
4472 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004473#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004474 1
4475#else
4476 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004477#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004478 },
4479 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004480#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004481 1
4482#else
4483 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004484#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004485 },
4486 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487 };
4488
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004489 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004490 for (i = 0; has_list[i].name != NULL; ++i)
4491 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004492 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004493 x = TRUE;
4494 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004495 break;
4496 }
4497
Bram Moolenaar79296512020-03-22 16:17:14 +01004498 // features also in has_list[] but sometimes enabled at runtime
4499 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004500 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004501 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004502 {
4503 // intentionally empty
4504 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004505#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004506 else if (STRICMP(name, "balloon_multiline") == 0)
4507 n = multiline_balloon_available();
4508#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004509#ifdef VIMDLL
4510 else if (STRICMP(name, "filterpipe") == 0)
4511 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004512#endif
4513#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4514 else if (STRICMP(name, "iconv") == 0)
4515 n = iconv_enabled(FALSE);
4516#endif
4517#ifdef DYNAMIC_LUA
4518 else if (STRICMP(name, "lua") == 0)
4519 n = lua_enabled(FALSE);
4520#endif
4521#ifdef DYNAMIC_MZSCHEME
4522 else if (STRICMP(name, "mzscheme") == 0)
4523 n = mzscheme_enabled(FALSE);
4524#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004525#ifdef DYNAMIC_PERL
4526 else if (STRICMP(name, "perl") == 0)
4527 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004528#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004529#ifdef DYNAMIC_PYTHON
4530 else if (STRICMP(name, "python") == 0)
4531 n = python_enabled(FALSE);
4532#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004533#ifdef DYNAMIC_PYTHON3
4534 else if (STRICMP(name, "python3") == 0)
4535 n = python3_enabled(FALSE);
4536#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004537#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4538 else if (STRICMP(name, "pythonx") == 0)
4539 {
4540# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4541 if (p_pyx == 0)
4542 n = python3_enabled(FALSE) || python_enabled(FALSE);
4543 else if (p_pyx == 3)
4544 n = python3_enabled(FALSE);
4545 else if (p_pyx == 2)
4546 n = python_enabled(FALSE);
4547# elif defined(DYNAMIC_PYTHON)
4548 n = python_enabled(FALSE);
4549# elif defined(DYNAMIC_PYTHON3)
4550 n = python3_enabled(FALSE);
4551# endif
4552 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004553#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004554#ifdef DYNAMIC_RUBY
4555 else if (STRICMP(name, "ruby") == 0)
4556 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004557#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004558#ifdef DYNAMIC_TCL
4559 else if (STRICMP(name, "tcl") == 0)
4560 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004561#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004562#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004563 else if (STRICMP(name, "terminal") == 0)
4564 n = terminal_enabled();
4565#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004566 }
4567
Bram Moolenaar79296512020-03-22 16:17:14 +01004568 // features not in has_list[]
4569 if (x == FALSE)
4570 {
4571 if (STRNICMP(name, "patch", 5) == 0)
4572 {
4573 x = TRUE;
4574 if (name[5] == '-'
4575 && STRLEN(name) >= 11
4576 && vim_isdigit(name[6])
4577 && vim_isdigit(name[8])
4578 && vim_isdigit(name[10]))
4579 {
4580 int major = atoi((char *)name + 6);
4581 int minor = atoi((char *)name + 8);
4582
4583 // Expect "patch-9.9.01234".
4584 n = (major < VIM_VERSION_MAJOR
4585 || (major == VIM_VERSION_MAJOR
4586 && (minor < VIM_VERSION_MINOR
4587 || (minor == VIM_VERSION_MINOR
4588 && has_patch(atoi((char *)name + 10))))));
4589 }
4590 else
4591 n = has_patch(atoi((char *)name + 5));
4592 }
4593 else if (STRICMP(name, "vim_starting") == 0)
4594 {
4595 x = TRUE;
4596 n = (starting != 0);
4597 }
4598 else if (STRICMP(name, "ttyin") == 0)
4599 {
4600 x = TRUE;
4601 n = mch_input_isatty();
4602 }
4603 else if (STRICMP(name, "ttyout") == 0)
4604 {
4605 x = TRUE;
4606 n = stdout_isatty;
4607 }
4608 else if (STRICMP(name, "multi_byte_encoding") == 0)
4609 {
4610 x = TRUE;
4611 n = has_mbyte;
4612 }
4613 else if (STRICMP(name, "gui_running") == 0)
4614 {
4615 x = TRUE;
4616#ifdef FEAT_GUI
4617 n = (gui.in_use || gui.starting);
4618#endif
4619 }
4620 else if (STRICMP(name, "browse") == 0)
4621 {
4622 x = TRUE;
4623#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4624 n = gui.in_use; // gui_mch_browse() works when GUI is running
4625#endif
4626 }
4627 else if (STRICMP(name, "syntax_items") == 0)
4628 {
4629 x = TRUE;
4630#ifdef FEAT_SYN_HL
4631 n = syntax_present(curwin);
4632#endif
4633 }
4634 else if (STRICMP(name, "vcon") == 0)
4635 {
4636 x = TRUE;
4637#ifdef FEAT_VTP
4638 n = is_term_win32() && has_vtp_working();
4639#endif
4640 }
4641 else if (STRICMP(name, "netbeans_enabled") == 0)
4642 {
4643 x = TRUE;
4644#ifdef FEAT_NETBEANS_INTG
4645 n = netbeans_active();
4646#endif
4647 }
4648 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4649 {
4650 x = TRUE;
4651#ifdef FEAT_MOUSE_GPM
4652 n = gpm_enabled();
4653#endif
4654 }
4655 else if (STRICMP(name, "conpty") == 0)
4656 {
4657 x = TRUE;
4658#if defined(FEAT_TERMINAL) && defined(MSWIN)
4659 n = use_conpty();
4660#endif
4661 }
4662 else if (STRICMP(name, "clipboard_working") == 0)
4663 {
4664 x = TRUE;
4665#ifdef FEAT_CLIPBOARD
4666 n = clip_star.available;
4667#endif
4668 }
4669 }
4670
4671 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4672 // return whether feature could ever be enabled
4673 rettv->vval.v_number = x;
4674 else
4675 // return whether feature is enabled
4676 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004677}
4678
4679/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680 * "haslocaldir()" function
4681 */
4682 static void
4683f_haslocaldir(typval_T *argvars, typval_T *rettv)
4684{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004685 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686 win_T *wp = NULL;
4687
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004688 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4689
4690 // Check for window-local and tab-local directories
4691 if (wp != NULL && wp->w_localdir != NULL)
4692 rettv->vval.v_number = 1;
4693 else if (tp != NULL && tp->tp_localdir != NULL)
4694 rettv->vval.v_number = 2;
4695 else
4696 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004697}
4698
4699/*
4700 * "hasmapto()" function
4701 */
4702 static void
4703f_hasmapto(typval_T *argvars, typval_T *rettv)
4704{
4705 char_u *name;
4706 char_u *mode;
4707 char_u buf[NUMBUFLEN];
4708 int abbr = FALSE;
4709
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004710 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004711 if (argvars[1].v_type == VAR_UNKNOWN)
4712 mode = (char_u *)"nvo";
4713 else
4714 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004715 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004716 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004717 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718 }
4719
4720 if (map_to_exists(name, mode, abbr))
4721 rettv->vval.v_number = TRUE;
4722 else
4723 rettv->vval.v_number = FALSE;
4724}
4725
4726/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004727 * "highlightID(name)" function
4728 */
4729 static void
4730f_hlID(typval_T *argvars, typval_T *rettv)
4731{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004732 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733}
4734
4735/*
4736 * "highlight_exists()" function
4737 */
4738 static void
4739f_hlexists(typval_T *argvars, typval_T *rettv)
4740{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004741 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004742}
4743
4744/*
4745 * "hostname()" function
4746 */
4747 static void
4748f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4749{
4750 char_u hostname[256];
4751
4752 mch_get_host_name(hostname, 256);
4753 rettv->v_type = VAR_STRING;
4754 rettv->vval.v_string = vim_strsave(hostname);
4755}
4756
4757/*
4758 * iconv() function
4759 */
4760 static void
4761f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4762{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004763 char_u buf1[NUMBUFLEN];
4764 char_u buf2[NUMBUFLEN];
4765 char_u *from, *to, *str;
4766 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004767
4768 rettv->v_type = VAR_STRING;
4769 rettv->vval.v_string = NULL;
4770
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004771 str = tv_get_string(&argvars[0]);
4772 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4773 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004774 vimconv.vc_type = CONV_NONE;
4775 convert_setup(&vimconv, from, to);
4776
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004777 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004778 if (vimconv.vc_type == CONV_NONE)
4779 rettv->vval.v_string = vim_strsave(str);
4780 else
4781 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4782
4783 convert_setup(&vimconv, NULL, NULL);
4784 vim_free(from);
4785 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004786}
4787
4788/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004789 * "index()" function
4790 */
4791 static void
4792f_index(typval_T *argvars, typval_T *rettv)
4793{
4794 list_T *l;
4795 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004796 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004797 long idx = 0;
4798 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004799 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004800
4801 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004802 if (argvars[0].v_type == VAR_BLOB)
4803 {
4804 typval_T tv;
4805 int start = 0;
4806
4807 if (argvars[2].v_type != VAR_UNKNOWN)
4808 {
4809 start = tv_get_number_chk(&argvars[2], &error);
4810 if (error)
4811 return;
4812 }
4813 b = argvars[0].vval.v_blob;
4814 if (b == NULL)
4815 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004816 if (start < 0)
4817 {
4818 start = blob_len(b) + start;
4819 if (start < 0)
4820 start = 0;
4821 }
4822
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004823 for (idx = start; idx < blob_len(b); ++idx)
4824 {
4825 tv.v_type = VAR_NUMBER;
4826 tv.vval.v_number = blob_get(b, idx);
4827 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4828 {
4829 rettv->vval.v_number = idx;
4830 return;
4831 }
4832 }
4833 return;
4834 }
4835 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004836 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004837 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004838 return;
4839 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004840
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841 l = argvars[0].vval.v_list;
4842 if (l != NULL)
4843 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004844 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004845 item = l->lv_first;
4846 if (argvars[2].v_type != VAR_UNKNOWN)
4847 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004848 // Start at specified item. Use the cached index that list_find()
4849 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004850 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004851 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004853 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004854 if (error)
4855 item = NULL;
4856 }
4857
4858 for ( ; item != NULL; item = item->li_next, ++idx)
4859 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4860 {
4861 rettv->vval.v_number = idx;
4862 break;
4863 }
4864 }
4865}
4866
4867static int inputsecret_flag = 0;
4868
4869/*
4870 * "input()" function
4871 * Also handles inputsecret() when inputsecret is set.
4872 */
4873 static void
4874f_input(typval_T *argvars, typval_T *rettv)
4875{
4876 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4877}
4878
4879/*
4880 * "inputdialog()" function
4881 */
4882 static void
4883f_inputdialog(typval_T *argvars, typval_T *rettv)
4884{
4885#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004886 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004887 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4888 {
4889 char_u *message;
4890 char_u buf[NUMBUFLEN];
4891 char_u *defstr = (char_u *)"";
4892
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004893 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004895 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004896 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4897 else
4898 IObuff[0] = NUL;
4899 if (message != NULL && defstr != NULL
4900 && do_dialog(VIM_QUESTION, NULL, message,
4901 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4902 rettv->vval.v_string = vim_strsave(IObuff);
4903 else
4904 {
4905 if (message != NULL && defstr != NULL
4906 && argvars[1].v_type != VAR_UNKNOWN
4907 && argvars[2].v_type != VAR_UNKNOWN)
4908 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004909 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 else
4911 rettv->vval.v_string = NULL;
4912 }
4913 rettv->v_type = VAR_STRING;
4914 }
4915 else
4916#endif
4917 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4918}
4919
4920/*
4921 * "inputlist()" function
4922 */
4923 static void
4924f_inputlist(typval_T *argvars, typval_T *rettv)
4925{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004926 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004927 listitem_T *li;
4928 int selected;
4929 int mouse_used;
4930
4931#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004932 // While starting up, there is no place to enter text. When running tests
4933 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004934 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935 return;
4936#endif
4937 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4938 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004939 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940 return;
4941 }
4942
4943 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004944 msg_row = Rows - 1; // for when 'cmdheight' > 1
4945 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946 msg_scroll = TRUE;
4947 msg_clr_eos();
4948
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004949 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004950 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02004951 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004952 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004953 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004954 msg_putchar('\n');
4955 }
4956
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004957 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958 selected = prompt_for_number(&mouse_used);
4959 if (mouse_used)
4960 selected -= lines_left;
4961
4962 rettv->vval.v_number = selected;
4963}
4964
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4966
4967/*
4968 * "inputrestore()" function
4969 */
4970 static void
4971f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4972{
4973 if (ga_userinput.ga_len > 0)
4974 {
4975 --ga_userinput.ga_len;
4976 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4977 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004978 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004979 }
4980 else if (p_verbose > 1)
4981 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004982 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004983 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984 }
4985}
4986
4987/*
4988 * "inputsave()" function
4989 */
4990 static void
4991f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4992{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004993 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004994 if (ga_grow(&ga_userinput, 1) == OK)
4995 {
4996 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4997 + ga_userinput.ga_len);
4998 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004999 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000 }
5001 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005002 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005003}
5004
5005/*
5006 * "inputsecret()" function
5007 */
5008 static void
5009f_inputsecret(typval_T *argvars, typval_T *rettv)
5010{
5011 ++cmdline_star;
5012 ++inputsecret_flag;
5013 f_input(argvars, rettv);
5014 --cmdline_star;
5015 --inputsecret_flag;
5016}
5017
5018/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005019 * "interrupt()" function
5020 */
5021 static void
5022f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5023{
5024 got_int = TRUE;
5025}
5026
5027/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005028 * "invert(expr)" function
5029 */
5030 static void
5031f_invert(typval_T *argvars, typval_T *rettv)
5032{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005033 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034}
5035
5036/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037 * "islocked()" function
5038 */
5039 static void
5040f_islocked(typval_T *argvars, typval_T *rettv)
5041{
5042 lval_T lv;
5043 char_u *end;
5044 dictitem_T *di;
5045
5046 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005047 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005048 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005049 if (end != NULL && lv.ll_name != NULL)
5050 {
5051 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005052 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053 else
5054 {
5055 if (lv.ll_tv == NULL)
5056 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005057 di = find_var(lv.ll_name, NULL, TRUE);
5058 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005059 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005060 // Consider a variable locked when:
5061 // 1. the variable itself is locked
5062 // 2. the value of the variable is locked.
5063 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005064 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5065 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005066 }
5067 }
5068 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005069 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005070 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005071 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005072 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005073 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005074 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5075 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005076 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5078 }
5079 }
5080
5081 clear_lval(&lv);
5082}
5083
5084#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5085/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005086 * "isinf()" function
5087 */
5088 static void
5089f_isinf(typval_T *argvars, typval_T *rettv)
5090{
5091 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5092 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5093}
5094
5095/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096 * "isnan()" function
5097 */
5098 static void
5099f_isnan(typval_T *argvars, typval_T *rettv)
5100{
5101 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5102 && isnan(argvars[0].vval.v_float);
5103}
5104#endif
5105
5106/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 * "last_buffer_nr()" function.
5108 */
5109 static void
5110f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5111{
5112 int n = 0;
5113 buf_T *buf;
5114
Bram Moolenaar29323592016-07-24 22:04:11 +02005115 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005116 if (n < buf->b_fnum)
5117 n = buf->b_fnum;
5118
5119 rettv->vval.v_number = n;
5120}
5121
5122/*
5123 * "len()" function
5124 */
5125 static void
5126f_len(typval_T *argvars, typval_T *rettv)
5127{
5128 switch (argvars[0].v_type)
5129 {
5130 case VAR_STRING:
5131 case VAR_NUMBER:
5132 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005133 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005134 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005135 case VAR_BLOB:
5136 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5137 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005138 case VAR_LIST:
5139 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5140 break;
5141 case VAR_DICT:
5142 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5143 break;
5144 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005145 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005146 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005147 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005148 case VAR_SPECIAL:
5149 case VAR_FLOAT:
5150 case VAR_FUNC:
5151 case VAR_PARTIAL:
5152 case VAR_JOB:
5153 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005154 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005155 break;
5156 }
5157}
5158
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005159 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005160libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005161{
5162#ifdef FEAT_LIBCALL
5163 char_u *string_in;
5164 char_u **string_result;
5165 int nr_result;
5166#endif
5167
5168 rettv->v_type = type;
5169 if (type != VAR_NUMBER)
5170 rettv->vval.v_string = NULL;
5171
5172 if (check_restricted() || check_secure())
5173 return;
5174
5175#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005176 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005177 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5178 {
5179 string_in = NULL;
5180 if (argvars[2].v_type == VAR_STRING)
5181 string_in = argvars[2].vval.v_string;
5182 if (type == VAR_NUMBER)
5183 string_result = NULL;
5184 else
5185 string_result = &rettv->vval.v_string;
5186 if (mch_libcall(argvars[0].vval.v_string,
5187 argvars[1].vval.v_string,
5188 string_in,
5189 argvars[2].vval.v_number,
5190 string_result,
5191 &nr_result) == OK
5192 && type == VAR_NUMBER)
5193 rettv->vval.v_number = nr_result;
5194 }
5195#endif
5196}
5197
5198/*
5199 * "libcall()" function
5200 */
5201 static void
5202f_libcall(typval_T *argvars, typval_T *rettv)
5203{
5204 libcall_common(argvars, rettv, VAR_STRING);
5205}
5206
5207/*
5208 * "libcallnr()" function
5209 */
5210 static void
5211f_libcallnr(typval_T *argvars, typval_T *rettv)
5212{
5213 libcall_common(argvars, rettv, VAR_NUMBER);
5214}
5215
5216/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005217 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005218 */
5219 static void
5220f_line(typval_T *argvars, typval_T *rettv)
5221{
5222 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005223 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005224 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005225 int id;
5226 tabpage_T *tp;
5227 win_T *wp;
5228 win_T *save_curwin;
5229 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005230
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005231 if (argvars[1].v_type != VAR_UNKNOWN)
5232 {
5233 // use window specified in the second argument
5234 id = (int)tv_get_number(&argvars[1]);
5235 wp = win_id2wp_tp(id, &tp);
5236 if (wp != NULL && tp != NULL)
5237 {
5238 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5239 == OK)
5240 {
5241 check_cursor();
5242 fp = var2fpos(&argvars[0], TRUE, &fnum);
5243 }
5244 restore_win_noblock(save_curwin, save_curtab, TRUE);
5245 }
5246 }
5247 else
5248 // use current window
5249 fp = var2fpos(&argvars[0], TRUE, &fnum);
5250
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005251 if (fp != NULL)
5252 lnum = fp->lnum;
5253 rettv->vval.v_number = lnum;
5254}
5255
5256/*
5257 * "line2byte(lnum)" function
5258 */
5259 static void
5260f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5261{
5262#ifndef FEAT_BYTEOFF
5263 rettv->vval.v_number = -1;
5264#else
5265 linenr_T lnum;
5266
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005267 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005268 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5269 rettv->vval.v_number = -1;
5270 else
5271 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5272 if (rettv->vval.v_number >= 0)
5273 ++rettv->vval.v_number;
5274#endif
5275}
5276
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005277#ifdef FEAT_FLOAT
5278/*
5279 * "log()" function
5280 */
5281 static void
5282f_log(typval_T *argvars, typval_T *rettv)
5283{
5284 float_T f = 0.0;
5285
5286 rettv->v_type = VAR_FLOAT;
5287 if (get_float_arg(argvars, &f) == OK)
5288 rettv->vval.v_float = log(f);
5289 else
5290 rettv->vval.v_float = 0.0;
5291}
5292
5293/*
5294 * "log10()" function
5295 */
5296 static void
5297f_log10(typval_T *argvars, typval_T *rettv)
5298{
5299 float_T f = 0.0;
5300
5301 rettv->v_type = VAR_FLOAT;
5302 if (get_float_arg(argvars, &f) == OK)
5303 rettv->vval.v_float = log10(f);
5304 else
5305 rettv->vval.v_float = 0.0;
5306}
5307#endif
5308
5309#ifdef FEAT_LUA
5310/*
5311 * "luaeval()" function
5312 */
5313 static void
5314f_luaeval(typval_T *argvars, typval_T *rettv)
5315{
5316 char_u *str;
5317 char_u buf[NUMBUFLEN];
5318
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005319 if (check_restricted() || check_secure())
5320 return;
5321
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005322 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005323 do_luaeval(str, argvars + 1, rettv);
5324}
5325#endif
5326
5327/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005328 * "maparg()" function
5329 */
5330 static void
5331f_maparg(typval_T *argvars, typval_T *rettv)
5332{
5333 get_maparg(argvars, rettv, TRUE);
5334}
5335
5336/*
5337 * "mapcheck()" function
5338 */
5339 static void
5340f_mapcheck(typval_T *argvars, typval_T *rettv)
5341{
5342 get_maparg(argvars, rettv, FALSE);
5343}
5344
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005345typedef enum
5346{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005347 MATCH_END, // matchend()
5348 MATCH_MATCH, // match()
5349 MATCH_STR, // matchstr()
5350 MATCH_LIST, // matchlist()
5351 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005352} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005353
5354 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005355find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005356{
5357 char_u *str = NULL;
5358 long len = 0;
5359 char_u *expr = NULL;
5360 char_u *pat;
5361 regmatch_T regmatch;
5362 char_u patbuf[NUMBUFLEN];
5363 char_u strbuf[NUMBUFLEN];
5364 char_u *save_cpo;
5365 long start = 0;
5366 long nth = 1;
5367 colnr_T startcol = 0;
5368 int match = 0;
5369 list_T *l = NULL;
5370 listitem_T *li = NULL;
5371 long idx = 0;
5372 char_u *tofree = NULL;
5373
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005374 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005375 save_cpo = p_cpo;
5376 p_cpo = (char_u *)"";
5377
5378 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005379 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005380 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005381 // type MATCH_LIST: return empty list when there are no matches.
5382 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005383 if (rettv_list_alloc(rettv) == FAIL)
5384 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005385 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005386 && (list_append_string(rettv->vval.v_list,
5387 (char_u *)"", 0) == FAIL
5388 || list_append_number(rettv->vval.v_list,
5389 (varnumber_T)-1) == FAIL
5390 || list_append_number(rettv->vval.v_list,
5391 (varnumber_T)-1) == FAIL
5392 || list_append_number(rettv->vval.v_list,
5393 (varnumber_T)-1) == FAIL))
5394 {
5395 list_free(rettv->vval.v_list);
5396 rettv->vval.v_list = NULL;
5397 goto theend;
5398 }
5399 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005400 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005401 {
5402 rettv->v_type = VAR_STRING;
5403 rettv->vval.v_string = NULL;
5404 }
5405
5406 if (argvars[0].v_type == VAR_LIST)
5407 {
5408 if ((l = argvars[0].vval.v_list) == NULL)
5409 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005410 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005411 li = l->lv_first;
5412 }
5413 else
5414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005415 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005416 len = (long)STRLEN(str);
5417 }
5418
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005419 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005420 if (pat == NULL)
5421 goto theend;
5422
5423 if (argvars[2].v_type != VAR_UNKNOWN)
5424 {
5425 int error = FALSE;
5426
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005427 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005428 if (error)
5429 goto theend;
5430 if (l != NULL)
5431 {
5432 li = list_find(l, start);
5433 if (li == NULL)
5434 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005435 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005436 }
5437 else
5438 {
5439 if (start < 0)
5440 start = 0;
5441 if (start > len)
5442 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005443 // When "count" argument is there ignore matches before "start",
5444 // otherwise skip part of the string. Differs when pattern is "^"
5445 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005446 if (argvars[3].v_type != VAR_UNKNOWN)
5447 startcol = start;
5448 else
5449 {
5450 str += start;
5451 len -= start;
5452 }
5453 }
5454
5455 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005456 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457 if (error)
5458 goto theend;
5459 }
5460
5461 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5462 if (regmatch.regprog != NULL)
5463 {
5464 regmatch.rm_ic = p_ic;
5465
5466 for (;;)
5467 {
5468 if (l != NULL)
5469 {
5470 if (li == NULL)
5471 {
5472 match = FALSE;
5473 break;
5474 }
5475 vim_free(tofree);
5476 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5477 if (str == NULL)
5478 break;
5479 }
5480
5481 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5482
5483 if (match && --nth <= 0)
5484 break;
5485 if (l == NULL && !match)
5486 break;
5487
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005488 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489 if (l != NULL)
5490 {
5491 li = li->li_next;
5492 ++idx;
5493 }
5494 else
5495 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005496 startcol = (colnr_T)(regmatch.startp[0]
5497 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005498 if (startcol > (colnr_T)len
5499 || str + startcol <= regmatch.startp[0])
5500 {
5501 match = FALSE;
5502 break;
5503 }
5504 }
5505 }
5506
5507 if (match)
5508 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005509 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005510 {
5511 listitem_T *li1 = rettv->vval.v_list->lv_first;
5512 listitem_T *li2 = li1->li_next;
5513 listitem_T *li3 = li2->li_next;
5514 listitem_T *li4 = li3->li_next;
5515
5516 vim_free(li1->li_tv.vval.v_string);
5517 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5518 (int)(regmatch.endp[0] - regmatch.startp[0]));
5519 li3->li_tv.vval.v_number =
5520 (varnumber_T)(regmatch.startp[0] - expr);
5521 li4->li_tv.vval.v_number =
5522 (varnumber_T)(regmatch.endp[0] - expr);
5523 if (l != NULL)
5524 li2->li_tv.vval.v_number = (varnumber_T)idx;
5525 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005526 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005527 {
5528 int i;
5529
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005530 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005531 for (i = 0; i < NSUBEXP; ++i)
5532 {
5533 if (regmatch.endp[i] == NULL)
5534 {
5535 if (list_append_string(rettv->vval.v_list,
5536 (char_u *)"", 0) == FAIL)
5537 break;
5538 }
5539 else if (list_append_string(rettv->vval.v_list,
5540 regmatch.startp[i],
5541 (int)(regmatch.endp[i] - regmatch.startp[i]))
5542 == FAIL)
5543 break;
5544 }
5545 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005546 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005547 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005548 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005549 if (l != NULL)
5550 copy_tv(&li->li_tv, rettv);
5551 else
5552 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
5553 (int)(regmatch.endp[0] - regmatch.startp[0]));
5554 }
5555 else if (l != NULL)
5556 rettv->vval.v_number = idx;
5557 else
5558 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005559 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005560 rettv->vval.v_number =
5561 (varnumber_T)(regmatch.startp[0] - str);
5562 else
5563 rettv->vval.v_number =
5564 (varnumber_T)(regmatch.endp[0] - str);
5565 rettv->vval.v_number += (varnumber_T)(str - expr);
5566 }
5567 }
5568 vim_regfree(regmatch.regprog);
5569 }
5570
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005571theend:
5572 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005573 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005574 listitem_remove(rettv->vval.v_list,
5575 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005576 vim_free(tofree);
5577 p_cpo = save_cpo;
5578}
5579
5580/*
5581 * "match()" function
5582 */
5583 static void
5584f_match(typval_T *argvars, typval_T *rettv)
5585{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005586 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005587}
5588
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005589/*
5590 * "matchend()" function
5591 */
5592 static void
5593f_matchend(typval_T *argvars, typval_T *rettv)
5594{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005595 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596}
5597
5598/*
5599 * "matchlist()" function
5600 */
5601 static void
5602f_matchlist(typval_T *argvars, typval_T *rettv)
5603{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005604 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605}
5606
5607/*
5608 * "matchstr()" function
5609 */
5610 static void
5611f_matchstr(typval_T *argvars, typval_T *rettv)
5612{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005613 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005614}
5615
5616/*
5617 * "matchstrpos()" function
5618 */
5619 static void
5620f_matchstrpos(typval_T *argvars, typval_T *rettv)
5621{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005622 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005623}
5624
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625 static void
5626max_min(typval_T *argvars, typval_T *rettv, int domax)
5627{
5628 varnumber_T n = 0;
5629 varnumber_T i;
5630 int error = FALSE;
5631
5632 if (argvars[0].v_type == VAR_LIST)
5633 {
5634 list_T *l;
5635 listitem_T *li;
5636
5637 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005638 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005640 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005641 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005642 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5643 n = l->lv_u.nonmat.lv_start;
5644 else
5645 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5646 * l->lv_u.nonmat.lv_stride;
5647 }
5648 else
5649 {
5650 li = l->lv_first;
5651 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005652 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005653 n = tv_get_number_chk(&li->li_tv, &error);
5654 for (;;)
5655 {
5656 li = li->li_next;
5657 if (li == NULL)
5658 break;
5659 i = tv_get_number_chk(&li->li_tv, &error);
5660 if (domax ? i > n : i < n)
5661 n = i;
5662 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005663 }
5664 }
5665 }
5666 }
5667 else if (argvars[0].v_type == VAR_DICT)
5668 {
5669 dict_T *d;
5670 int first = TRUE;
5671 hashitem_T *hi;
5672 int todo;
5673
5674 d = argvars[0].vval.v_dict;
5675 if (d != NULL)
5676 {
5677 todo = (int)d->dv_hashtab.ht_used;
5678 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5679 {
5680 if (!HASHITEM_EMPTY(hi))
5681 {
5682 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005683 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005684 if (first)
5685 {
5686 n = i;
5687 first = FALSE;
5688 }
5689 else if (domax ? i > n : i < n)
5690 n = i;
5691 }
5692 }
5693 }
5694 }
5695 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005696 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005697 rettv->vval.v_number = error ? 0 : n;
5698}
5699
5700/*
5701 * "max()" function
5702 */
5703 static void
5704f_max(typval_T *argvars, typval_T *rettv)
5705{
5706 max_min(argvars, rettv, TRUE);
5707}
5708
5709/*
5710 * "min()" function
5711 */
5712 static void
5713f_min(typval_T *argvars, typval_T *rettv)
5714{
5715 max_min(argvars, rettv, FALSE);
5716}
5717
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005718#if defined(FEAT_MZSCHEME) || defined(PROTO)
5719/*
5720 * "mzeval()" function
5721 */
5722 static void
5723f_mzeval(typval_T *argvars, typval_T *rettv)
5724{
5725 char_u *str;
5726 char_u buf[NUMBUFLEN];
5727
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005728 if (check_restricted() || check_secure())
5729 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005730 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005731 do_mzeval(str, rettv);
5732}
5733
5734 void
5735mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5736{
5737 typval_T argvars[3];
5738
5739 argvars[0].v_type = VAR_STRING;
5740 argvars[0].vval.v_string = name;
5741 copy_tv(args, &argvars[1]);
5742 argvars[2].v_type = VAR_UNKNOWN;
5743 f_call(argvars, rettv);
5744 clear_tv(&argvars[1]);
5745}
5746#endif
5747
5748/*
5749 * "nextnonblank()" function
5750 */
5751 static void
5752f_nextnonblank(typval_T *argvars, typval_T *rettv)
5753{
5754 linenr_T lnum;
5755
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005756 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005757 {
5758 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5759 {
5760 lnum = 0;
5761 break;
5762 }
5763 if (*skipwhite(ml_get(lnum)) != NUL)
5764 break;
5765 }
5766 rettv->vval.v_number = lnum;
5767}
5768
5769/*
5770 * "nr2char()" function
5771 */
5772 static void
5773f_nr2char(typval_T *argvars, typval_T *rettv)
5774{
5775 char_u buf[NUMBUFLEN];
5776
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005777 if (has_mbyte)
5778 {
5779 int utf8 = 0;
5780
5781 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005782 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005784 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005785 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005786 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005787 }
5788 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005789 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005790 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791 buf[1] = NUL;
5792 }
5793 rettv->v_type = VAR_STRING;
5794 rettv->vval.v_string = vim_strsave(buf);
5795}
5796
5797/*
5798 * "or(expr, expr)" function
5799 */
5800 static void
5801f_or(typval_T *argvars, typval_T *rettv)
5802{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005803 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5804 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005805}
5806
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005807#ifdef FEAT_PERL
5808/*
5809 * "perleval()" function
5810 */
5811 static void
5812f_perleval(typval_T *argvars, typval_T *rettv)
5813{
5814 char_u *str;
5815 char_u buf[NUMBUFLEN];
5816
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005817 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005818 do_perleval(str, rettv);
5819}
5820#endif
5821
5822#ifdef FEAT_FLOAT
5823/*
5824 * "pow()" function
5825 */
5826 static void
5827f_pow(typval_T *argvars, typval_T *rettv)
5828{
5829 float_T fx = 0.0, fy = 0.0;
5830
5831 rettv->v_type = VAR_FLOAT;
5832 if (get_float_arg(argvars, &fx) == OK
5833 && get_float_arg(&argvars[1], &fy) == OK)
5834 rettv->vval.v_float = pow(fx, fy);
5835 else
5836 rettv->vval.v_float = 0.0;
5837}
5838#endif
5839
5840/*
5841 * "prevnonblank()" function
5842 */
5843 static void
5844f_prevnonblank(typval_T *argvars, typval_T *rettv)
5845{
5846 linenr_T lnum;
5847
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005848 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005849 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5850 lnum = 0;
5851 else
5852 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5853 --lnum;
5854 rettv->vval.v_number = lnum;
5855}
5856
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005857// This dummy va_list is here because:
5858// - passing a NULL pointer doesn't work when va_list isn't a pointer
5859// - locally in the function results in a "used before set" warning
5860// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005861static va_list ap;
5862
5863/*
5864 * "printf()" function
5865 */
5866 static void
5867f_printf(typval_T *argvars, typval_T *rettv)
5868{
5869 char_u buf[NUMBUFLEN];
5870 int len;
5871 char_u *s;
5872 int saved_did_emsg = did_emsg;
5873 char *fmt;
5874
5875 rettv->v_type = VAR_STRING;
5876 rettv->vval.v_string = NULL;
5877
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005878 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005879 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005880 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005881 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005882 if (!did_emsg)
5883 {
5884 s = alloc(len + 1);
5885 if (s != NULL)
5886 {
5887 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005888 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5889 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005890 }
5891 }
5892 did_emsg |= saved_did_emsg;
5893}
5894
5895/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005896 * "pum_getpos()" function
5897 */
5898 static void
5899f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5900{
5901 if (rettv_dict_alloc(rettv) != OK)
5902 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005903 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005904}
5905
5906/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005907 * "pumvisible()" function
5908 */
5909 static void
5910f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5911{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912 if (pum_visible())
5913 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914}
5915
5916#ifdef FEAT_PYTHON3
5917/*
5918 * "py3eval()" function
5919 */
5920 static void
5921f_py3eval(typval_T *argvars, typval_T *rettv)
5922{
5923 char_u *str;
5924 char_u buf[NUMBUFLEN];
5925
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005926 if (check_restricted() || check_secure())
5927 return;
5928
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005929 if (p_pyx == 0)
5930 p_pyx = 3;
5931
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005932 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005933 do_py3eval(str, rettv);
5934}
5935#endif
5936
5937#ifdef FEAT_PYTHON
5938/*
5939 * "pyeval()" function
5940 */
5941 static void
5942f_pyeval(typval_T *argvars, typval_T *rettv)
5943{
5944 char_u *str;
5945 char_u buf[NUMBUFLEN];
5946
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005947 if (check_restricted() || check_secure())
5948 return;
5949
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005950 if (p_pyx == 0)
5951 p_pyx = 2;
5952
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005953 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005954 do_pyeval(str, rettv);
5955}
5956#endif
5957
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005958#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5959/*
5960 * "pyxeval()" function
5961 */
5962 static void
5963f_pyxeval(typval_T *argvars, typval_T *rettv)
5964{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005965 if (check_restricted() || check_secure())
5966 return;
5967
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005968# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5969 init_pyxversion();
5970 if (p_pyx == 2)
5971 f_pyeval(argvars, rettv);
5972 else
5973 f_py3eval(argvars, rettv);
5974# elif defined(FEAT_PYTHON)
5975 f_pyeval(argvars, rettv);
5976# elif defined(FEAT_PYTHON3)
5977 f_py3eval(argvars, rettv);
5978# endif
5979}
5980#endif
5981
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005982static UINT32_T srand_seed_for_testing = 0;
5983static int srand_seed_for_testing_is_used = FALSE;
5984
5985 static void
5986f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5987{
5988 if (argvars[0].v_type == VAR_UNKNOWN)
5989 srand_seed_for_testing_is_used = FALSE;
5990 else
5991 {
5992 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5993 srand_seed_for_testing_is_used = TRUE;
5994 }
5995}
5996
5997 static void
5998init_srand(UINT32_T *x)
5999{
6000#ifndef MSWIN
6001 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6002#endif
6003
6004 if (srand_seed_for_testing_is_used)
6005 {
6006 *x = srand_seed_for_testing;
6007 return;
6008 }
6009#ifndef MSWIN
6010 if (dev_urandom_state != FAIL)
6011 {
6012 int fd = open("/dev/urandom", O_RDONLY);
6013 struct {
6014 union {
6015 UINT32_T number;
6016 char bytes[sizeof(UINT32_T)];
6017 } contents;
6018 } buf;
6019
6020 // Attempt reading /dev/urandom.
6021 if (fd == -1)
6022 dev_urandom_state = FAIL;
6023 else
6024 {
6025 buf.contents.number = 0;
6026 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6027 != sizeof(UINT32_T))
6028 dev_urandom_state = FAIL;
6029 else
6030 {
6031 dev_urandom_state = OK;
6032 *x = buf.contents.number;
6033 }
6034 close(fd);
6035 }
6036 }
6037 if (dev_urandom_state != OK)
6038 // Reading /dev/urandom doesn't work, fall back to time().
6039#endif
6040 *x = vim_time();
6041}
6042
6043#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6044#define SPLITMIX32(x, z) ( \
6045 z = (x += 0x9e3779b9), \
6046 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6047 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6048 z ^ (z >> 16) \
6049 )
6050#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6051 result = ROTL(y * 5, 7) * 9; \
6052 t = y << 9; \
6053 z ^= x; \
6054 w ^= y; \
6055 y ^= z, x ^= w; \
6056 z ^= t; \
6057 w = ROTL(w, 11);
6058
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006059/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006060 * "rand()" function
6061 */
6062 static void
6063f_rand(typval_T *argvars, typval_T *rettv)
6064{
6065 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006066 static UINT32_T gx, gy, gz, gw;
6067 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006068 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006069 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006070
6071 if (argvars[0].v_type == VAR_UNKNOWN)
6072 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006073 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006074 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006075 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006076 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006077 init_srand(&x);
6078
6079 gx = SPLITMIX32(x, z);
6080 gy = SPLITMIX32(x, z);
6081 gz = SPLITMIX32(x, z);
6082 gw = SPLITMIX32(x, z);
6083 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006084 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006085
6086 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006087 }
6088 else if (argvars[0].v_type == VAR_LIST)
6089 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006090 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006091 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006092 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006093
6094 lx = list_find(l, 0L);
6095 ly = list_find(l, 1L);
6096 lz = list_find(l, 2L);
6097 lw = list_find(l, 3L);
6098 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6099 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6100 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6101 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6102 x = (UINT32_T)lx->li_tv.vval.v_number;
6103 y = (UINT32_T)ly->li_tv.vval.v_number;
6104 z = (UINT32_T)lz->li_tv.vval.v_number;
6105 w = (UINT32_T)lw->li_tv.vval.v_number;
6106
6107 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6108
6109 lx->li_tv.vval.v_number = (varnumber_T)x;
6110 ly->li_tv.vval.v_number = (varnumber_T)y;
6111 lz->li_tv.vval.v_number = (varnumber_T)z;
6112 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006113 }
6114 else
6115 goto theend;
6116
6117 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006118 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006119 return;
6120
6121theend:
6122 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006123 rettv->v_type = VAR_NUMBER;
6124 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006125}
6126
6127/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006128 * "srand()" function
6129 */
6130 static void
6131f_srand(typval_T *argvars, typval_T *rettv)
6132{
6133 UINT32_T x = 0, z;
6134
6135 if (rettv_list_alloc(rettv) == FAIL)
6136 return;
6137 if (argvars[0].v_type == VAR_UNKNOWN)
6138 {
6139 init_srand(&x);
6140 }
6141 else
6142 {
6143 int error = FALSE;
6144
6145 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6146 if (error)
6147 return;
6148 }
6149
6150 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6151 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6152 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6153 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6154}
6155
6156#undef ROTL
6157#undef SPLITMIX32
6158#undef SHUFFLE_XOSHIRO128STARSTAR
6159
6160/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006161 * "range()" function
6162 */
6163 static void
6164f_range(typval_T *argvars, typval_T *rettv)
6165{
6166 varnumber_T start;
6167 varnumber_T end;
6168 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006169 int error = FALSE;
6170
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006171 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006172 if (argvars[1].v_type == VAR_UNKNOWN)
6173 {
6174 end = start - 1;
6175 start = 0;
6176 }
6177 else
6178 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006179 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006180 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006181 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182 }
6183
6184 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006185 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006187 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006189 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006190 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006191 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006192 list_T *list = rettv->vval.v_list;
6193
6194 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006195 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006196 // be called.
6197 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006198 list->lv_u.nonmat.lv_start = start;
6199 list->lv_u.nonmat.lv_end = end;
6200 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006201 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006202 }
6203}
6204
6205/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006206 * Materialize "list".
6207 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006208 */
6209 void
6210range_list_materialize(list_T *list)
6211{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006212 varnumber_T start = list->lv_u.nonmat.lv_start;
6213 varnumber_T end = list->lv_u.nonmat.lv_end;
6214 int stride = list->lv_u.nonmat.lv_stride;
6215 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006216
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006217 list->lv_first = NULL;
6218 list->lv_u.mat.lv_last = NULL;
6219 list->lv_len = 0;
6220 list->lv_u.mat.lv_idx_item = NULL;
6221 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6222 if (list_append_number(list, (varnumber_T)i) == FAIL)
6223 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006224}
6225
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006226 static void
6227return_register(int regname, typval_T *rettv)
6228{
6229 char_u buf[2] = {0, 0};
6230
6231 buf[0] = (char_u)regname;
6232 rettv->v_type = VAR_STRING;
6233 rettv->vval.v_string = vim_strsave(buf);
6234}
6235
6236/*
6237 * "reg_executing()" function
6238 */
6239 static void
6240f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6241{
6242 return_register(reg_executing, rettv);
6243}
6244
6245/*
6246 * "reg_recording()" function
6247 */
6248 static void
6249f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6250{
6251 return_register(reg_recording, rettv);
6252}
6253
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006254/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006255 * "rename({from}, {to})" function
6256 */
6257 static void
6258f_rename(typval_T *argvars, typval_T *rettv)
6259{
6260 char_u buf[NUMBUFLEN];
6261
6262 if (check_restricted() || check_secure())
6263 rettv->vval.v_number = -1;
6264 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006265 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6266 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006267}
6268
6269/*
6270 * "repeat()" function
6271 */
6272 static void
6273f_repeat(typval_T *argvars, typval_T *rettv)
6274{
6275 char_u *p;
6276 int n;
6277 int slen;
6278 int len;
6279 char_u *r;
6280 int i;
6281
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006282 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283 if (argvars[0].v_type == VAR_LIST)
6284 {
6285 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6286 while (n-- > 0)
6287 if (list_extend(rettv->vval.v_list,
6288 argvars[0].vval.v_list, NULL) == FAIL)
6289 break;
6290 }
6291 else
6292 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006293 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294 rettv->v_type = VAR_STRING;
6295 rettv->vval.v_string = NULL;
6296
6297 slen = (int)STRLEN(p);
6298 len = slen * n;
6299 if (len <= 0)
6300 return;
6301
6302 r = alloc(len + 1);
6303 if (r != NULL)
6304 {
6305 for (i = 0; i < n; i++)
6306 mch_memmove(r + i * slen, p, (size_t)slen);
6307 r[len] = NUL;
6308 }
6309
6310 rettv->vval.v_string = r;
6311 }
6312}
6313
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006314#define SP_NOMOVE 0x01 // don't move cursor
6315#define SP_REPEAT 0x02 // repeat to find outer pair
6316#define SP_RETCOUNT 0x04 // return matchcount
6317#define SP_SETPCMARK 0x08 // set previous context mark
6318#define SP_START 0x10 // accept match at start position
6319#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6320#define SP_END 0x40 // leave cursor at end of match
6321#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323/*
6324 * Get flags for a search function.
6325 * Possibly sets "p_ws".
6326 * Returns BACKWARD, FORWARD or zero (for an error).
6327 */
6328 static int
6329get_search_arg(typval_T *varp, int *flagsp)
6330{
6331 int dir = FORWARD;
6332 char_u *flags;
6333 char_u nbuf[NUMBUFLEN];
6334 int mask;
6335
6336 if (varp->v_type != VAR_UNKNOWN)
6337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006338 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006339 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006340 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341 while (*flags != NUL)
6342 {
6343 switch (*flags)
6344 {
6345 case 'b': dir = BACKWARD; break;
6346 case 'w': p_ws = TRUE; break;
6347 case 'W': p_ws = FALSE; break;
6348 default: mask = 0;
6349 if (flagsp != NULL)
6350 switch (*flags)
6351 {
6352 case 'c': mask = SP_START; break;
6353 case 'e': mask = SP_END; break;
6354 case 'm': mask = SP_RETCOUNT; break;
6355 case 'n': mask = SP_NOMOVE; break;
6356 case 'p': mask = SP_SUBPAT; break;
6357 case 'r': mask = SP_REPEAT; break;
6358 case 's': mask = SP_SETPCMARK; break;
6359 case 'z': mask = SP_COLUMN; break;
6360 }
6361 if (mask == 0)
6362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006363 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006364 dir = 0;
6365 }
6366 else
6367 *flagsp |= mask;
6368 }
6369 if (dir == 0)
6370 break;
6371 ++flags;
6372 }
6373 }
6374 return dir;
6375}
6376
6377/*
6378 * Shared by search() and searchpos() functions.
6379 */
6380 static int
6381search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6382{
6383 int flags;
6384 char_u *pat;
6385 pos_T pos;
6386 pos_T save_cursor;
6387 int save_p_ws = p_ws;
6388 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006389 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006390 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006391#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006392 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 long time_limit = 0;
6394#endif
6395 int options = SEARCH_KEEP;
6396 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006397 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006398
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006399 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006400 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006401 if (dir == 0)
6402 goto theend;
6403 flags = *flagsp;
6404 if (flags & SP_START)
6405 options |= SEARCH_START;
6406 if (flags & SP_END)
6407 options |= SEARCH_END;
6408 if (flags & SP_COLUMN)
6409 options |= SEARCH_COL;
6410
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006411 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6413 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006414 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 if (lnum_stop < 0)
6416 goto theend;
6417#ifdef FEAT_RELTIME
6418 if (argvars[3].v_type != VAR_UNKNOWN)
6419 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006420 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421 if (time_limit < 0)
6422 goto theend;
6423 }
6424#endif
6425 }
6426
6427#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006428 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006429 profile_setlimit(time_limit, &tm);
6430#endif
6431
6432 /*
6433 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6434 * Check to make sure only those flags are set.
6435 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6436 * flags cannot be set. Check for that condition also.
6437 */
6438 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6439 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6440 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006441 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 goto theend;
6443 }
6444
6445 pos = save_cursor = curwin->w_cursor;
Bram Moolenaara80faa82020-04-12 19:37:17 +02006446 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006447 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6448#ifdef FEAT_RELTIME
6449 sia.sa_tm = &tm;
6450#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006451 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006452 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006453 if (subpatnum != FAIL)
6454 {
6455 if (flags & SP_SUBPAT)
6456 retval = subpatnum;
6457 else
6458 retval = pos.lnum;
6459 if (flags & SP_SETPCMARK)
6460 setpcmark();
6461 curwin->w_cursor = pos;
6462 if (match_pos != NULL)
6463 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006464 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465 match_pos->lnum = pos.lnum;
6466 match_pos->col = pos.col + 1;
6467 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006468 // "/$" will put the cursor after the end of the line, may need to
6469 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006470 check_cursor();
6471 }
6472
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006473 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 if (flags & SP_NOMOVE)
6475 curwin->w_cursor = save_cursor;
6476 else
6477 curwin->w_set_curswant = TRUE;
6478theend:
6479 p_ws = save_p_ws;
6480
6481 return retval;
6482}
6483
6484#ifdef FEAT_FLOAT
6485
6486/*
6487 * round() is not in C90, use ceil() or floor() instead.
6488 */
6489 float_T
6490vim_round(float_T f)
6491{
6492 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6493}
6494
6495/*
6496 * "round({float})" function
6497 */
6498 static void
6499f_round(typval_T *argvars, typval_T *rettv)
6500{
6501 float_T f = 0.0;
6502
6503 rettv->v_type = VAR_FLOAT;
6504 if (get_float_arg(argvars, &f) == OK)
6505 rettv->vval.v_float = vim_round(f);
6506 else
6507 rettv->vval.v_float = 0.0;
6508}
6509#endif
6510
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006511#ifdef FEAT_RUBY
6512/*
6513 * "rubyeval()" function
6514 */
6515 static void
6516f_rubyeval(typval_T *argvars, typval_T *rettv)
6517{
6518 char_u *str;
6519 char_u buf[NUMBUFLEN];
6520
6521 str = tv_get_string_buf(&argvars[0], buf);
6522 do_rubyeval(str, rettv);
6523}
6524#endif
6525
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526/*
6527 * "screenattr()" function
6528 */
6529 static void
6530f_screenattr(typval_T *argvars, typval_T *rettv)
6531{
6532 int row;
6533 int col;
6534 int c;
6535
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006536 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6537 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 if (row < 0 || row >= screen_Rows
6539 || col < 0 || col >= screen_Columns)
6540 c = -1;
6541 else
6542 c = ScreenAttrs[LineOffset[row] + col];
6543 rettv->vval.v_number = c;
6544}
6545
6546/*
6547 * "screenchar()" function
6548 */
6549 static void
6550f_screenchar(typval_T *argvars, typval_T *rettv)
6551{
6552 int row;
6553 int col;
6554 int off;
6555 int c;
6556
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006557 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6558 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006559 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 c = -1;
6561 else
6562 {
6563 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006564 if (enc_utf8 && ScreenLinesUC[off] != 0)
6565 c = ScreenLinesUC[off];
6566 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006567 c = ScreenLines[off];
6568 }
6569 rettv->vval.v_number = c;
6570}
6571
6572/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006573 * "screenchars()" function
6574 */
6575 static void
6576f_screenchars(typval_T *argvars, typval_T *rettv)
6577{
6578 int row;
6579 int col;
6580 int off;
6581 int c;
6582 int i;
6583
6584 if (rettv_list_alloc(rettv) == FAIL)
6585 return;
6586 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6587 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6588 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6589 return;
6590
6591 off = LineOffset[row] + col;
6592 if (enc_utf8 && ScreenLinesUC[off] != 0)
6593 c = ScreenLinesUC[off];
6594 else
6595 c = ScreenLines[off];
6596 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6597
6598 if (enc_utf8)
6599
6600 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6601 list_append_number(rettv->vval.v_list,
6602 (varnumber_T)ScreenLinesC[i][off]);
6603}
6604
6605/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006606 * "screencol()" function
6607 *
6608 * First column is 1 to be consistent with virtcol().
6609 */
6610 static void
6611f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6612{
6613 rettv->vval.v_number = screen_screencol() + 1;
6614}
6615
6616/*
6617 * "screenrow()" function
6618 */
6619 static void
6620f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6621{
6622 rettv->vval.v_number = screen_screenrow() + 1;
6623}
6624
6625/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006626 * "screenstring()" function
6627 */
6628 static void
6629f_screenstring(typval_T *argvars, typval_T *rettv)
6630{
6631 int row;
6632 int col;
6633 int off;
6634 int c;
6635 int i;
6636 char_u buf[MB_MAXBYTES + 1];
6637 int buflen = 0;
6638
6639 rettv->vval.v_string = NULL;
6640 rettv->v_type = VAR_STRING;
6641
6642 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6643 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6644 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6645 return;
6646
6647 off = LineOffset[row] + col;
6648 if (enc_utf8 && ScreenLinesUC[off] != 0)
6649 c = ScreenLinesUC[off];
6650 else
6651 c = ScreenLines[off];
6652 buflen += mb_char2bytes(c, buf);
6653
6654 if (enc_utf8)
6655 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6656 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6657
6658 buf[buflen] = NUL;
6659 rettv->vval.v_string = vim_strsave(buf);
6660}
6661
6662/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006663 * "search()" function
6664 */
6665 static void
6666f_search(typval_T *argvars, typval_T *rettv)
6667{
6668 int flags = 0;
6669
6670 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6671}
6672
6673/*
6674 * "searchdecl()" function
6675 */
6676 static void
6677f_searchdecl(typval_T *argvars, typval_T *rettv)
6678{
6679 int locally = 1;
6680 int thisblock = 0;
6681 int error = FALSE;
6682 char_u *name;
6683
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006684 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006686 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006687 if (argvars[1].v_type != VAR_UNKNOWN)
6688 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006689 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006691 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006692 }
6693 if (!error && name != NULL)
6694 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6695 locally, thisblock, SEARCH_KEEP) == FAIL;
6696}
6697
6698/*
6699 * Used by searchpair() and searchpairpos()
6700 */
6701 static int
6702searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6703{
6704 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006705 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006706 int save_p_ws = p_ws;
6707 int dir;
6708 int flags = 0;
6709 char_u nbuf1[NUMBUFLEN];
6710 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006711 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006712 long lnum_stop = 0;
6713 long time_limit = 0;
6714
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006715 // Get the three pattern arguments: start, middle, end. Will result in an
6716 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006717 spat = tv_get_string_chk(&argvars[0]);
6718 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6719 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006720 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006721 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006722
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006723 // Handle the optional fourth argument: flags
6724 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006725 if (dir == 0)
6726 goto theend;
6727
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006728 // Don't accept SP_END or SP_SUBPAT.
6729 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006730 if ((flags & (SP_END | SP_SUBPAT)) != 0
6731 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6732 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006733 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006734 goto theend;
6735 }
6736
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006737 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006738 if (flags & SP_REPEAT)
6739 p_ws = FALSE;
6740
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006741 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742 if (argvars[3].v_type == VAR_UNKNOWN
6743 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006744 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006745 else
6746 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006747 skip = &argvars[4];
6748 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6749 && skip->v_type != VAR_STRING)
6750 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006751 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006752 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006753 goto theend;
6754 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006755 if (argvars[5].v_type != VAR_UNKNOWN)
6756 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006757 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006759 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006760 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006761 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006762 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006763#ifdef FEAT_RELTIME
6764 if (argvars[6].v_type != VAR_UNKNOWN)
6765 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006766 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006767 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006768 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006769 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006771 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006772 }
6773#endif
6774 }
6775 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776
6777 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6778 match_pos, lnum_stop, time_limit);
6779
6780theend:
6781 p_ws = save_p_ws;
6782
6783 return retval;
6784}
6785
6786/*
6787 * "searchpair()" function
6788 */
6789 static void
6790f_searchpair(typval_T *argvars, typval_T *rettv)
6791{
6792 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6793}
6794
6795/*
6796 * "searchpairpos()" function
6797 */
6798 static void
6799f_searchpairpos(typval_T *argvars, typval_T *rettv)
6800{
6801 pos_T match_pos;
6802 int lnum = 0;
6803 int col = 0;
6804
6805 if (rettv_list_alloc(rettv) == FAIL)
6806 return;
6807
6808 if (searchpair_cmn(argvars, &match_pos) > 0)
6809 {
6810 lnum = match_pos.lnum;
6811 col = match_pos.col;
6812 }
6813
6814 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6815 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6816}
6817
6818/*
6819 * Search for a start/middle/end thing.
6820 * Used by searchpair(), see its documentation for the details.
6821 * Returns 0 or -1 for no match,
6822 */
6823 long
6824do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006825 char_u *spat, // start pattern
6826 char_u *mpat, // middle pattern
6827 char_u *epat, // end pattern
6828 int dir, // BACKWARD or FORWARD
6829 typval_T *skip, // skip expression
6830 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006832 linenr_T lnum_stop, // stop at this line if not zero
6833 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834{
6835 char_u *save_cpo;
6836 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6837 long retval = 0;
6838 pos_T pos;
6839 pos_T firstpos;
6840 pos_T foundpos;
6841 pos_T save_cursor;
6842 pos_T save_pos;
6843 int n;
6844 int r;
6845 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006846 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006847 int err;
6848 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006849#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006851#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006852
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006853 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006854 save_cpo = p_cpo;
6855 p_cpo = empty_option;
6856
6857#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006858 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006859 profile_setlimit(time_limit, &tm);
6860#endif
6861
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006862 // Make two search patterns: start/end (pat2, for in nested pairs) and
6863 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006864 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6865 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 if (pat2 == NULL || pat3 == NULL)
6867 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006868 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869 if (*mpat == NUL)
6870 STRCPY(pat3, pat2);
6871 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006872 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006873 spat, epat, mpat);
6874 if (flags & SP_START)
6875 options |= SEARCH_START;
6876
Bram Moolenaar48570482017-10-30 21:48:41 +01006877 if (skip != NULL)
6878 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006879 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006880 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6881 use_skip = skip->vval.v_string != NULL
6882 && *skip->vval.v_string != NUL;
6883 }
6884
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006885 save_cursor = curwin->w_cursor;
6886 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006887 CLEAR_POS(&firstpos);
6888 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006889 pat = pat3;
6890 for (;;)
6891 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006892 searchit_arg_T sia;
6893
Bram Moolenaara80faa82020-04-12 19:37:17 +02006894 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006895 sia.sa_stop_lnum = lnum_stop;
6896#ifdef FEAT_RELTIME
6897 sia.sa_tm = &tm;
6898#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006899 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006900 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006901 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006902 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006903 break;
6904
6905 if (firstpos.lnum == 0)
6906 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006907 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006909 // Found the same position again. Can happen with a pattern that
6910 // has "\zs" at the end and searching backwards. Advance one
6911 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006912 if (dir == BACKWARD)
6913 decl(&pos);
6914 else
6915 incl(&pos);
6916 }
6917 foundpos = pos;
6918
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006919 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920 options &= ~SEARCH_START;
6921
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006922 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006923 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006924 {
6925 save_pos = curwin->w_cursor;
6926 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006927 err = FALSE;
6928 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006929 curwin->w_cursor = save_pos;
6930 if (err)
6931 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006932 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006933 curwin->w_cursor = save_cursor;
6934 retval = -1;
6935 break;
6936 }
6937 if (r)
6938 continue;
6939 }
6940
6941 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6942 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006943 // Found end when searching backwards or start when searching
6944 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006945 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006946 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006947 }
6948 else
6949 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006950 // Found end when searching forward or start when searching
6951 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006952 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006953 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954 }
6955
6956 if (nest == 0)
6957 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006958 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959 if (flags & SP_RETCOUNT)
6960 ++retval;
6961 else
6962 retval = pos.lnum;
6963 if (flags & SP_SETPCMARK)
6964 setpcmark();
6965 curwin->w_cursor = pos;
6966 if (!(flags & SP_REPEAT))
6967 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006968 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006969 }
6970 }
6971
6972 if (match_pos != NULL)
6973 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006974 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 match_pos->lnum = curwin->w_cursor.lnum;
6976 match_pos->col = curwin->w_cursor.col + 1;
6977 }
6978
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006979 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006980 if ((flags & SP_NOMOVE) || retval == 0)
6981 curwin->w_cursor = save_cursor;
6982
6983theend:
6984 vim_free(pat2);
6985 vim_free(pat3);
6986 if (p_cpo == empty_option)
6987 p_cpo = save_cpo;
6988 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006989 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006990 free_string_option(save_cpo);
6991
6992 return retval;
6993}
6994
6995/*
6996 * "searchpos()" function
6997 */
6998 static void
6999f_searchpos(typval_T *argvars, typval_T *rettv)
7000{
7001 pos_T match_pos;
7002 int lnum = 0;
7003 int col = 0;
7004 int n;
7005 int flags = 0;
7006
7007 if (rettv_list_alloc(rettv) == FAIL)
7008 return;
7009
7010 n = search_cmn(argvars, &match_pos, &flags);
7011 if (n > 0)
7012 {
7013 lnum = match_pos.lnum;
7014 col = match_pos.col;
7015 }
7016
7017 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7018 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7019 if (flags & SP_SUBPAT)
7020 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7021}
7022
7023 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7025{
7026 dict_T *d;
7027 dictitem_T *di;
7028 char_u *csearch;
7029
7030 if (argvars[0].v_type != VAR_DICT)
7031 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007032 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007033 return;
7034 }
7035
7036 if ((d = argvars[0].vval.v_dict) != NULL)
7037 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007038 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039 if (csearch != NULL)
7040 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007041 if (enc_utf8)
7042 {
7043 int pcc[MAX_MCO];
7044 int c = utfc_ptr2char(csearch, pcc);
7045
7046 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7047 }
7048 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007049 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007050 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007051 }
7052
7053 di = dict_find(d, (char_u *)"forward", -1);
7054 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007055 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007056 ? FORWARD : BACKWARD);
7057
7058 di = dict_find(d, (char_u *)"until", -1);
7059 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007060 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007061 }
7062}
7063
7064/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007065 * "setenv()" function
7066 */
7067 static void
7068f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7069{
7070 char_u namebuf[NUMBUFLEN];
7071 char_u valbuf[NUMBUFLEN];
7072 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7073
7074 if (argvars[1].v_type == VAR_SPECIAL
7075 && argvars[1].vval.v_number == VVAL_NULL)
7076 vim_unsetenv(name);
7077 else
7078 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7079}
7080
7081/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007082 * "setfperm({fname}, {mode})" function
7083 */
7084 static void
7085f_setfperm(typval_T *argvars, typval_T *rettv)
7086{
7087 char_u *fname;
7088 char_u modebuf[NUMBUFLEN];
7089 char_u *mode_str;
7090 int i;
7091 int mask;
7092 int mode = 0;
7093
7094 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007095 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007096 if (fname == NULL)
7097 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007098 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007099 if (mode_str == NULL)
7100 return;
7101 if (STRLEN(mode_str) != 9)
7102 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007103 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007104 return;
7105 }
7106
7107 mask = 1;
7108 for (i = 8; i >= 0; --i)
7109 {
7110 if (mode_str[i] != '-')
7111 mode |= mask;
7112 mask = mask << 1;
7113 }
7114 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7115}
7116
7117/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 * "setpos()" function
7119 */
7120 static void
7121f_setpos(typval_T *argvars, typval_T *rettv)
7122{
7123 pos_T pos;
7124 int fnum;
7125 char_u *name;
7126 colnr_T curswant = -1;
7127
7128 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007129 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007130 if (name != NULL)
7131 {
7132 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7133 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007134 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 pos.col = 0;
7136 if (name[0] == '.' && name[1] == NUL)
7137 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007138 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007139 curwin->w_cursor = pos;
7140 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007141 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007142 curwin->w_curswant = curswant - 1;
7143 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007144 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007145 check_cursor();
7146 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007147 }
7148 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7149 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007150 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007151 if (setmark_pos(name[1], &pos, fnum) == OK)
7152 rettv->vval.v_number = 0;
7153 }
7154 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007155 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007156 }
7157 }
7158}
7159
7160/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007161 * "setreg()" function
7162 */
7163 static void
7164f_setreg(typval_T *argvars, typval_T *rettv)
7165{
7166 int regname;
7167 char_u *strregname;
7168 char_u *stropt;
7169 char_u *strval;
7170 int append;
7171 char_u yank_type;
7172 long block_len;
7173
7174 block_len = -1;
7175 yank_type = MAUTO;
7176 append = FALSE;
7177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007178 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007179 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007180
7181 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007182 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007183 regname = *strregname;
7184 if (regname == 0 || regname == '@')
7185 regname = '"';
7186
7187 if (argvars[2].v_type != VAR_UNKNOWN)
7188 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007189 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007190 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007191 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007192 for (; *stropt != NUL; ++stropt)
7193 switch (*stropt)
7194 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007195 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007196 append = TRUE;
7197 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007198 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007199 yank_type = MCHAR;
7200 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007201 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007202 yank_type = MLINE;
7203 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007204 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007205 yank_type = MBLOCK;
7206 if (VIM_ISDIGIT(stropt[1]))
7207 {
7208 ++stropt;
7209 block_len = getdigits(&stropt) - 1;
7210 --stropt;
7211 }
7212 break;
7213 }
7214 }
7215
7216 if (argvars[1].v_type == VAR_LIST)
7217 {
7218 char_u **lstval;
7219 char_u **allocval;
7220 char_u buf[NUMBUFLEN];
7221 char_u **curval;
7222 char_u **curallocval;
7223 list_T *ll = argvars[1].vval.v_list;
7224 listitem_T *li;
7225 int len;
7226
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007227 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 len = ll == NULL ? 0 : ll->lv_len;
7229
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007230 // First half: use for pointers to result lines; second half: use for
7231 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007232 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 if (lstval == NULL)
7234 return;
7235 curval = lstval;
7236 allocval = lstval + len + 2;
7237 curallocval = allocval;
7238
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007239 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007240 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007241 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007242 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007243 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007244 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007245 if (strval == NULL)
7246 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007247 if (strval == buf)
7248 {
7249 // Need to make a copy, next tv_get_string_buf_chk() will
7250 // overwrite the string.
7251 strval = vim_strsave(buf);
7252 if (strval == NULL)
7253 goto free_lstval;
7254 *curallocval++ = strval;
7255 }
7256 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007257 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258 }
7259 *curval++ = NULL;
7260
7261 write_reg_contents_lst(regname, lstval, -1,
7262 append, yank_type, block_len);
7263free_lstval:
7264 while (curallocval > allocval)
7265 vim_free(*--curallocval);
7266 vim_free(lstval);
7267 }
7268 else
7269 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007270 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007271 if (strval == NULL)
7272 return;
7273 write_reg_contents_ex(regname, strval, -1,
7274 append, yank_type, block_len);
7275 }
7276 rettv->vval.v_number = 0;
7277}
7278
7279/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007280 * "settagstack()" function
7281 */
7282 static void
7283f_settagstack(typval_T *argvars, typval_T *rettv)
7284{
7285 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7286 win_T *wp;
7287 dict_T *d;
7288 int action = 'r';
7289
7290 rettv->vval.v_number = -1;
7291
7292 // first argument: window number or id
7293 wp = find_win_by_nr_or_id(&argvars[0]);
7294 if (wp == NULL)
7295 return;
7296
7297 // second argument: dict with items to set in the tag stack
7298 if (argvars[1].v_type != VAR_DICT)
7299 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007300 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007301 return;
7302 }
7303 d = argvars[1].vval.v_dict;
7304 if (d == NULL)
7305 return;
7306
7307 // third argument: action - 'a' for append and 'r' for replace.
7308 // default is to replace the stack.
7309 if (argvars[2].v_type == VAR_UNKNOWN)
7310 action = 'r';
7311 else if (argvars[2].v_type == VAR_STRING)
7312 {
7313 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007314 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007315 if (actstr == NULL)
7316 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007317 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7318 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007319 action = *actstr;
7320 else
7321 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007322 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007323 return;
7324 }
7325 }
7326 else
7327 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007328 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007329 return;
7330 }
7331
7332 if (set_tagstack(wp, d, action) == OK)
7333 rettv->vval.v_number = 0;
7334}
7335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336#ifdef FEAT_CRYPT
7337/*
7338 * "sha256({string})" function
7339 */
7340 static void
7341f_sha256(typval_T *argvars, typval_T *rettv)
7342{
7343 char_u *p;
7344
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007345 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346 rettv->vval.v_string = vim_strsave(
7347 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7348 rettv->v_type = VAR_STRING;
7349}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007350#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351
7352/*
7353 * "shellescape({string})" function
7354 */
7355 static void
7356f_shellescape(typval_T *argvars, typval_T *rettv)
7357{
Bram Moolenaar20615522017-06-05 18:46:26 +02007358 int do_special = non_zero_arg(&argvars[1]);
7359
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007360 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007361 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362 rettv->v_type = VAR_STRING;
7363}
7364
7365/*
7366 * shiftwidth() function
7367 */
7368 static void
7369f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7370{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007371 rettv->vval.v_number = 0;
7372
7373 if (argvars[0].v_type != VAR_UNKNOWN)
7374 {
7375 long col;
7376
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007378 if (col < 0)
7379 return; // type error; errmsg already given
7380#ifdef FEAT_VARTABS
7381 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7382 return;
7383#endif
7384 }
7385
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386 rettv->vval.v_number = get_sw_value(curbuf);
7387}
7388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389#ifdef FEAT_FLOAT
7390/*
7391 * "sin()" function
7392 */
7393 static void
7394f_sin(typval_T *argvars, typval_T *rettv)
7395{
7396 float_T f = 0.0;
7397
7398 rettv->v_type = VAR_FLOAT;
7399 if (get_float_arg(argvars, &f) == OK)
7400 rettv->vval.v_float = sin(f);
7401 else
7402 rettv->vval.v_float = 0.0;
7403}
7404
7405/*
7406 * "sinh()" function
7407 */
7408 static void
7409f_sinh(typval_T *argvars, typval_T *rettv)
7410{
7411 float_T f = 0.0;
7412
7413 rettv->v_type = VAR_FLOAT;
7414 if (get_float_arg(argvars, &f) == OK)
7415 rettv->vval.v_float = sinh(f);
7416 else
7417 rettv->vval.v_float = 0.0;
7418}
7419#endif
7420
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007421/*
7422 * "soundfold({word})" function
7423 */
7424 static void
7425f_soundfold(typval_T *argvars, typval_T *rettv)
7426{
7427 char_u *s;
7428
7429 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007430 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431#ifdef FEAT_SPELL
7432 rettv->vval.v_string = eval_soundfold(s);
7433#else
7434 rettv->vval.v_string = vim_strsave(s);
7435#endif
7436}
7437
7438/*
7439 * "spellbadword()" function
7440 */
7441 static void
7442f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7443{
7444 char_u *word = (char_u *)"";
7445 hlf_T attr = HLF_COUNT;
7446 int len = 0;
7447
7448 if (rettv_list_alloc(rettv) == FAIL)
7449 return;
7450
7451#ifdef FEAT_SPELL
7452 if (argvars[0].v_type == VAR_UNKNOWN)
7453 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007454 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7456 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007457 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007459 curwin->w_set_curswant = TRUE;
7460 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007461 }
7462 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7463 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007464 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007465 int capcol = -1;
7466
7467 if (str != NULL)
7468 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007469 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470 while (*str != NUL)
7471 {
7472 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7473 if (attr != HLF_COUNT)
7474 {
7475 word = str;
7476 break;
7477 }
7478 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007479 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007480 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007481 }
7482 }
7483 }
7484#endif
7485
7486 list_append_string(rettv->vval.v_list, word, len);
7487 list_append_string(rettv->vval.v_list, (char_u *)(
7488 attr == HLF_SPB ? "bad" :
7489 attr == HLF_SPR ? "rare" :
7490 attr == HLF_SPL ? "local" :
7491 attr == HLF_SPC ? "caps" :
7492 ""), -1);
7493}
7494
7495/*
7496 * "spellsuggest()" function
7497 */
7498 static void
7499f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7500{
7501#ifdef FEAT_SPELL
7502 char_u *str;
7503 int typeerr = FALSE;
7504 int maxcount;
7505 garray_T ga;
7506 int i;
7507 listitem_T *li;
7508 int need_capital = FALSE;
7509#endif
7510
7511 if (rettv_list_alloc(rettv) == FAIL)
7512 return;
7513
7514#ifdef FEAT_SPELL
7515 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7516 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007517 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 if (argvars[1].v_type != VAR_UNKNOWN)
7519 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007520 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 if (maxcount <= 0)
7522 return;
7523 if (argvars[2].v_type != VAR_UNKNOWN)
7524 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007525 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 if (typeerr)
7527 return;
7528 }
7529 }
7530 else
7531 maxcount = 25;
7532
7533 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7534
7535 for (i = 0; i < ga.ga_len; ++i)
7536 {
7537 str = ((char_u **)ga.ga_data)[i];
7538
7539 li = listitem_alloc();
7540 if (li == NULL)
7541 vim_free(str);
7542 else
7543 {
7544 li->li_tv.v_type = VAR_STRING;
7545 li->li_tv.v_lock = 0;
7546 li->li_tv.vval.v_string = str;
7547 list_append(rettv->vval.v_list, li);
7548 }
7549 }
7550 ga_clear(&ga);
7551 }
7552#endif
7553}
7554
7555 static void
7556f_split(typval_T *argvars, typval_T *rettv)
7557{
7558 char_u *str;
7559 char_u *end;
7560 char_u *pat = NULL;
7561 regmatch_T regmatch;
7562 char_u patbuf[NUMBUFLEN];
7563 char_u *save_cpo;
7564 int match;
7565 colnr_T col = 0;
7566 int keepempty = FALSE;
7567 int typeerr = FALSE;
7568
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007569 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570 save_cpo = p_cpo;
7571 p_cpo = (char_u *)"";
7572
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007573 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007574 if (argvars[1].v_type != VAR_UNKNOWN)
7575 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 if (pat == NULL)
7578 typeerr = TRUE;
7579 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007580 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581 }
7582 if (pat == NULL || *pat == NUL)
7583 pat = (char_u *)"[\\x01- ]\\+";
7584
7585 if (rettv_list_alloc(rettv) == FAIL)
7586 return;
7587 if (typeerr)
7588 return;
7589
7590 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7591 if (regmatch.regprog != NULL)
7592 {
7593 regmatch.rm_ic = FALSE;
7594 while (*str != NUL || keepempty)
7595 {
7596 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007597 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007598 else
7599 match = vim_regexec_nl(&regmatch, str, col);
7600 if (match)
7601 end = regmatch.startp[0];
7602 else
7603 end = str + STRLEN(str);
7604 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7605 && *str != NUL && match && end < regmatch.endp[0]))
7606 {
7607 if (list_append_string(rettv->vval.v_list, str,
7608 (int)(end - str)) == FAIL)
7609 break;
7610 }
7611 if (!match)
7612 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007613 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007614 if (regmatch.endp[0] > str)
7615 col = 0;
7616 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007617 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007618 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619 str = regmatch.endp[0];
7620 }
7621
7622 vim_regfree(regmatch.regprog);
7623 }
7624
7625 p_cpo = save_cpo;
7626}
7627
7628#ifdef FEAT_FLOAT
7629/*
7630 * "sqrt()" function
7631 */
7632 static void
7633f_sqrt(typval_T *argvars, typval_T *rettv)
7634{
7635 float_T f = 0.0;
7636
7637 rettv->v_type = VAR_FLOAT;
7638 if (get_float_arg(argvars, &f) == OK)
7639 rettv->vval.v_float = sqrt(f);
7640 else
7641 rettv->vval.v_float = 0.0;
7642}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007643#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007644
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007645#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007646/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 * "str2float()" function
7648 */
7649 static void
7650f_str2float(typval_T *argvars, typval_T *rettv)
7651{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007652 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007653 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007654
Bram Moolenaar08243d22017-01-10 16:12:29 +01007655 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007656 p = skipwhite(p + 1);
7657 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007658 if (isneg)
7659 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007660 rettv->v_type = VAR_FLOAT;
7661}
7662#endif
7663
7664/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007665 * "str2list()" function
7666 */
7667 static void
7668f_str2list(typval_T *argvars, typval_T *rettv)
7669{
7670 char_u *p;
7671 int utf8 = FALSE;
7672
7673 if (rettv_list_alloc(rettv) == FAIL)
7674 return;
7675
7676 if (argvars[1].v_type != VAR_UNKNOWN)
7677 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7678
7679 p = tv_get_string(&argvars[0]);
7680
7681 if (has_mbyte || utf8)
7682 {
7683 int (*ptr2len)(char_u *);
7684 int (*ptr2char)(char_u *);
7685
7686 if (utf8 || enc_utf8)
7687 {
7688 ptr2len = utf_ptr2len;
7689 ptr2char = utf_ptr2char;
7690 }
7691 else
7692 {
7693 ptr2len = mb_ptr2len;
7694 ptr2char = mb_ptr2char;
7695 }
7696
7697 for ( ; *p != NUL; p += (*ptr2len)(p))
7698 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7699 }
7700 else
7701 for ( ; *p != NUL; ++p)
7702 list_append_number(rettv->vval.v_list, *p);
7703}
7704
7705/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007706 * "str2nr()" function
7707 */
7708 static void
7709f_str2nr(typval_T *argvars, typval_T *rettv)
7710{
7711 int base = 10;
7712 char_u *p;
7713 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007714 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007715 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716
7717 if (argvars[1].v_type != VAR_UNKNOWN)
7718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007719 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007720 if (base != 2 && base != 8 && base != 10 && base != 16)
7721 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007722 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007723 return;
7724 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007725 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7726 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727 }
7728
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007729 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007730 isneg = (*p == '-');
7731 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007732 p = skipwhite(p + 1);
7733 switch (base)
7734 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007735 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7736 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7737 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007739 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7740 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007741 if (isneg)
7742 rettv->vval.v_number = -n;
7743 else
7744 rettv->vval.v_number = n;
7745
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746}
7747
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748/*
7749 * "strgetchar()" function
7750 */
7751 static void
7752f_strgetchar(typval_T *argvars, typval_T *rettv)
7753{
7754 char_u *str;
7755 int len;
7756 int error = FALSE;
7757 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007758 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759
7760 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007761 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007762 if (str == NULL)
7763 return;
7764 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007765 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007766 if (error)
7767 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007768
Bram Moolenaar13505972019-01-24 15:04:48 +01007769 while (charidx >= 0 && byteidx < len)
7770 {
7771 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007772 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007773 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7774 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007775 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007776 --charidx;
7777 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007778 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007779}
7780
7781/*
7782 * "stridx()" function
7783 */
7784 static void
7785f_stridx(typval_T *argvars, typval_T *rettv)
7786{
7787 char_u buf[NUMBUFLEN];
7788 char_u *needle;
7789 char_u *haystack;
7790 char_u *save_haystack;
7791 char_u *pos;
7792 int start_idx;
7793
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007794 needle = tv_get_string_chk(&argvars[1]);
7795 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007796 rettv->vval.v_number = -1;
7797 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007798 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799
7800 if (argvars[2].v_type != VAR_UNKNOWN)
7801 {
7802 int error = FALSE;
7803
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007804 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805 if (error || start_idx >= (int)STRLEN(haystack))
7806 return;
7807 if (start_idx >= 0)
7808 haystack += start_idx;
7809 }
7810
7811 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7812 if (pos != NULL)
7813 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7814}
7815
7816/*
7817 * "string()" function
7818 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007819 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007820f_string(typval_T *argvars, typval_T *rettv)
7821{
7822 char_u *tofree;
7823 char_u numbuf[NUMBUFLEN];
7824
7825 rettv->v_type = VAR_STRING;
7826 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7827 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007828 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007829 if (rettv->vval.v_string != NULL && tofree == NULL)
7830 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7831}
7832
7833/*
7834 * "strlen()" function
7835 */
7836 static void
7837f_strlen(typval_T *argvars, typval_T *rettv)
7838{
7839 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007840 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841}
7842
7843/*
7844 * "strchars()" function
7845 */
7846 static void
7847f_strchars(typval_T *argvars, typval_T *rettv)
7848{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007849 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007850 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007851 varnumber_T len = 0;
7852 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853
7854 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007855 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007857 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858 else
7859 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007860 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7861 while (*s != NUL)
7862 {
7863 func_mb_ptr2char_adv(&s);
7864 ++len;
7865 }
7866 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867 }
7868}
7869
7870/*
7871 * "strdisplaywidth()" function
7872 */
7873 static void
7874f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7875{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007876 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007877 int col = 0;
7878
7879 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007880 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007881
7882 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7883}
7884
7885/*
7886 * "strwidth()" function
7887 */
7888 static void
7889f_strwidth(typval_T *argvars, typval_T *rettv)
7890{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007891 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892
Bram Moolenaar13505972019-01-24 15:04:48 +01007893 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007894}
7895
7896/*
7897 * "strcharpart()" function
7898 */
7899 static void
7900f_strcharpart(typval_T *argvars, typval_T *rettv)
7901{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007902 char_u *p;
7903 int nchar;
7904 int nbyte = 0;
7905 int charlen;
7906 int len = 0;
7907 int slen;
7908 int error = FALSE;
7909
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007910 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007911 slen = (int)STRLEN(p);
7912
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007913 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914 if (!error)
7915 {
7916 if (nchar > 0)
7917 while (nchar > 0 && nbyte < slen)
7918 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007919 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007920 --nchar;
7921 }
7922 else
7923 nbyte = nchar;
7924 if (argvars[2].v_type != VAR_UNKNOWN)
7925 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007926 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007927 while (charlen > 0 && nbyte + len < slen)
7928 {
7929 int off = nbyte + len;
7930
7931 if (off < 0)
7932 len += 1;
7933 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007934 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007935 --charlen;
7936 }
7937 }
7938 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007939 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007940 }
7941
7942 /*
7943 * Only return the overlap between the specified part and the actual
7944 * string.
7945 */
7946 if (nbyte < 0)
7947 {
7948 len += nbyte;
7949 nbyte = 0;
7950 }
7951 else if (nbyte > slen)
7952 nbyte = slen;
7953 if (len < 0)
7954 len = 0;
7955 else if (nbyte + len > slen)
7956 len = slen - nbyte;
7957
7958 rettv->v_type = VAR_STRING;
7959 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960}
7961
7962/*
7963 * "strpart()" function
7964 */
7965 static void
7966f_strpart(typval_T *argvars, typval_T *rettv)
7967{
7968 char_u *p;
7969 int n;
7970 int len;
7971 int slen;
7972 int error = FALSE;
7973
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007974 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007975 slen = (int)STRLEN(p);
7976
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007977 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007978 if (error)
7979 len = 0;
7980 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007981 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007982 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007983 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984
7985 /*
7986 * Only return the overlap between the specified part and the actual
7987 * string.
7988 */
7989 if (n < 0)
7990 {
7991 len += n;
7992 n = 0;
7993 }
7994 else if (n > slen)
7995 n = slen;
7996 if (len < 0)
7997 len = 0;
7998 else if (n + len > slen)
7999 len = slen - n;
8000
8001 rettv->v_type = VAR_STRING;
8002 rettv->vval.v_string = vim_strnsave(p + n, len);
8003}
8004
8005/*
8006 * "strridx()" function
8007 */
8008 static void
8009f_strridx(typval_T *argvars, typval_T *rettv)
8010{
8011 char_u buf[NUMBUFLEN];
8012 char_u *needle;
8013 char_u *haystack;
8014 char_u *rest;
8015 char_u *lastmatch = NULL;
8016 int haystack_len, end_idx;
8017
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008018 needle = tv_get_string_chk(&argvars[1]);
8019 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008020
8021 rettv->vval.v_number = -1;
8022 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008023 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008024
8025 haystack_len = (int)STRLEN(haystack);
8026 if (argvars[2].v_type != VAR_UNKNOWN)
8027 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008028 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008029 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008031 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008032 }
8033 else
8034 end_idx = haystack_len;
8035
8036 if (*needle == NUL)
8037 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008038 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039 lastmatch = haystack + end_idx;
8040 }
8041 else
8042 {
8043 for (rest = haystack; *rest != '\0'; ++rest)
8044 {
8045 rest = (char_u *)strstr((char *)rest, (char *)needle);
8046 if (rest == NULL || rest > haystack + end_idx)
8047 break;
8048 lastmatch = rest;
8049 }
8050 }
8051
8052 if (lastmatch == NULL)
8053 rettv->vval.v_number = -1;
8054 else
8055 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8056}
8057
8058/*
8059 * "strtrans()" function
8060 */
8061 static void
8062f_strtrans(typval_T *argvars, typval_T *rettv)
8063{
8064 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008065 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066}
8067
8068/*
8069 * "submatch()" function
8070 */
8071 static void
8072f_submatch(typval_T *argvars, typval_T *rettv)
8073{
8074 int error = FALSE;
8075 int no;
8076 int retList = 0;
8077
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008078 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 if (error)
8080 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008081 if (no < 0 || no >= NSUBEXP)
8082 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008083 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008084 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008085 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008087 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008088 if (error)
8089 return;
8090
8091 if (retList == 0)
8092 {
8093 rettv->v_type = VAR_STRING;
8094 rettv->vval.v_string = reg_submatch(no);
8095 }
8096 else
8097 {
8098 rettv->v_type = VAR_LIST;
8099 rettv->vval.v_list = reg_submatch_list(no);
8100 }
8101}
8102
8103/*
8104 * "substitute()" function
8105 */
8106 static void
8107f_substitute(typval_T *argvars, typval_T *rettv)
8108{
8109 char_u patbuf[NUMBUFLEN];
8110 char_u subbuf[NUMBUFLEN];
8111 char_u flagsbuf[NUMBUFLEN];
8112
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008113 char_u *str = tv_get_string_chk(&argvars[0]);
8114 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008115 char_u *sub = NULL;
8116 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008117 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008119 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8120 expr = &argvars[2];
8121 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008122 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008123
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008124 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008125 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8126 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008127 rettv->vval.v_string = NULL;
8128 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008129 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130}
8131
8132/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008133 * "swapinfo(swap_filename)" function
8134 */
8135 static void
8136f_swapinfo(typval_T *argvars, typval_T *rettv)
8137{
8138 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008139 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008140}
8141
8142/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008143 * "swapname(expr)" function
8144 */
8145 static void
8146f_swapname(typval_T *argvars, typval_T *rettv)
8147{
8148 buf_T *buf;
8149
8150 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008151 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008152 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8153 || buf->b_ml.ml_mfp->mf_fname == NULL)
8154 rettv->vval.v_string = NULL;
8155 else
8156 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8157}
8158
8159/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160 * "synID(lnum, col, trans)" function
8161 */
8162 static void
8163f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8164{
8165 int id = 0;
8166#ifdef FEAT_SYN_HL
8167 linenr_T lnum;
8168 colnr_T col;
8169 int trans;
8170 int transerr = FALSE;
8171
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008172 lnum = tv_get_lnum(argvars); // -1 on type error
8173 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008174 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008175
8176 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8177 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8178 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8179#endif
8180
8181 rettv->vval.v_number = id;
8182}
8183
8184/*
8185 * "synIDattr(id, what [, mode])" function
8186 */
8187 static void
8188f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8189{
8190 char_u *p = NULL;
8191#ifdef FEAT_SYN_HL
8192 int id;
8193 char_u *what;
8194 char_u *mode;
8195 char_u modebuf[NUMBUFLEN];
8196 int modec;
8197
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008198 id = (int)tv_get_number(&argvars[0]);
8199 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008200 if (argvars[2].v_type != VAR_UNKNOWN)
8201 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008202 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008203 modec = TOLOWER_ASC(mode[0]);
8204 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008205 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008206 }
8207 else
8208 {
8209#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8210 if (USE_24BIT)
8211 modec = 'g';
8212 else
8213#endif
8214 if (t_colors > 1)
8215 modec = 'c';
8216 else
8217 modec = 't';
8218 }
8219
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008220 switch (TOLOWER_ASC(what[0]))
8221 {
8222 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008223 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008224 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008225 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226 p = highlight_has_attr(id, HL_BOLD, modec);
8227 break;
8228
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008229 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008230 p = highlight_color(id, what, modec);
8231 break;
8232
8233 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008234 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008235 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008236 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008237 p = highlight_has_attr(id, HL_ITALIC, modec);
8238 break;
8239
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008240 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008241 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008242 break;
8243
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008244 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008245 p = highlight_has_attr(id, HL_INVERSE, modec);
8246 break;
8247
8248 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008249 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008250 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008251 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008252 else if (TOLOWER_ASC(what[1]) == 't' &&
8253 TOLOWER_ASC(what[2]) == 'r')
8254 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008255 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008256 p = highlight_has_attr(id, HL_STANDOUT, modec);
8257 break;
8258
8259 case 'u':
8260 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008261 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008262 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8263 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008264 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8266 break;
8267 }
8268
8269 if (p != NULL)
8270 p = vim_strsave(p);
8271#endif
8272 rettv->v_type = VAR_STRING;
8273 rettv->vval.v_string = p;
8274}
8275
8276/*
8277 * "synIDtrans(id)" function
8278 */
8279 static void
8280f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8281{
8282 int id;
8283
8284#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008285 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008286
8287 if (id > 0)
8288 id = syn_get_final_id(id);
8289 else
8290#endif
8291 id = 0;
8292
8293 rettv->vval.v_number = id;
8294}
8295
8296/*
8297 * "synconcealed(lnum, col)" function
8298 */
8299 static void
8300f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8301{
8302#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8303 linenr_T lnum;
8304 colnr_T col;
8305 int syntax_flags = 0;
8306 int cchar;
8307 int matchid = 0;
8308 char_u str[NUMBUFLEN];
8309#endif
8310
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008311 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008312
8313#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008314 lnum = tv_get_lnum(argvars); // -1 on type error
8315 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316
Bram Moolenaara80faa82020-04-12 19:37:17 +02008317 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008318
8319 if (rettv_list_alloc(rettv) != FAIL)
8320 {
8321 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8322 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8323 && curwin->w_p_cole > 0)
8324 {
8325 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8326 syntax_flags = get_syntax_info(&matchid);
8327
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008328 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8330 {
8331 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008332 if (cchar == NUL && curwin->w_p_cole == 1)
8333 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008334 if (cchar != NUL)
8335 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008336 if (has_mbyte)
8337 (*mb_char2bytes)(cchar, str);
8338 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339 str[0] = cchar;
8340 }
8341 }
8342 }
8343
8344 list_append_number(rettv->vval.v_list,
8345 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008346 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008347 list_append_string(rettv->vval.v_list, str, -1);
8348 list_append_number(rettv->vval.v_list, matchid);
8349 }
8350#endif
8351}
8352
8353/*
8354 * "synstack(lnum, col)" function
8355 */
8356 static void
8357f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8358{
8359#ifdef FEAT_SYN_HL
8360 linenr_T lnum;
8361 colnr_T col;
8362 int i;
8363 int id;
8364#endif
8365
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008366 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008367
8368#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008369 lnum = tv_get_lnum(argvars); // -1 on type error
8370 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371
8372 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8373 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8374 && rettv_list_alloc(rettv) != FAIL)
8375 {
8376 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8377 for (i = 0; ; ++i)
8378 {
8379 id = syn_get_stack_item(i);
8380 if (id < 0)
8381 break;
8382 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8383 break;
8384 }
8385 }
8386#endif
8387}
8388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008389/*
8390 * "tabpagebuflist()" function
8391 */
8392 static void
8393f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8394{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008395 tabpage_T *tp;
8396 win_T *wp = NULL;
8397
8398 if (argvars[0].v_type == VAR_UNKNOWN)
8399 wp = firstwin;
8400 else
8401 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008402 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008403 if (tp != NULL)
8404 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8405 }
8406 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8407 {
8408 for (; wp != NULL; wp = wp->w_next)
8409 if (list_append_number(rettv->vval.v_list,
8410 wp->w_buffer->b_fnum) == FAIL)
8411 break;
8412 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008413}
8414
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008415/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008416 * "tagfiles()" function
8417 */
8418 static void
8419f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8420{
8421 char_u *fname;
8422 tagname_T tn;
8423 int first;
8424
8425 if (rettv_list_alloc(rettv) == FAIL)
8426 return;
8427 fname = alloc(MAXPATHL);
8428 if (fname == NULL)
8429 return;
8430
8431 for (first = TRUE; ; first = FALSE)
8432 if (get_tagfname(&tn, first, fname) == FAIL
8433 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8434 break;
8435 tagname_free(&tn);
8436 vim_free(fname);
8437}
8438
8439/*
8440 * "taglist()" function
8441 */
8442 static void
8443f_taglist(typval_T *argvars, typval_T *rettv)
8444{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008445 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008446 char_u *tag_pattern;
8447
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008448 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008449
8450 rettv->vval.v_number = FALSE;
8451 if (*tag_pattern == NUL)
8452 return;
8453
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008454 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008455 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008456 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008457 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458}
8459
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008460#ifdef FEAT_FLOAT
8461/*
8462 * "tan()" function
8463 */
8464 static void
8465f_tan(typval_T *argvars, typval_T *rettv)
8466{
8467 float_T f = 0.0;
8468
8469 rettv->v_type = VAR_FLOAT;
8470 if (get_float_arg(argvars, &f) == OK)
8471 rettv->vval.v_float = tan(f);
8472 else
8473 rettv->vval.v_float = 0.0;
8474}
8475
8476/*
8477 * "tanh()" function
8478 */
8479 static void
8480f_tanh(typval_T *argvars, typval_T *rettv)
8481{
8482 float_T f = 0.0;
8483
8484 rettv->v_type = VAR_FLOAT;
8485 if (get_float_arg(argvars, &f) == OK)
8486 rettv->vval.v_float = tanh(f);
8487 else
8488 rettv->vval.v_float = 0.0;
8489}
8490#endif
8491
8492/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008493 * "tolower(string)" function
8494 */
8495 static void
8496f_tolower(typval_T *argvars, typval_T *rettv)
8497{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008498 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008499 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008500}
8501
8502/*
8503 * "toupper(string)" function
8504 */
8505 static void
8506f_toupper(typval_T *argvars, typval_T *rettv)
8507{
8508 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008509 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008510}
8511
8512/*
8513 * "tr(string, fromstr, tostr)" function
8514 */
8515 static void
8516f_tr(typval_T *argvars, typval_T *rettv)
8517{
8518 char_u *in_str;
8519 char_u *fromstr;
8520 char_u *tostr;
8521 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008522 int inlen;
8523 int fromlen;
8524 int tolen;
8525 int idx;
8526 char_u *cpstr;
8527 int cplen;
8528 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008529 char_u buf[NUMBUFLEN];
8530 char_u buf2[NUMBUFLEN];
8531 garray_T ga;
8532
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008533 in_str = tv_get_string(&argvars[0]);
8534 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8535 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008536
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008537 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008538 rettv->v_type = VAR_STRING;
8539 rettv->vval.v_string = NULL;
8540 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008541 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008542 ga_init2(&ga, (int)sizeof(char), 80);
8543
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008544 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008545 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008546 if (STRLEN(fromstr) != STRLEN(tostr))
8547 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008548error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008549 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008550 ga_clear(&ga);
8551 return;
8552 }
8553
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008554 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008555 while (*in_str != NUL)
8556 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008557 if (has_mbyte)
8558 {
8559 inlen = (*mb_ptr2len)(in_str);
8560 cpstr = in_str;
8561 cplen = inlen;
8562 idx = 0;
8563 for (p = fromstr; *p != NUL; p += fromlen)
8564 {
8565 fromlen = (*mb_ptr2len)(p);
8566 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8567 {
8568 for (p = tostr; *p != NUL; p += tolen)
8569 {
8570 tolen = (*mb_ptr2len)(p);
8571 if (idx-- == 0)
8572 {
8573 cplen = tolen;
8574 cpstr = p;
8575 break;
8576 }
8577 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008578 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008579 goto error;
8580 break;
8581 }
8582 ++idx;
8583 }
8584
8585 if (first && cpstr == in_str)
8586 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008587 // Check that fromstr and tostr have the same number of
8588 // (multi-byte) characters. Done only once when a character
8589 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008590 first = FALSE;
8591 for (p = tostr; *p != NUL; p += tolen)
8592 {
8593 tolen = (*mb_ptr2len)(p);
8594 --idx;
8595 }
8596 if (idx != 0)
8597 goto error;
8598 }
8599
8600 (void)ga_grow(&ga, cplen);
8601 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8602 ga.ga_len += cplen;
8603
8604 in_str += inlen;
8605 }
8606 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008608 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008609 p = vim_strchr(fromstr, *in_str);
8610 if (p != NULL)
8611 ga_append(&ga, tostr[p - fromstr]);
8612 else
8613 ga_append(&ga, *in_str);
8614 ++in_str;
8615 }
8616 }
8617
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008618 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008619 (void)ga_grow(&ga, 1);
8620 ga_append(&ga, NUL);
8621
8622 rettv->vval.v_string = ga.ga_data;
8623}
8624
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008625/*
8626 * "trim({expr})" function
8627 */
8628 static void
8629f_trim(typval_T *argvars, typval_T *rettv)
8630{
8631 char_u buf1[NUMBUFLEN];
8632 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008633 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008634 char_u *mask = NULL;
8635 char_u *tail;
8636 char_u *prev;
8637 char_u *p;
8638 int c1;
8639
8640 rettv->v_type = VAR_STRING;
8641 if (head == NULL)
8642 {
8643 rettv->vval.v_string = NULL;
8644 return;
8645 }
8646
8647 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008648 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008649
8650 while (*head != NUL)
8651 {
8652 c1 = PTR2CHAR(head);
8653 if (mask == NULL)
8654 {
8655 if (c1 > ' ' && c1 != 0xa0)
8656 break;
8657 }
8658 else
8659 {
8660 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8661 if (c1 == PTR2CHAR(p))
8662 break;
8663 if (*p == NUL)
8664 break;
8665 }
8666 MB_PTR_ADV(head);
8667 }
8668
8669 for (tail = head + STRLEN(head); tail > head; tail = prev)
8670 {
8671 prev = tail;
8672 MB_PTR_BACK(head, prev);
8673 c1 = PTR2CHAR(prev);
8674 if (mask == NULL)
8675 {
8676 if (c1 > ' ' && c1 != 0xa0)
8677 break;
8678 }
8679 else
8680 {
8681 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8682 if (c1 == PTR2CHAR(p))
8683 break;
8684 if (*p == NUL)
8685 break;
8686 }
8687 }
8688 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8689}
8690
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008691#ifdef FEAT_FLOAT
8692/*
8693 * "trunc({float})" function
8694 */
8695 static void
8696f_trunc(typval_T *argvars, typval_T *rettv)
8697{
8698 float_T f = 0.0;
8699
8700 rettv->v_type = VAR_FLOAT;
8701 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008702 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008703 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8704 else
8705 rettv->vval.v_float = 0.0;
8706}
8707#endif
8708
8709/*
8710 * "type(expr)" function
8711 */
8712 static void
8713f_type(typval_T *argvars, typval_T *rettv)
8714{
8715 int n = -1;
8716
8717 switch (argvars[0].v_type)
8718 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008719 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8720 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008722 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8723 case VAR_LIST: n = VAR_TYPE_LIST; break;
8724 case VAR_DICT: n = VAR_TYPE_DICT; break;
8725 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8726 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8727 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008728 case VAR_JOB: n = VAR_TYPE_JOB; break;
8729 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008730 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008731 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02008732 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008733 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008734 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008735 n = -1;
8736 break;
8737 }
8738 rettv->vval.v_number = n;
8739}
8740
8741/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008742 * "virtcol(string)" function
8743 */
8744 static void
8745f_virtcol(typval_T *argvars, typval_T *rettv)
8746{
8747 colnr_T vcol = 0;
8748 pos_T *fp;
8749 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008750 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008751
8752 fp = var2fpos(&argvars[0], FALSE, &fnum);
8753 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8754 && fnum == curbuf->b_fnum)
8755 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008756 // Limit the column to a valid value, getvvcol() doesn't check.
8757 if (fp->col < 0)
8758 fp->col = 0;
8759 else
8760 {
8761 len = (int)STRLEN(ml_get(fp->lnum));
8762 if (fp->col > len)
8763 fp->col = len;
8764 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008765 getvvcol(curwin, fp, NULL, NULL, &vcol);
8766 ++vcol;
8767 }
8768
8769 rettv->vval.v_number = vcol;
8770}
8771
8772/*
8773 * "visualmode()" function
8774 */
8775 static void
8776f_visualmode(typval_T *argvars, typval_T *rettv)
8777{
8778 char_u str[2];
8779
8780 rettv->v_type = VAR_STRING;
8781 str[0] = curbuf->b_visual_mode_eval;
8782 str[1] = NUL;
8783 rettv->vval.v_string = vim_strsave(str);
8784
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008785 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008786 if (non_zero_arg(&argvars[0]))
8787 curbuf->b_visual_mode_eval = NUL;
8788}
8789
8790/*
8791 * "wildmenumode()" function
8792 */
8793 static void
8794f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8795{
8796#ifdef FEAT_WILDMENU
8797 if (wild_menu_showing)
8798 rettv->vval.v_number = 1;
8799#endif
8800}
8801
8802/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008803 * "windowsversion()" function
8804 */
8805 static void
8806f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8807{
8808 rettv->v_type = VAR_STRING;
8809 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8810}
8811
8812/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008813 * "wordcount()" function
8814 */
8815 static void
8816f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8817{
8818 if (rettv_dict_alloc(rettv) == FAIL)
8819 return;
8820 cursor_pos_info(rettv->vval.v_dict);
8821}
8822
8823/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008824 * "xor(expr, expr)" function
8825 */
8826 static void
8827f_xor(typval_T *argvars, typval_T *rettv)
8828{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008829 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8830 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008831}
8832
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008833#endif // FEAT_EVAL