blob: 92d6c066714059e910e7ef61a3ac2b78af48906c [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},
Bram Moolenaarcfb4b472020-05-31 15:41:57 +0200582 {"getmarklist", 0, 1, 0, ret_list_dict_any, f_getmarklist},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100583 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
584 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
585 {"getpid", 0, 0, 0, ret_number, f_getpid},
586 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
587 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
588 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
589 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
590 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
591 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
592 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
593 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
594 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
595 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
596 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
597 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
598 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
599 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
600 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
601 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100602 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100603 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
604 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
605 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
606 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
607 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
608 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
609 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
610 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
611 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
612 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
613 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
614 {"hostname", 0, 0, 0, ret_string, f_hostname},
615 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
616 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
617 {"index", 2, 4, FEARG_1, ret_number, f_index},
618 {"input", 1, 3, FEARG_1, ret_string, f_input},
619 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
620 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
621 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
622 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
623 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
624 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
625 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
626 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
627 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100628 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100629 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100630 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100631 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100632 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
633 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
634 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
635 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
636 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
637 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100638 {"join", 1, 2, FEARG_1, ret_string, f_join},
639 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
640 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
641 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
642 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
643 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
644 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
645 {"len", 1, 1, FEARG_1, ret_number, f_len},
646 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
647 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
648 {"line", 1, 2, FEARG_1, ret_number, f_line},
649 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
650 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
651 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
652 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
653 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
654 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
655 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100656 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
657 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
658 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200659#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100660 f_luaeval
661#else
662 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200663#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100664 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100665 {"map", 2, 2, FEARG_1, ret_any, f_map},
666 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
667 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200668 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100669 {"match", 2, 4, FEARG_1, ret_any, f_match},
670 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
671 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
672 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
673 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
674 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
675 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
676 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
677 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
678 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100679 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100680#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100681 f_menu_info
682#else
683 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100684#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100685 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100686 {"min", 1, 1, FEARG_1, ret_any, f_min},
687 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
688 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100689 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200690#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100691 f_mzeval
692#else
693 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200694#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100695 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100696 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
697 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
698 {"or", 2, 2, FEARG_1, ret_number, f_or},
699 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100700 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200701#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100702 f_perleval
703#else
704 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200705#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100706 },
707 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
708 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200709 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100710 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
711 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
712 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
713 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)},
714 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)},
715 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
716 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
717 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
718 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
719 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200720 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100721 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
722 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
723 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
724 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
725 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
726 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
727 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
728 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100729 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
730 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100731 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
732 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
733 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
734 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
735 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
736 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
737 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
738 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
739 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
740 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
741 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
742 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
743 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100744 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
745 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100746 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100748 f_py3eval
749#else
750 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200751#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100752 },
753 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200754#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100755 f_pyeval
756#else
757 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200758#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100759 },
760 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100761#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100762 f_pyxeval
763#else
764 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100765#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100766 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100767 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
768 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
769 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
770 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
771 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
772 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
773 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100774 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100775 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
776 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
777 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
778 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
779 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
780 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
781 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
782 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
783 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
784 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
785 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
786 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100787 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
788 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100789#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100790 f_rubyeval
791#else
792 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100793#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100794 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100795 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
796 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
797 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
798 {"screencol", 0, 0, 0, ret_number, f_screencol},
799 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
800 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
801 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
802 {"search", 1, 4, FEARG_1, ret_number, f_search},
803 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
804 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
805 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
806 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
807 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
808 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
809 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
810 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
811 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
812 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
813 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
814 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
815 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
816 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
817 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
818 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
819 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
820 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
821 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
822 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
823 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
824 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100825 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200826#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100827 f_sha256
828#else
829 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100831 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100832 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
833 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100834 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
835 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
836 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
837 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
838 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
839 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
840 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
841 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
842 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200843 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100844 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
845 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100846 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100847 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
848 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
849 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
850 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100851 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
852 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
853 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
854 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100855 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100856 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
857 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100858 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100859 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
860 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
861 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
862 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
863 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100864 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200865#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100866 f_strftime
867#else
868 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200869#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100870 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100871 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
872 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
873 {"string", 1, 1, FEARG_1, ret_string, f_string},
874 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
875 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100876 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100877#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100878 f_strptime
879#else
880 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100881#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100882 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100883 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
884 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
885 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
886 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
887 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
888 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
889 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
890 {"synID", 3, 3, 0, ret_number, f_synID},
891 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
892 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
893 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
894 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
895 {"system", 1, 2, FEARG_1, ret_string, f_system},
896 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
897 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
898 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
899 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
900 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
901 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100902 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
903 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100904 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100905 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
906 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
907 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
908 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
909 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100910#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100911 f_term_getansicolors
912#else
913 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200914#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100915 },
916 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
917 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
918 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
919 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
920 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
921 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
922 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
923 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
924 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
925 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
926 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
927 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
928 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100929#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100930 f_term_setansicolors
931#else
932 NULL
933#endif
934 },
935 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
936 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
937 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
938 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
939 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
940 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100941 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
942 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
943 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
944 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
945 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
946 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
947 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
948 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100949 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100950 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200951 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100952 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100953 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200954 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100955 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
956 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
957 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
958 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100959 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +0200960#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +0100961 f_test_scrollbar
962#else
963 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +0200964#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100965 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100966 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
967 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
968 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
969 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
970 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100971 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
972 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
973 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
974 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
975 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100976 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
977 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
978 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +0200979 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100980 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100981 {"type", 1, 1, FEARG_1, ret_number, f_type},
982 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
983 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
984 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
985 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
986 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
987 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
988 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
989 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
990 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
991 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
992 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
993 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
994 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
995 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
996 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
997 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
998 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
999 {"wincol", 0, 0, 0, ret_number, f_wincol},
1000 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1001 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1002 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1003 {"winline", 0, 0, 0, ret_number, f_winline},
1004 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1005 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1006 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1007 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1008 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1009 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1010 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1011 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001012};
1013
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014/*
1015 * Function given to ExpandGeneric() to obtain the list of internal
1016 * or user defined function names.
1017 */
1018 char_u *
1019get_function_name(expand_T *xp, int idx)
1020{
1021 static int intidx = -1;
1022 char_u *name;
1023
1024 if (idx == 0)
1025 intidx = -1;
1026 if (intidx < 0)
1027 {
1028 name = get_user_func_name(xp, idx);
1029 if (name != NULL)
1030 return name;
1031 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001032 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001033 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001034 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001035 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001036 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001037 STRCAT(IObuff, ")");
1038 return IObuff;
1039 }
1040
1041 return NULL;
1042}
1043
1044/*
1045 * Function given to ExpandGeneric() to obtain the list of internal or
1046 * user defined variable or function names.
1047 */
1048 char_u *
1049get_expr_name(expand_T *xp, int idx)
1050{
1051 static int intidx = -1;
1052 char_u *name;
1053
1054 if (idx == 0)
1055 intidx = -1;
1056 if (intidx < 0)
1057 {
1058 name = get_function_name(xp, idx);
1059 if (name != NULL)
1060 return name;
1061 }
1062 return get_user_var_name(xp, ++intidx);
1063}
1064
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001065/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001066 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001067 * Return index, or -1 if not found or "implemented" is TRUE and the function
1068 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001069 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001070 static int
1071find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001072{
1073 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001074 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001075 int cmp;
1076 int x;
1077
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001078 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001079
1080 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001081 while (first <= last)
1082 {
1083 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001084 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001085 if (cmp < 0)
1086 last = x - 1;
1087 else if (cmp > 0)
1088 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001089 else if (implemented && global_functions[x].f_func == NULL)
1090 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001091 else
1092 return x;
1093 }
1094 return -1;
1095}
1096
Bram Moolenaar15c47602020-03-26 22:16:48 +01001097/*
1098 * Find internal function "name" in table "global_functions".
1099 * Return index, or -1 if not found or the function is not implemented.
1100 */
1101 int
1102find_internal_func(char_u *name)
1103{
1104 return find_internal_func_opt(name, TRUE);
1105}
1106
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001107 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001108has_internal_func(char_u *name)
1109{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001110 return find_internal_func_opt(name, TRUE) >= 0;
1111}
1112
1113 static int
1114has_internal_func_name(char_u *name)
1115{
1116 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001117}
1118
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001119 char *
1120internal_func_name(int idx)
1121{
1122 return global_functions[idx].f_name;
1123}
1124
1125 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001126internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001127{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001128 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001129}
1130
1131/*
1132 * Check the argument count to use for internal function "idx".
1133 * Returns OK or FAIL;
1134 */
1135 int
1136check_internal_func(int idx, int argcount)
1137{
1138 int res;
1139 char *name;
1140
1141 if (argcount < global_functions[idx].f_min_argc)
1142 res = FCERR_TOOFEW;
1143 else if (argcount > global_functions[idx].f_max_argc)
1144 res = FCERR_TOOMANY;
1145 else
1146 return OK;
1147
1148 name = internal_func_name(idx);
1149 if (res == FCERR_TOOMANY)
1150 semsg(_(e_toomanyarg), name);
1151 else
1152 semsg(_(e_toofewarg), name);
1153 return FAIL;
1154}
1155
Bram Moolenaarac92e252019-08-03 21:58:38 +02001156 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001157call_internal_func(
1158 char_u *name,
1159 int argcount,
1160 typval_T *argvars,
1161 typval_T *rettv)
1162{
1163 int i;
1164
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001165 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001166 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001167 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001168 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001169 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001170 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001171 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001172 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001173 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001174 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001175}
1176
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001177 void
1178call_internal_func_by_idx(
1179 int idx,
1180 typval_T *argvars,
1181 typval_T *rettv)
1182{
1183 global_functions[idx].f_func(argvars, rettv);
1184}
1185
Bram Moolenaarac92e252019-08-03 21:58:38 +02001186/*
1187 * Invoke a method for base->method().
1188 */
1189 int
1190call_internal_method(
1191 char_u *name,
1192 int argcount,
1193 typval_T *argvars,
1194 typval_T *rettv,
1195 typval_T *basetv)
1196{
1197 int i;
1198 int fi;
1199 typval_T argv[MAX_FUNC_ARGS + 1];
1200
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001201 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001202 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001203 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001204 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001205 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001206 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001207 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001208 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001209 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001210
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001211 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001212 {
1213 // base value goes last
1214 for (i = 0; i < argcount; ++i)
1215 argv[i] = argvars[i];
1216 argv[argcount] = *basetv;
1217 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001218 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001219 {
1220 // base value goes second
1221 argv[0] = argvars[0];
1222 argv[1] = *basetv;
1223 for (i = 1; i < argcount; ++i)
1224 argv[i + 1] = argvars[i];
1225 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001226 else if (global_functions[fi].f_argtype == FEARG_3)
1227 {
1228 // base value goes third
1229 argv[0] = argvars[0];
1230 argv[1] = argvars[1];
1231 argv[2] = *basetv;
1232 for (i = 2; i < argcount; ++i)
1233 argv[i + 1] = argvars[i];
1234 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001235 else if (global_functions[fi].f_argtype == FEARG_4)
1236 {
1237 // base value goes fourth
1238 argv[0] = argvars[0];
1239 argv[1] = argvars[1];
1240 argv[2] = argvars[2];
1241 argv[3] = *basetv;
1242 for (i = 3; i < argcount; ++i)
1243 argv[i + 1] = argvars[i];
1244 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001245 else
1246 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001247 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001248 argv[0] = *basetv;
1249 for (i = 0; i < argcount; ++i)
1250 argv[i + 1] = argvars[i];
1251 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001252 argv[argcount + 1].v_type = VAR_UNKNOWN;
1253
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001254 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001255 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001256}
1257
1258/*
1259 * Return TRUE for a non-zero Number and a non-empty String.
1260 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001261 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001262non_zero_arg(typval_T *argvars)
1263{
1264 return ((argvars[0].v_type == VAR_NUMBER
1265 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001266 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001267 && argvars[0].vval.v_number == VVAL_TRUE)
1268 || (argvars[0].v_type == VAR_STRING
1269 && argvars[0].vval.v_string != NULL
1270 && *argvars[0].vval.v_string != NUL));
1271}
1272
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001273#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001274/*
1275 * Get the float value of "argvars[0]" into "f".
1276 * Returns FAIL when the argument is not a Number or Float.
1277 */
1278 static int
1279get_float_arg(typval_T *argvars, float_T *f)
1280{
1281 if (argvars[0].v_type == VAR_FLOAT)
1282 {
1283 *f = argvars[0].vval.v_float;
1284 return OK;
1285 }
1286 if (argvars[0].v_type == VAR_NUMBER)
1287 {
1288 *f = (float_T)argvars[0].vval.v_number;
1289 return OK;
1290 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001291 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001292 return FAIL;
1293}
1294
1295/*
1296 * "abs(expr)" function
1297 */
1298 static void
1299f_abs(typval_T *argvars, typval_T *rettv)
1300{
1301 if (argvars[0].v_type == VAR_FLOAT)
1302 {
1303 rettv->v_type = VAR_FLOAT;
1304 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1305 }
1306 else
1307 {
1308 varnumber_T n;
1309 int error = FALSE;
1310
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001311 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001312 if (error)
1313 rettv->vval.v_number = -1;
1314 else if (n > 0)
1315 rettv->vval.v_number = n;
1316 else
1317 rettv->vval.v_number = -n;
1318 }
1319}
1320
1321/*
1322 * "acos()" function
1323 */
1324 static void
1325f_acos(typval_T *argvars, typval_T *rettv)
1326{
1327 float_T f = 0.0;
1328
1329 rettv->v_type = VAR_FLOAT;
1330 if (get_float_arg(argvars, &f) == OK)
1331 rettv->vval.v_float = acos(f);
1332 else
1333 rettv->vval.v_float = 0.0;
1334}
1335#endif
1336
1337/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001338 * "and(expr, expr)" function
1339 */
1340 static void
1341f_and(typval_T *argvars, typval_T *rettv)
1342{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001343 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1344 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001345}
1346
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347#ifdef FEAT_FLOAT
1348/*
1349 * "asin()" function
1350 */
1351 static void
1352f_asin(typval_T *argvars, typval_T *rettv)
1353{
1354 float_T f = 0.0;
1355
1356 rettv->v_type = VAR_FLOAT;
1357 if (get_float_arg(argvars, &f) == OK)
1358 rettv->vval.v_float = asin(f);
1359 else
1360 rettv->vval.v_float = 0.0;
1361}
1362
1363/*
1364 * "atan()" function
1365 */
1366 static void
1367f_atan(typval_T *argvars, typval_T *rettv)
1368{
1369 float_T f = 0.0;
1370
1371 rettv->v_type = VAR_FLOAT;
1372 if (get_float_arg(argvars, &f) == OK)
1373 rettv->vval.v_float = atan(f);
1374 else
1375 rettv->vval.v_float = 0.0;
1376}
1377
1378/*
1379 * "atan2()" function
1380 */
1381 static void
1382f_atan2(typval_T *argvars, typval_T *rettv)
1383{
1384 float_T fx = 0.0, fy = 0.0;
1385
1386 rettv->v_type = VAR_FLOAT;
1387 if (get_float_arg(argvars, &fx) == OK
1388 && get_float_arg(&argvars[1], &fy) == OK)
1389 rettv->vval.v_float = atan2(fx, fy);
1390 else
1391 rettv->vval.v_float = 0.0;
1392}
1393#endif
1394
1395/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001396 * "balloon_show()" function
1397 */
1398#ifdef FEAT_BEVAL
1399 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001400f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1401{
1402 rettv->v_type = VAR_STRING;
1403 if (balloonEval != NULL)
1404 {
1405 if (balloonEval->msg == NULL)
1406 rettv->vval.v_string = NULL;
1407 else
1408 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1409 }
1410}
1411
1412 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001413f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1414{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001415 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001416 {
1417 if (argvars[0].v_type == VAR_LIST
1418# ifdef FEAT_GUI
1419 && !gui.in_use
1420# endif
1421 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001422 {
1423 list_T *l = argvars[0].vval.v_list;
1424
1425 // empty list removes the balloon
1426 post_balloon(balloonEval, NULL,
1427 l == NULL || l->lv_len == 0 ? NULL : l);
1428 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001429 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001430 {
1431 char_u *mesg = tv_get_string_chk(&argvars[0]);
1432
1433 if (mesg != NULL)
1434 // empty string removes the balloon
1435 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1436 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001437 }
1438}
1439
Bram Moolenaar669a8282017-11-19 20:13:05 +01001440# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001441 static void
1442f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1443{
1444 if (rettv_list_alloc(rettv) == OK)
1445 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001446 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001447
1448 if (msg != NULL)
1449 {
1450 pumitem_T *array;
1451 int size = split_message(msg, &array);
1452 int i;
1453
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001454 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001455 for (i = 1; i < size - 1; ++i)
1456 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001457 while (size > 0)
1458 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001459 vim_free(array);
1460 }
1461 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001462}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001463# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001464#endif
1465
1466/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001467 * Get the buffer from "arg" and give an error and return NULL if it is not
1468 * valid.
1469 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001470 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001471get_buf_arg(typval_T *arg)
1472{
1473 buf_T *buf;
1474
1475 ++emsg_off;
1476 buf = tv_get_buf(arg, FALSE);
1477 --emsg_off;
1478 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001479 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001480 return buf;
1481}
1482
1483/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001484 * "byte2line(byte)" function
1485 */
1486 static void
1487f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1488{
1489#ifndef FEAT_BYTEOFF
1490 rettv->vval.v_number = -1;
1491#else
1492 long boff = 0;
1493
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001494 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495 if (boff < 0)
1496 rettv->vval.v_number = -1;
1497 else
1498 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1499 (linenr_T)0, &boff);
1500#endif
1501}
1502
1503 static void
1504byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1505{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001507 char_u *str;
1508 varnumber_T idx;
1509
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001510 str = tv_get_string_chk(&argvars[0]);
1511 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512 rettv->vval.v_number = -1;
1513 if (str == NULL || idx < 0)
1514 return;
1515
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001516 t = str;
1517 for ( ; idx > 0; idx--)
1518 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001519 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001520 return;
1521 if (enc_utf8 && comp)
1522 t += utf_ptr2len(t);
1523 else
1524 t += (*mb_ptr2len)(t);
1525 }
1526 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001527}
1528
1529/*
1530 * "byteidx()" function
1531 */
1532 static void
1533f_byteidx(typval_T *argvars, typval_T *rettv)
1534{
1535 byteidx(argvars, rettv, FALSE);
1536}
1537
1538/*
1539 * "byteidxcomp()" function
1540 */
1541 static void
1542f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1543{
1544 byteidx(argvars, rettv, TRUE);
1545}
1546
1547/*
1548 * "call(func, arglist [, dict])" function
1549 */
1550 static void
1551f_call(typval_T *argvars, typval_T *rettv)
1552{
1553 char_u *func;
1554 partial_T *partial = NULL;
1555 dict_T *selfdict = NULL;
1556
1557 if (argvars[1].v_type != VAR_LIST)
1558 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001559 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001560 return;
1561 }
1562 if (argvars[1].vval.v_list == NULL)
1563 return;
1564
1565 if (argvars[0].v_type == VAR_FUNC)
1566 func = argvars[0].vval.v_string;
1567 else if (argvars[0].v_type == VAR_PARTIAL)
1568 {
1569 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001570 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001571 }
1572 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001573 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001574 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001575 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576
1577 if (argvars[2].v_type != VAR_UNKNOWN)
1578 {
1579 if (argvars[2].v_type != VAR_DICT)
1580 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001581 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001582 return;
1583 }
1584 selfdict = argvars[2].vval.v_dict;
1585 }
1586
1587 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1588}
1589
1590#ifdef FEAT_FLOAT
1591/*
1592 * "ceil({float})" function
1593 */
1594 static void
1595f_ceil(typval_T *argvars, typval_T *rettv)
1596{
1597 float_T f = 0.0;
1598
1599 rettv->v_type = VAR_FLOAT;
1600 if (get_float_arg(argvars, &f) == OK)
1601 rettv->vval.v_float = ceil(f);
1602 else
1603 rettv->vval.v_float = 0.0;
1604}
1605#endif
1606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607/*
1608 * "changenr()" function
1609 */
1610 static void
1611f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1612{
1613 rettv->vval.v_number = curbuf->b_u_seq_cur;
1614}
1615
1616/*
1617 * "char2nr(string)" function
1618 */
1619 static void
1620f_char2nr(typval_T *argvars, typval_T *rettv)
1621{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622 if (has_mbyte)
1623 {
1624 int utf8 = 0;
1625
1626 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001627 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001628
1629 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001630 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001631 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001632 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001633 }
1634 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001635 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001636}
1637
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001638 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001639get_optional_window(typval_T *argvars, int idx)
1640{
1641 win_T *win = curwin;
1642
1643 if (argvars[idx].v_type != VAR_UNKNOWN)
1644 {
1645 win = find_win_by_nr_or_id(&argvars[idx]);
1646 if (win == NULL)
1647 {
1648 emsg(_(e_invalwindow));
1649 return NULL;
1650 }
1651 }
1652 return win;
1653}
1654
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001655/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001656 * "col(string)" function
1657 */
1658 static void
1659f_col(typval_T *argvars, typval_T *rettv)
1660{
1661 colnr_T col = 0;
1662 pos_T *fp;
1663 int fnum = curbuf->b_fnum;
1664
1665 fp = var2fpos(&argvars[0], FALSE, &fnum);
1666 if (fp != NULL && fnum == curbuf->b_fnum)
1667 {
1668 if (fp->col == MAXCOL)
1669 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001670 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001671 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1672 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1673 else
1674 col = MAXCOL;
1675 }
1676 else
1677 {
1678 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001679 // col(".") when the cursor is on the NUL at the end of the line
1680 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 if (virtual_active() && fp == &curwin->w_cursor)
1682 {
1683 char_u *p = ml_get_cursor();
1684
1685 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1686 curwin->w_virtcol - curwin->w_cursor.coladd))
1687 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 int l;
1689
1690 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1691 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692 }
1693 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001694 }
1695 }
1696 rettv->vval.v_number = col;
1697}
1698
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001699/*
1700 * "confirm(message, buttons[, default [, type]])" function
1701 */
1702 static void
1703f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1704{
1705#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1706 char_u *message;
1707 char_u *buttons = NULL;
1708 char_u buf[NUMBUFLEN];
1709 char_u buf2[NUMBUFLEN];
1710 int def = 1;
1711 int type = VIM_GENERIC;
1712 char_u *typestr;
1713 int error = FALSE;
1714
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001715 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 if (message == NULL)
1717 error = TRUE;
1718 if (argvars[1].v_type != VAR_UNKNOWN)
1719 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001720 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001721 if (buttons == NULL)
1722 error = TRUE;
1723 if (argvars[2].v_type != VAR_UNKNOWN)
1724 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001725 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001726 if (argvars[3].v_type != VAR_UNKNOWN)
1727 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001728 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001729 if (typestr == NULL)
1730 error = TRUE;
1731 else
1732 {
1733 switch (TOUPPER_ASC(*typestr))
1734 {
1735 case 'E': type = VIM_ERROR; break;
1736 case 'Q': type = VIM_QUESTION; break;
1737 case 'I': type = VIM_INFO; break;
1738 case 'W': type = VIM_WARNING; break;
1739 case 'G': type = VIM_GENERIC; break;
1740 }
1741 }
1742 }
1743 }
1744 }
1745
1746 if (buttons == NULL || *buttons == NUL)
1747 buttons = (char_u *)_("&Ok");
1748
1749 if (!error)
1750 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1751 def, NULL, FALSE);
1752#endif
1753}
1754
1755/*
1756 * "copy()" function
1757 */
1758 static void
1759f_copy(typval_T *argvars, typval_T *rettv)
1760{
1761 item_copy(&argvars[0], rettv, FALSE, 0);
1762}
1763
1764#ifdef FEAT_FLOAT
1765/*
1766 * "cos()" function
1767 */
1768 static void
1769f_cos(typval_T *argvars, typval_T *rettv)
1770{
1771 float_T f = 0.0;
1772
1773 rettv->v_type = VAR_FLOAT;
1774 if (get_float_arg(argvars, &f) == OK)
1775 rettv->vval.v_float = cos(f);
1776 else
1777 rettv->vval.v_float = 0.0;
1778}
1779
1780/*
1781 * "cosh()" function
1782 */
1783 static void
1784f_cosh(typval_T *argvars, typval_T *rettv)
1785{
1786 float_T f = 0.0;
1787
1788 rettv->v_type = VAR_FLOAT;
1789 if (get_float_arg(argvars, &f) == OK)
1790 rettv->vval.v_float = cosh(f);
1791 else
1792 rettv->vval.v_float = 0.0;
1793}
1794#endif
1795
1796/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001797 * "cursor(lnum, col)" function, or
1798 * "cursor(list)"
1799 *
1800 * Moves the cursor to the specified line and column.
1801 * Returns 0 when the position could be set, -1 otherwise.
1802 */
1803 static void
1804f_cursor(typval_T *argvars, typval_T *rettv)
1805{
1806 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001807 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001808 int set_curswant = TRUE;
1809
1810 rettv->vval.v_number = -1;
1811 if (argvars[1].v_type == VAR_UNKNOWN)
1812 {
1813 pos_T pos;
1814 colnr_T curswant = -1;
1815
1816 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1817 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001818 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001819 return;
1820 }
1821 line = pos.lnum;
1822 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001823 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001824 if (curswant >= 0)
1825 {
1826 curwin->w_curswant = curswant - 1;
1827 set_curswant = FALSE;
1828 }
1829 }
1830 else
1831 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001832 line = tv_get_lnum(argvars);
1833 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001835 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001836 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001837 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001838 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 if (line > 0)
1840 curwin->w_cursor.lnum = line;
1841 if (col > 0)
1842 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001843 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001845 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001847 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001848 if (has_mbyte)
1849 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001850
1851 curwin->w_set_curswant = set_curswant;
1852 rettv->vval.v_number = 0;
1853}
1854
Bram Moolenaar4f974752019-02-17 17:44:42 +01001855#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001856/*
1857 * "debugbreak()" function
1858 */
1859 static void
1860f_debugbreak(typval_T *argvars, typval_T *rettv)
1861{
1862 int pid;
1863
1864 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001865 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001866 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001867 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001868 else
1869 {
1870 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1871
1872 if (hProcess != NULL)
1873 {
1874 DebugBreakProcess(hProcess);
1875 CloseHandle(hProcess);
1876 rettv->vval.v_number = OK;
1877 }
1878 }
1879}
1880#endif
1881
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001882/*
1883 * "deepcopy()" function
1884 */
1885 static void
1886f_deepcopy(typval_T *argvars, typval_T *rettv)
1887{
1888 int noref = 0;
1889 int copyID;
1890
1891 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001892 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001893 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001894 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001895 else
1896 {
1897 copyID = get_copyID();
1898 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1899 }
1900}
1901
1902/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001903 * "did_filetype()" function
1904 */
1905 static void
1906f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1907{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001909}
1910
1911/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001912 * "echoraw({expr})" function
1913 */
1914 static void
1915f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1916{
1917 char_u *str = tv_get_string_chk(&argvars[0]);
1918
1919 if (str != NULL && *str != NUL)
1920 {
1921 out_str(str);
1922 out_flush();
1923 }
1924}
1925
1926/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927 * "empty({expr})" function
1928 */
1929 static void
1930f_empty(typval_T *argvars, typval_T *rettv)
1931{
1932 int n = FALSE;
1933
1934 switch (argvars[0].v_type)
1935 {
1936 case VAR_STRING:
1937 case VAR_FUNC:
1938 n = argvars[0].vval.v_string == NULL
1939 || *argvars[0].vval.v_string == NUL;
1940 break;
1941 case VAR_PARTIAL:
1942 n = FALSE;
1943 break;
1944 case VAR_NUMBER:
1945 n = argvars[0].vval.v_number == 0;
1946 break;
1947 case VAR_FLOAT:
1948#ifdef FEAT_FLOAT
1949 n = argvars[0].vval.v_float == 0.0;
1950 break;
1951#endif
1952 case VAR_LIST:
1953 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001954 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001955 break;
1956 case VAR_DICT:
1957 n = argvars[0].vval.v_dict == NULL
1958 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1959 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001960 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001961 case VAR_SPECIAL:
1962 n = argvars[0].vval.v_number != VVAL_TRUE;
1963 break;
1964
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001965 case VAR_BLOB:
1966 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001967 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1968 break;
1969
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001970 case VAR_JOB:
1971#ifdef FEAT_JOB_CHANNEL
1972 n = argvars[0].vval.v_job == NULL
1973 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1974 break;
1975#endif
1976 case VAR_CHANNEL:
1977#ifdef FEAT_JOB_CHANNEL
1978 n = argvars[0].vval.v_channel == NULL
1979 || !channel_is_open(argvars[0].vval.v_channel);
1980 break;
1981#endif
1982 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02001983 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001984 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001985 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986 n = TRUE;
1987 break;
1988 }
1989
1990 rettv->vval.v_number = n;
1991}
1992
1993/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001994 * "environ()" function
1995 */
1996 static void
1997f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1998{
1999#if !defined(AMIGA)
2000 int i = 0;
2001 char_u *entry, *value;
2002# ifdef MSWIN
2003 extern wchar_t **_wenviron;
2004# else
2005 extern char **environ;
2006# endif
2007
2008 if (rettv_dict_alloc(rettv) != OK)
2009 return;
2010
2011# ifdef MSWIN
2012 if (*_wenviron == NULL)
2013 return;
2014# else
2015 if (*environ == NULL)
2016 return;
2017# endif
2018
2019 for (i = 0; ; ++i)
2020 {
2021# ifdef MSWIN
2022 short_u *p;
2023
2024 if ((p = (short_u *)_wenviron[i]) == NULL)
2025 return;
2026 entry = utf16_to_enc(p, NULL);
2027# else
2028 if ((entry = (char_u *)environ[i]) == NULL)
2029 return;
2030 entry = vim_strsave(entry);
2031# endif
2032 if (entry == NULL) // out of memory
2033 return;
2034 if ((value = vim_strchr(entry, '=')) == NULL)
2035 {
2036 vim_free(entry);
2037 continue;
2038 }
2039 *value++ = NUL;
2040 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2041 vim_free(entry);
2042 }
2043#endif
2044}
2045
2046/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002047 * "escape({string}, {chars})" function
2048 */
2049 static void
2050f_escape(typval_T *argvars, typval_T *rettv)
2051{
2052 char_u buf[NUMBUFLEN];
2053
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002054 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2055 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002056 rettv->v_type = VAR_STRING;
2057}
2058
2059/*
2060 * "eval()" function
2061 */
2062 static void
2063f_eval(typval_T *argvars, typval_T *rettv)
2064{
2065 char_u *s, *p;
2066
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002067 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002068 if (s != NULL)
2069 s = skipwhite(s);
2070
2071 p = s;
Bram Moolenaar32e35112020-05-14 22:41:15 +02002072 if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002073 {
2074 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002075 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002076 need_clr_eos = FALSE;
2077 rettv->v_type = VAR_NUMBER;
2078 rettv->vval.v_number = 0;
2079 }
2080 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002081 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082}
2083
2084/*
2085 * "eventhandler()" function
2086 */
2087 static void
2088f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2089{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002090 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002091}
2092
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093static garray_T redir_execute_ga;
2094
2095/*
2096 * Append "value[value_len]" to the execute() output.
2097 */
2098 void
2099execute_redir_str(char_u *value, int value_len)
2100{
2101 int len;
2102
2103 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002104 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002105 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002106 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002107 if (ga_grow(&redir_execute_ga, len) == OK)
2108 {
2109 mch_memmove((char *)redir_execute_ga.ga_data
2110 + redir_execute_ga.ga_len, value, len);
2111 redir_execute_ga.ga_len += len;
2112 }
2113}
2114
2115/*
2116 * Get next line from a list.
2117 * Called by do_cmdline() to get the next line.
2118 * Returns allocated string, or NULL for end of function.
2119 */
2120
2121 static char_u *
2122get_list_line(
2123 int c UNUSED,
2124 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002125 int indent UNUSED,
2126 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002127{
2128 listitem_T **p = (listitem_T **)cookie;
2129 listitem_T *item = *p;
2130 char_u buf[NUMBUFLEN];
2131 char_u *s;
2132
2133 if (item == NULL)
2134 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002135 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002136 *p = item->li_next;
2137 return s == NULL ? NULL : vim_strsave(s);
2138}
2139
2140/*
2141 * "execute()" function
2142 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002143 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002144execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002145{
2146 char_u *cmd = NULL;
2147 list_T *list = NULL;
2148 int save_msg_silent = msg_silent;
2149 int save_emsg_silent = emsg_silent;
2150 int save_emsg_noredir = emsg_noredir;
2151 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002152 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002154 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002155 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002156
2157 rettv->vval.v_string = NULL;
2158 rettv->v_type = VAR_STRING;
2159
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002160 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002162 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002163 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002164 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002165 return;
2166 ++list->lv_refcount;
2167 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002168 else if (argvars[arg_off].v_type == VAR_JOB
2169 || argvars[arg_off].v_type == VAR_CHANNEL)
2170 {
2171 emsg(_(e_inval_string));
2172 return;
2173 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002174 else
2175 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002176 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 if (cmd == NULL)
2178 return;
2179 }
2180
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002181 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182 {
2183 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002184 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002185
2186 if (s == NULL)
2187 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002188 if (*s == NUL)
2189 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002190 if (STRNCMP(s, "silent", 6) == 0)
2191 ++msg_silent;
2192 if (STRCMP(s, "silent!") == 0)
2193 {
2194 emsg_silent = TRUE;
2195 emsg_noredir = TRUE;
2196 }
2197 }
2198 else
2199 ++msg_silent;
2200
2201 if (redir_execute)
2202 save_ga = redir_execute_ga;
2203 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2204 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002205 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002206 if (!echo_output)
2207 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002208
2209 if (cmd != NULL)
2210 do_cmdline_cmd(cmd);
2211 else
2212 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002213 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002214
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002215 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002216 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002217 do_cmdline(NULL, get_list_line, (void *)&item,
2218 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2219 --list->lv_refcount;
2220 }
2221
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002222 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002223 if (ga_grow(&redir_execute_ga, 1) == OK)
2224 {
2225 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2226 rettv->vval.v_string = redir_execute_ga.ga_data;
2227 }
2228 else
2229 {
2230 ga_clear(&redir_execute_ga);
2231 rettv->vval.v_string = NULL;
2232 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002233 msg_silent = save_msg_silent;
2234 emsg_silent = save_emsg_silent;
2235 emsg_noredir = save_emsg_noredir;
2236
2237 redir_execute = save_redir_execute;
2238 if (redir_execute)
2239 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002240 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002241
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002242 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002243 if (echo_output)
2244 // When not working silently: put it in column zero. A following
2245 // "echon" will overwrite the message, unavoidably.
2246 msg_col = 0;
2247 else
2248 // When working silently: Put it back where it was, since nothing
2249 // should have been written.
2250 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002251}
2252
2253/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002254 * "execute()" function
2255 */
2256 static void
2257f_execute(typval_T *argvars, typval_T *rettv)
2258{
2259 execute_common(argvars, rettv, 0);
2260}
2261
2262/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263 * "exists()" function
2264 */
2265 static void
2266f_exists(typval_T *argvars, typval_T *rettv)
2267{
2268 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002270
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002271 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002272 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002273 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002274 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275 if (mch_getenv(p + 1) != NULL)
2276 n = TRUE;
2277 else
2278 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002279 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 p = expand_env_save(p);
2281 if (p != NULL && *p != '$')
2282 n = TRUE;
2283 vim_free(p);
2284 }
2285 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002286 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002287 {
2288 n = (get_option_tv(&p, NULL, TRUE) == OK);
2289 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002290 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002291 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002292 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002294 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002296 else if (*p == '?') // internal function only
2297 {
2298 n = has_internal_func_name(p + 1);
2299 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002300 else if (*p == ':')
2301 {
2302 n = cmd_exists(p + 1);
2303 }
2304 else if (*p == '#')
2305 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002306 if (p[1] == '#')
2307 n = autocmd_supported(p + 2);
2308 else
2309 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002310 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002311 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002312 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002313 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002314 }
2315
2316 rettv->vval.v_number = n;
2317}
2318
2319#ifdef FEAT_FLOAT
2320/*
2321 * "exp()" function
2322 */
2323 static void
2324f_exp(typval_T *argvars, typval_T *rettv)
2325{
2326 float_T f = 0.0;
2327
2328 rettv->v_type = VAR_FLOAT;
2329 if (get_float_arg(argvars, &f) == OK)
2330 rettv->vval.v_float = exp(f);
2331 else
2332 rettv->vval.v_float = 0.0;
2333}
2334#endif
2335
2336/*
2337 * "expand()" function
2338 */
2339 static void
2340f_expand(typval_T *argvars, typval_T *rettv)
2341{
2342 char_u *s;
2343 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002344 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2346 expand_T xpc;
2347 int error = FALSE;
2348 char_u *result;
2349
2350 rettv->v_type = VAR_STRING;
2351 if (argvars[1].v_type != VAR_UNKNOWN
2352 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002353 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002354 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002355 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002357 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002358 if (*s == '%' || *s == '#' || *s == '<')
2359 {
2360 ++emsg_off;
2361 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2362 --emsg_off;
2363 if (rettv->v_type == VAR_LIST)
2364 {
2365 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2366 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002367 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002368 }
2369 else
2370 rettv->vval.v_string = result;
2371 }
2372 else
2373 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002374 // When the optional second argument is non-zero, don't remove matches
2375 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002376 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002377 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002378 options |= WILD_KEEP_ALL;
2379 if (!error)
2380 {
2381 ExpandInit(&xpc);
2382 xpc.xp_context = EXPAND_FILES;
2383 if (p_wic)
2384 options += WILD_ICASE;
2385 if (rettv->v_type == VAR_STRING)
2386 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2387 options, WILD_ALL);
2388 else if (rettv_list_alloc(rettv) != FAIL)
2389 {
2390 int i;
2391
2392 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2393 for (i = 0; i < xpc.xp_numfiles; i++)
2394 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2395 ExpandCleanup(&xpc);
2396 }
2397 }
2398 else
2399 rettv->vval.v_string = NULL;
2400 }
2401}
2402
2403/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002404 * "expandcmd()" function
2405 * Expand all the special characters in a command string.
2406 */
2407 static void
2408f_expandcmd(typval_T *argvars, typval_T *rettv)
2409{
2410 exarg_T eap;
2411 char_u *cmdstr;
2412 char *errormsg = NULL;
2413
2414 rettv->v_type = VAR_STRING;
2415 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2416
2417 memset(&eap, 0, sizeof(eap));
2418 eap.cmd = cmdstr;
2419 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002420 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002421 eap.usefilter = FALSE;
2422 eap.nextcmd = NULL;
2423 eap.cmdidx = CMD_USER;
2424
2425 expand_filename(&eap, &cmdstr, &errormsg);
2426 if (errormsg != NULL && *errormsg != NUL)
2427 emsg(errormsg);
2428
2429 rettv->vval.v_string = cmdstr;
2430}
2431
2432/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002433 * "feedkeys()" function
2434 */
2435 static void
2436f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2437{
2438 int remap = TRUE;
2439 int insert = FALSE;
2440 char_u *keys, *flags;
2441 char_u nbuf[NUMBUFLEN];
2442 int typed = FALSE;
2443 int execute = FALSE;
2444 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002445 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446 char_u *keys_esc;
2447
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002448 // This is not allowed in the sandbox. If the commands would still be
2449 // executed in the sandbox it would be OK, but it probably happens later,
2450 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451 if (check_secure())
2452 return;
2453
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002454 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002455
2456 if (argvars[1].v_type != VAR_UNKNOWN)
2457 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002458 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 for ( ; *flags != NUL; ++flags)
2460 {
2461 switch (*flags)
2462 {
2463 case 'n': remap = FALSE; break;
2464 case 'm': remap = TRUE; break;
2465 case 't': typed = TRUE; break;
2466 case 'i': insert = TRUE; break;
2467 case 'x': execute = TRUE; break;
2468 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002469 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470 }
2471 }
2472 }
2473
2474 if (*keys != NUL || execute)
2475 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002476 // Need to escape K_SPECIAL and CSI before putting the string in the
2477 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002478 keys_esc = vim_strsave_escape_csi(keys);
2479 if (keys_esc != NULL)
2480 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002481 if (lowlevel)
2482 {
2483#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002484 int idx;
2485 int len = (int)STRLEN(keys);
2486
2487 for (idx = 0; idx < len; ++idx)
2488 {
2489 // if a CTRL-C was typed, set got_int, similar to what
2490 // happens in fill_input_buf()
2491 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2492 got_int = TRUE;
2493 add_to_input_buf(keys + idx, 1);
2494 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002495#else
2496 emsg(_("E980: lowlevel input not supported"));
2497#endif
2498 }
2499 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002500 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002501 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002502 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002503 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002504#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002505 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002506#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002507 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002508 typebuf_was_filled = TRUE;
2509 }
2510 vim_free(keys_esc);
2511
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512 if (execute)
2513 {
2514 int save_msg_scroll = msg_scroll;
2515
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002516 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517 msg_scroll = FALSE;
2518
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002519 if (!dangerous)
2520 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002521 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002522 if (!dangerous)
2523 --ex_normal_busy;
2524
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002525 msg_scroll |= save_msg_scroll;
2526 }
2527 }
2528 }
2529}
2530
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002531#ifdef FEAT_FLOAT
2532/*
2533 * "float2nr({float})" function
2534 */
2535 static void
2536f_float2nr(typval_T *argvars, typval_T *rettv)
2537{
2538 float_T f = 0.0;
2539
2540 if (get_float_arg(argvars, &f) == OK)
2541 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002542 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002543 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002544 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002545 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002546 else
2547 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002548 }
2549}
2550
2551/*
2552 * "floor({float})" function
2553 */
2554 static void
2555f_floor(typval_T *argvars, typval_T *rettv)
2556{
2557 float_T f = 0.0;
2558
2559 rettv->v_type = VAR_FLOAT;
2560 if (get_float_arg(argvars, &f) == OK)
2561 rettv->vval.v_float = floor(f);
2562 else
2563 rettv->vval.v_float = 0.0;
2564}
2565
2566/*
2567 * "fmod()" function
2568 */
2569 static void
2570f_fmod(typval_T *argvars, typval_T *rettv)
2571{
2572 float_T fx = 0.0, fy = 0.0;
2573
2574 rettv->v_type = VAR_FLOAT;
2575 if (get_float_arg(argvars, &fx) == OK
2576 && get_float_arg(&argvars[1], &fy) == OK)
2577 rettv->vval.v_float = fmod(fx, fy);
2578 else
2579 rettv->vval.v_float = 0.0;
2580}
2581#endif
2582
2583/*
2584 * "fnameescape({string})" function
2585 */
2586 static void
2587f_fnameescape(typval_T *argvars, typval_T *rettv)
2588{
2589 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002590 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591 rettv->v_type = VAR_STRING;
2592}
2593
2594/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002595 * "foreground()" function
2596 */
2597 static void
2598f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2599{
2600#ifdef FEAT_GUI
2601 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002602 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002604 return;
2605 }
2606#endif
2607#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002608 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609#endif
2610}
2611
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002612 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002613common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614{
2615 char_u *s;
2616 char_u *name;
2617 int use_string = FALSE;
2618 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002619 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002620 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621
2622 if (argvars[0].v_type == VAR_FUNC)
2623 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002624 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002625 s = argvars[0].vval.v_string;
2626 }
2627 else if (argvars[0].v_type == VAR_PARTIAL
2628 && argvars[0].vval.v_partial != NULL)
2629 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002630 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002631 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002632 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002633 }
2634 else
2635 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002636 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002637 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002638 use_string = TRUE;
2639 }
2640
Bram Moolenaar843b8842016-08-21 14:36:15 +02002641 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002642 {
2643 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002644 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002645 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2646 if (*name != NUL)
2647 s = NULL;
2648 }
2649
Bram Moolenaar843b8842016-08-21 14:36:15 +02002650 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2651 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002652 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002653 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002654 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002655 ? find_func(trans_name, is_global, NULL) == NULL
2656 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002657 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002658 else
2659 {
2660 int dict_idx = 0;
2661 int arg_idx = 0;
2662 list_T *list = NULL;
2663
2664 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2665 {
2666 char sid_buf[25];
2667 int off = *s == 's' ? 2 : 5;
2668
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002669 // Expand s: and <SID> into <SNR>nr_, so that the function can
2670 // also be called from another script. Using trans_function_name()
2671 // would also work, but some plugins depend on the name being
2672 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002673 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002674 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675 if (name != NULL)
2676 {
2677 STRCPY(name, sid_buf);
2678 STRCAT(name, s + off);
2679 }
2680 }
2681 else
2682 name = vim_strsave(s);
2683
2684 if (argvars[1].v_type != VAR_UNKNOWN)
2685 {
2686 if (argvars[2].v_type != VAR_UNKNOWN)
2687 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002688 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002689 arg_idx = 1;
2690 dict_idx = 2;
2691 }
2692 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002693 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694 dict_idx = 1;
2695 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002696 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002697 arg_idx = 1;
2698 if (dict_idx > 0)
2699 {
2700 if (argvars[dict_idx].v_type != VAR_DICT)
2701 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002702 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002704 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705 }
2706 if (argvars[dict_idx].vval.v_dict == NULL)
2707 dict_idx = 0;
2708 }
2709 if (arg_idx > 0)
2710 {
2711 if (argvars[arg_idx].v_type != VAR_LIST)
2712 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002713 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002714 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002715 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002716 }
2717 list = argvars[arg_idx].vval.v_list;
2718 if (list == NULL || list->lv_len == 0)
2719 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002720 else if (list->lv_len > MAX_FUNC_ARGS)
2721 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002722 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002723 vim_free(name);
2724 goto theend;
2725 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002726 }
2727 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002728 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002729 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002730 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002731
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002732 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002733 if (pt == NULL)
2734 vim_free(name);
2735 else
2736 {
2737 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2738 {
2739 listitem_T *li;
2740 int i = 0;
2741 int arg_len = 0;
2742 int lv_len = 0;
2743
2744 if (arg_pt != NULL)
2745 arg_len = arg_pt->pt_argc;
2746 if (list != NULL)
2747 lv_len = list->lv_len;
2748 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002749 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002750 if (pt->pt_argv == NULL)
2751 {
2752 vim_free(pt);
2753 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002754 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002755 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002756 for (i = 0; i < arg_len; i++)
2757 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2758 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002759 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002760 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002761 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002762 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002763 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002764 }
2765
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002766 // For "function(dict.func, [], dict)" and "func" is a partial
2767 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002768 if (dict_idx > 0)
2769 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002770 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002771 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2772 ++pt->pt_dict->dv_refcount;
2773 }
2774 else if (arg_pt != NULL)
2775 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002776 // If the dict was bound automatically the result is also
2777 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 pt->pt_dict = arg_pt->pt_dict;
2779 pt->pt_auto = arg_pt->pt_auto;
2780 if (pt->pt_dict != NULL)
2781 ++pt->pt_dict->dv_refcount;
2782 }
2783
2784 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002785 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2786 {
2787 pt->pt_func = arg_pt->pt_func;
2788 func_ptr_ref(pt->pt_func);
2789 vim_free(name);
2790 }
2791 else if (is_funcref)
2792 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002793 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002794 func_ptr_ref(pt->pt_func);
2795 vim_free(name);
2796 }
2797 else
2798 {
2799 pt->pt_name = name;
2800 func_ref(name);
2801 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002802 }
2803 rettv->v_type = VAR_PARTIAL;
2804 rettv->vval.v_partial = pt;
2805 }
2806 else
2807 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002808 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002809 rettv->v_type = VAR_FUNC;
2810 rettv->vval.v_string = name;
2811 func_ref(name);
2812 }
2813 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002814theend:
2815 vim_free(trans_name);
2816}
2817
2818/*
2819 * "funcref()" function
2820 */
2821 static void
2822f_funcref(typval_T *argvars, typval_T *rettv)
2823{
2824 common_function(argvars, rettv, TRUE);
2825}
2826
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002827 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002828ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002829{
2830 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2831 return &t_func_any;
Bram Moolenaard77a8522020-04-03 21:59:57 +02002832 return &t_func_void;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002833}
2834
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002835/*
2836 * "function()" function
2837 */
2838 static void
2839f_function(typval_T *argvars, typval_T *rettv)
2840{
2841 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002842}
2843
2844/*
2845 * "garbagecollect()" function
2846 */
2847 static void
2848f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2849{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002850 // This is postponed until we are back at the toplevel, because we may be
2851 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002852 want_garbage_collect = TRUE;
2853
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002854 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855 garbage_collect_at_exit = TRUE;
2856}
2857
2858/*
2859 * "get()" function
2860 */
2861 static void
2862f_get(typval_T *argvars, typval_T *rettv)
2863{
2864 listitem_T *li;
2865 list_T *l;
2866 dictitem_T *di;
2867 dict_T *d;
2868 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002869 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002870
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002871 if (argvars[0].v_type == VAR_BLOB)
2872 {
2873 int error = FALSE;
2874 int idx = tv_get_number_chk(&argvars[1], &error);
2875
2876 if (!error)
2877 {
2878 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002879 if (idx < 0)
2880 idx = blob_len(argvars[0].vval.v_blob) + idx;
2881 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2882 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002883 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002884 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002885 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002886 tv = rettv;
2887 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002888 }
2889 }
2890 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002891 {
2892 if ((l = argvars[0].vval.v_list) != NULL)
2893 {
2894 int error = FALSE;
2895
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002896 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002897 if (!error && li != NULL)
2898 tv = &li->li_tv;
2899 }
2900 }
2901 else if (argvars[0].v_type == VAR_DICT)
2902 {
2903 if ((d = argvars[0].vval.v_dict) != NULL)
2904 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002905 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002906 if (di != NULL)
2907 tv = &di->di_tv;
2908 }
2909 }
2910 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2911 {
2912 partial_T *pt;
2913 partial_T fref_pt;
2914
2915 if (argvars[0].v_type == VAR_PARTIAL)
2916 pt = argvars[0].vval.v_partial;
2917 else
2918 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02002919 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002920 fref_pt.pt_name = argvars[0].vval.v_string;
2921 pt = &fref_pt;
2922 }
2923
2924 if (pt != NULL)
2925 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002926 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002927 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002928
2929 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2930 {
2931 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002932 n = partial_name(pt);
2933 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002934 rettv->vval.v_string = NULL;
2935 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002936 {
2937 rettv->vval.v_string = vim_strsave(n);
2938 if (rettv->v_type == VAR_FUNC)
2939 func_ref(rettv->vval.v_string);
2940 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002941 }
2942 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002943 {
2944 what_is_dict = TRUE;
2945 if (pt->pt_dict != NULL)
2946 rettv_dict_set(rettv, pt->pt_dict);
2947 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002948 else if (STRCMP(what, "args") == 0)
2949 {
2950 rettv->v_type = VAR_LIST;
2951 if (rettv_list_alloc(rettv) == OK)
2952 {
2953 int i;
2954
2955 for (i = 0; i < pt->pt_argc; ++i)
2956 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2957 }
2958 }
2959 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002960 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002961
2962 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2963 // third argument
2964 if (!what_is_dict)
2965 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002966 }
2967 }
2968 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002969 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002970
2971 if (tv == NULL)
2972 {
2973 if (argvars[2].v_type != VAR_UNKNOWN)
2974 copy_tv(&argvars[2], rettv);
2975 }
2976 else
2977 copy_tv(tv, rettv);
2978}
2979
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002980/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002981 * "getchangelist()" function
2982 */
2983 static void
2984f_getchangelist(typval_T *argvars, typval_T *rettv)
2985{
2986#ifdef FEAT_JUMPLIST
2987 buf_T *buf;
2988 int i;
2989 list_T *l;
2990 dict_T *d;
2991#endif
2992
2993 if (rettv_list_alloc(rettv) != OK)
2994 return;
2995
2996#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002997 if (argvars[0].v_type == VAR_UNKNOWN)
2998 buf = curbuf;
2999 else
3000 {
3001 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3002 ++emsg_off;
3003 buf = tv_get_buf(&argvars[0], FALSE);
3004 --emsg_off;
3005 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003006 if (buf == NULL)
3007 return;
3008
3009 l = list_alloc();
3010 if (l == NULL)
3011 return;
3012
3013 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3014 return;
3015 /*
3016 * The current window change list index tracks only the position in the
3017 * current buffer change list. For other buffers, use the change list
3018 * length as the current index.
3019 */
3020 list_append_number(rettv->vval.v_list,
3021 (varnumber_T)((buf == curwin->w_buffer)
3022 ? curwin->w_changelistidx : buf->b_changelistlen));
3023
3024 for (i = 0; i < buf->b_changelistlen; ++i)
3025 {
3026 if (buf->b_changelist[i].lnum == 0)
3027 continue;
3028 if ((d = dict_alloc()) == NULL)
3029 return;
3030 if (list_append_dict(l, d) == FAIL)
3031 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003032 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3033 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003034 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003035 }
3036#endif
3037}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038
3039/*
3040 * "getcharsearch()" function
3041 */
3042 static void
3043f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3044{
3045 if (rettv_dict_alloc(rettv) != FAIL)
3046 {
3047 dict_T *dict = rettv->vval.v_dict;
3048
Bram Moolenaare0be1672018-07-08 16:50:37 +02003049 dict_add_string(dict, "char", last_csearch());
3050 dict_add_number(dict, "forward", last_csearch_forward());
3051 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003052 }
3053}
3054
3055/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003056 * "getenv()" function
3057 */
3058 static void
3059f_getenv(typval_T *argvars, typval_T *rettv)
3060{
3061 int mustfree = FALSE;
3062 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3063
3064 if (p == NULL)
3065 {
3066 rettv->v_type = VAR_SPECIAL;
3067 rettv->vval.v_number = VVAL_NULL;
3068 return;
3069 }
3070 if (!mustfree)
3071 p = vim_strsave(p);
3072 rettv->vval.v_string = p;
3073 rettv->v_type = VAR_STRING;
3074}
3075
3076/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 * "getfontname()" function
3078 */
3079 static void
3080f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3081{
3082 rettv->v_type = VAR_STRING;
3083 rettv->vval.v_string = NULL;
3084#ifdef FEAT_GUI
3085 if (gui.in_use)
3086 {
3087 GuiFont font;
3088 char_u *name = NULL;
3089
3090 if (argvars[0].v_type == VAR_UNKNOWN)
3091 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003092 // Get the "Normal" font. Either the name saved by
3093 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003094 font = gui.norm_font;
3095 name = hl_get_font_name();
3096 }
3097 else
3098 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003099 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003100 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003101 return;
3102 font = gui_mch_get_font(name, FALSE);
3103 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003104 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003105 }
3106 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3107 if (argvars[0].v_type != VAR_UNKNOWN)
3108 gui_mch_free_font(font);
3109 }
3110#endif
3111}
3112
3113/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003114 * "getjumplist()" function
3115 */
3116 static void
3117f_getjumplist(typval_T *argvars, typval_T *rettv)
3118{
3119#ifdef FEAT_JUMPLIST
3120 win_T *wp;
3121 int i;
3122 list_T *l;
3123 dict_T *d;
3124#endif
3125
3126 if (rettv_list_alloc(rettv) != OK)
3127 return;
3128
3129#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003130 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003131 if (wp == NULL)
3132 return;
3133
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003134 cleanup_jumplist(wp, TRUE);
3135
Bram Moolenaar4f505882018-02-10 21:06:32 +01003136 l = list_alloc();
3137 if (l == NULL)
3138 return;
3139
3140 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3141 return;
3142 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3143
3144 for (i = 0; i < wp->w_jumplistlen; ++i)
3145 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003146 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3147 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003148 if ((d = dict_alloc()) == NULL)
3149 return;
3150 if (list_append_dict(l, d) == FAIL)
3151 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003152 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3153 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003154 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003155 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003156 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003157 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003158 }
3159#endif
3160}
3161
3162/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003163 * "getpid()" function
3164 */
3165 static void
3166f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3167{
3168 rettv->vval.v_number = mch_get_pid();
3169}
3170
3171 static void
3172getpos_both(
3173 typval_T *argvars,
3174 typval_T *rettv,
3175 int getcurpos)
3176{
3177 pos_T *fp;
3178 list_T *l;
3179 int fnum = -1;
3180
3181 if (rettv_list_alloc(rettv) == OK)
3182 {
3183 l = rettv->vval.v_list;
3184 if (getcurpos)
3185 fp = &curwin->w_cursor;
3186 else
3187 fp = var2fpos(&argvars[0], TRUE, &fnum);
3188 if (fnum != -1)
3189 list_append_number(l, (varnumber_T)fnum);
3190 else
3191 list_append_number(l, (varnumber_T)0);
3192 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3193 : (varnumber_T)0);
3194 list_append_number(l, (fp != NULL)
3195 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3196 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003197 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003198 (varnumber_T)0);
3199 if (getcurpos)
3200 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003201 int save_set_curswant = curwin->w_set_curswant;
3202 colnr_T save_curswant = curwin->w_curswant;
3203 colnr_T save_virtcol = curwin->w_virtcol;
3204
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003205 update_curswant();
3206 list_append_number(l, curwin->w_curswant == MAXCOL ?
3207 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003208
3209 // Do not change "curswant", as it is unexpected that a get
3210 // function has a side effect.
3211 if (save_set_curswant)
3212 {
3213 curwin->w_set_curswant = save_set_curswant;
3214 curwin->w_curswant = save_curswant;
3215 curwin->w_virtcol = save_virtcol;
3216 curwin->w_valid &= ~VALID_VIRTCOL;
3217 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003218 }
3219 }
3220 else
3221 rettv->vval.v_number = FALSE;
3222}
3223
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003224/*
3225 * "getcurpos()" function
3226 */
3227 static void
3228f_getcurpos(typval_T *argvars, typval_T *rettv)
3229{
3230 getpos_both(argvars, rettv, TRUE);
3231}
3232
3233/*
3234 * "getpos(string)" function
3235 */
3236 static void
3237f_getpos(typval_T *argvars, typval_T *rettv)
3238{
3239 getpos_both(argvars, rettv, FALSE);
3240}
3241
3242/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003243 * "getreg()" function
3244 */
3245 static void
3246f_getreg(typval_T *argvars, typval_T *rettv)
3247{
3248 char_u *strregname;
3249 int regname;
3250 int arg2 = FALSE;
3251 int return_list = FALSE;
3252 int error = FALSE;
3253
3254 if (argvars[0].v_type != VAR_UNKNOWN)
3255 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003256 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257 error = strregname == NULL;
3258 if (argvars[1].v_type != VAR_UNKNOWN)
3259 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003260 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003261 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003262 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003263 }
3264 }
3265 else
3266 strregname = get_vim_var_str(VV_REG);
3267
3268 if (error)
3269 return;
3270
3271 regname = (strregname == NULL ? '"' : *strregname);
3272 if (regname == 0)
3273 regname = '"';
3274
3275 if (return_list)
3276 {
3277 rettv->v_type = VAR_LIST;
3278 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3279 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3280 if (rettv->vval.v_list == NULL)
3281 (void)rettv_list_alloc(rettv);
3282 else
3283 ++rettv->vval.v_list->lv_refcount;
3284 }
3285 else
3286 {
3287 rettv->v_type = VAR_STRING;
3288 rettv->vval.v_string = get_reg_contents(regname,
3289 arg2 ? GREG_EXPR_SRC : 0);
3290 }
3291}
3292
3293/*
3294 * "getregtype()" function
3295 */
3296 static void
3297f_getregtype(typval_T *argvars, typval_T *rettv)
3298{
3299 char_u *strregname;
3300 int regname;
3301 char_u buf[NUMBUFLEN + 2];
3302 long reglen = 0;
3303
3304 if (argvars[0].v_type != VAR_UNKNOWN)
3305 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003306 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003307 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 {
3309 rettv->v_type = VAR_STRING;
3310 rettv->vval.v_string = NULL;
3311 return;
3312 }
3313 }
3314 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003315 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316 strregname = get_vim_var_str(VV_REG);
3317
3318 regname = (strregname == NULL ? '"' : *strregname);
3319 if (regname == 0)
3320 regname = '"';
3321
3322 buf[0] = NUL;
3323 buf[1] = NUL;
3324 switch (get_reg_type(regname, &reglen))
3325 {
3326 case MLINE: buf[0] = 'V'; break;
3327 case MCHAR: buf[0] = 'v'; break;
3328 case MBLOCK:
3329 buf[0] = Ctrl_V;
3330 sprintf((char *)buf + 1, "%ld", reglen + 1);
3331 break;
3332 }
3333 rettv->v_type = VAR_STRING;
3334 rettv->vval.v_string = vim_strsave(buf);
3335}
3336
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003337/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003338 * "gettagstack()" function
3339 */
3340 static void
3341f_gettagstack(typval_T *argvars, typval_T *rettv)
3342{
3343 win_T *wp = curwin; // default is current window
3344
3345 if (rettv_dict_alloc(rettv) != OK)
3346 return;
3347
3348 if (argvars[0].v_type != VAR_UNKNOWN)
3349 {
3350 wp = find_win_by_nr_or_id(&argvars[0]);
3351 if (wp == NULL)
3352 return;
3353 }
3354
3355 get_tagstack(wp, rettv->vval.v_dict);
3356}
3357
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003358// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003359#include "version.h"
3360
3361/*
3362 * "has()" function
3363 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003364 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003365f_has(typval_T *argvars, typval_T *rettv)
3366{
3367 int i;
3368 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003369 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003370 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003371 typedef struct {
3372 char *name;
3373 short present;
3374 } has_item_T;
3375 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003377 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003379 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003380#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003381 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003382#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003383 },
3384 {"arp",
3385#if defined(AMIGA) && defined(FEAT_ARP)
3386 1
3387#else
3388 0
3389#endif
3390 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003391 {"haiku",
3392#ifdef __HAIKU__
3393 1
3394#else
3395 0
3396#endif
3397 },
3398 {"bsd",
3399#if defined(BSD) && !defined(MACOS_X)
3400 1
3401#else
3402 0
3403#endif
3404 },
3405 {"hpux",
3406#ifdef hpux
3407 1
3408#else
3409 0
3410#endif
3411 },
3412 {"linux",
3413#ifdef __linux__
3414 1
3415#else
3416 0
3417#endif
3418 },
3419 {"mac", // Mac OS X (and, once, Mac OS Classic)
3420#ifdef MACOS_X
3421 1
3422#else
3423 0
3424#endif
3425 },
3426 {"osx", // Mac OS X
3427#ifdef MACOS_X
3428 1
3429#else
3430 0
3431#endif
3432 },
3433 {"macunix", // Mac OS X, with the darwin feature
3434#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3435 1
3436#else
3437 0
3438#endif
3439 },
3440 {"osxdarwin", // synonym for macunix
3441#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3442 1
3443#else
3444 0
3445#endif
3446 },
3447 {"qnx",
3448#ifdef __QNX__
3449 1
3450#else
3451 0
3452#endif
3453 },
3454 {"sun",
3455#ifdef SUN_SYSTEM
3456 1
3457#else
3458 0
3459#endif
3460 },
3461 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003462#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003463 1
3464#else
3465 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003466#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003467 },
3468 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003469#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003470 1
3471#else
3472 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003473#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003474 },
3475 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003476#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003477 1
3478#else
3479 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003480#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003481 },
3482 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003483#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003484 1
3485#else
3486 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003487#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003488 },
3489 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003490#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003491 1
3492#else
3493 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003494#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003495 },
3496 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003497#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003498 1
3499#else
3500 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003501#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003502 },
3503 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003504#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003505 1
3506#else
3507 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003508#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003509 },
3510 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003511#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003512 1
3513#else
3514 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003515#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003516 },
3517 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003519 1
3520#else
3521 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003522#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003523 },
3524 {"autocmd", 1},
3525 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003526#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003527 1
3528#else
3529 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003530#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003531 },
3532 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003533#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003534 1
3535#else
3536 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003537#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003538 },
3539 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003540#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003541 1
3542#else
3543 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003544#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003545 },
3546 {"balloon_multiline",
3547#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3548 // MS-Windows requires runtime check, see below
3549 1
3550#else
3551 0
3552#endif
3553 },
3554 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003555#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003556 1
3557#else
3558 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003559#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003560 },
3561 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003562#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003563 1
3564#else
3565 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003566#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003567 },
3568 {"all_builtin_terms",
3569#if defined(ALL_BUILTIN_TCAPS)
3570 1
3571#else
3572 0
3573#endif
3574 },
3575 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003576#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003577 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003579 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003580#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003581 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003583 },
3584 {"byte_offset",
3585#ifdef FEAT_BYTEOFF
3586 1
3587#else
3588 0
3589#endif
3590 },
3591 {"channel",
3592#ifdef FEAT_JOB_CHANNEL
3593 1
3594#else
3595 0
3596#endif
3597 },
3598 {"cindent",
3599#ifdef FEAT_CINDENT
3600 1
3601#else
3602 0
3603#endif
3604 },
3605 {"clientserver",
3606#ifdef FEAT_CLIENTSERVER
3607 1
3608#else
3609 0
3610#endif
3611 },
3612 {"clipboard",
3613#ifdef FEAT_CLIPBOARD
3614 1
3615#else
3616 0
3617#endif
3618 },
3619 {"cmdline_compl", 1},
3620 {"cmdline_hist", 1},
3621 {"comments", 1},
3622 {"conceal",
3623#ifdef FEAT_CONCEAL
3624 1
3625#else
3626 0
3627#endif
3628 },
3629 {"cryptv",
3630#ifdef FEAT_CRYPT
3631 1
3632#else
3633 0
3634#endif
3635 },
3636 {"crypt-blowfish",
3637#ifdef FEAT_CRYPT
3638 1
3639#else
3640 0
3641#endif
3642 },
3643 {"crypt-blowfish2",
3644#ifdef FEAT_CRYPT
3645 1
3646#else
3647 0
3648#endif
3649 },
3650 {"cscope",
3651#ifdef FEAT_CSCOPE
3652 1
3653#else
3654 0
3655#endif
3656 },
3657 {"cursorbind", 1},
3658 {"cursorshape",
3659#ifdef CURSOR_SHAPE
3660 1
3661#else
3662 0
3663#endif
3664 },
3665 {"debug",
3666#ifdef DEBUG
3667 1
3668#else
3669 0
3670#endif
3671 },
3672 {"dialog_con",
3673#ifdef FEAT_CON_DIALOG
3674 1
3675#else
3676 0
3677#endif
3678 },
3679 {"dialog_gui",
3680#ifdef FEAT_GUI_DIALOG
3681 1
3682#else
3683 0
3684#endif
3685 },
3686 {"diff",
3687#ifdef FEAT_DIFF
3688 1
3689#else
3690 0
3691#endif
3692 },
3693 {"digraphs",
3694#ifdef FEAT_DIGRAPHS
3695 1
3696#else
3697 0
3698#endif
3699 },
3700 {"directx",
3701#ifdef FEAT_DIRECTX
3702 1
3703#else
3704 0
3705#endif
3706 },
3707 {"dnd",
3708#ifdef FEAT_DND
3709 1
3710#else
3711 0
3712#endif
3713 },
3714 {"emacs_tags",
3715#ifdef FEAT_EMACS_TAGS
3716 1
3717#else
3718 0
3719#endif
3720 },
3721 {"eval", 1}, // always present, of course!
3722 {"ex_extra", 1}, // graduated feature
3723 {"extra_search",
3724#ifdef FEAT_SEARCH_EXTRA
3725 1
3726#else
3727 0
3728#endif
3729 },
3730 {"file_in_path",
3731#ifdef FEAT_SEARCHPATH
3732 1
3733#else
3734 0
3735#endif
3736 },
3737 {"filterpipe",
3738#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3739 1
3740#else
3741 0
3742#endif
3743 },
3744 {"find_in_path",
3745#ifdef FEAT_FIND_ID
3746 1
3747#else
3748 0
3749#endif
3750 },
3751 {"float",
3752#ifdef FEAT_FLOAT
3753 1
3754#else
3755 0
3756#endif
3757 },
3758 {"folding",
3759#ifdef FEAT_FOLDING
3760 1
3761#else
3762 0
3763#endif
3764 },
3765 {"footer",
3766#ifdef FEAT_FOOTER
3767 1
3768#else
3769 0
3770#endif
3771 },
3772 {"fork",
3773#if !defined(USE_SYSTEM) && defined(UNIX)
3774 1
3775#else
3776 0
3777#endif
3778 },
3779 {"gettext",
3780#ifdef FEAT_GETTEXT
3781 1
3782#else
3783 0
3784#endif
3785 },
3786 {"gui",
3787#ifdef FEAT_GUI
3788 1
3789#else
3790 0
3791#endif
3792 },
3793 {"gui_neXtaw",
3794#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3795 1
3796#else
3797 0
3798#endif
3799 },
3800 {"gui_athena",
3801#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3802 1
3803#else
3804 0
3805#endif
3806 },
3807 {"gui_gtk",
3808#ifdef FEAT_GUI_GTK
3809 1
3810#else
3811 0
3812#endif
3813 },
3814 {"gui_gtk2",
3815#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3816 1
3817#else
3818 0
3819#endif
3820 },
3821 {"gui_gtk3",
3822#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3823 1
3824#else
3825 0
3826#endif
3827 },
3828 {"gui_gnome",
3829#ifdef FEAT_GUI_GNOME
3830 1
3831#else
3832 0
3833#endif
3834 },
3835 {"gui_haiku",
3836#ifdef FEAT_GUI_HAIKU
3837 1
3838#else
3839 0
3840#endif
3841 },
3842 {"gui_mac",
3843#ifdef FEAT_GUI_MAC
3844 1
3845#else
3846 0
3847#endif
3848 },
3849 {"gui_motif",
3850#ifdef FEAT_GUI_MOTIF
3851 1
3852#else
3853 0
3854#endif
3855 },
3856 {"gui_photon",
3857#ifdef FEAT_GUI_PHOTON
3858 1
3859#else
3860 0
3861#endif
3862 },
3863 {"gui_win32",
3864#ifdef FEAT_GUI_MSWIN
3865 1
3866#else
3867 0
3868#endif
3869 },
3870 {"iconv",
3871#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3872 1
3873#else
3874 0
3875#endif
3876 },
3877 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003878 {"ipv6",
3879#ifdef FEAT_IPV6
3880 1
3881#else
3882 0
3883#endif
3884 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003885 {"job",
3886#ifdef FEAT_JOB_CHANNEL
3887 1
3888#else
3889 0
3890#endif
3891 },
3892 {"jumplist",
3893#ifdef FEAT_JUMPLIST
3894 1
3895#else
3896 0
3897#endif
3898 },
3899 {"keymap",
3900#ifdef FEAT_KEYMAP
3901 1
3902#else
3903 0
3904#endif
3905 },
3906 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
3907 {"langmap",
3908#ifdef FEAT_LANGMAP
3909 1
3910#else
3911 0
3912#endif
3913 },
3914 {"libcall",
3915#ifdef FEAT_LIBCALL
3916 1
3917#else
3918 0
3919#endif
3920 },
3921 {"linebreak",
3922#ifdef FEAT_LINEBREAK
3923 1
3924#else
3925 0
3926#endif
3927 },
3928 {"lispindent",
3929#ifdef FEAT_LISP
3930 1
3931#else
3932 0
3933#endif
3934 },
3935 {"listcmds", 1},
3936 {"localmap", 1},
3937 {"lua",
3938#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
3939 1
3940#else
3941 0
3942#endif
3943 },
3944 {"menu",
3945#ifdef FEAT_MENU
3946 1
3947#else
3948 0
3949#endif
3950 },
3951 {"mksession",
3952#ifdef FEAT_SESSION
3953 1
3954#else
3955 0
3956#endif
3957 },
3958 {"modify_fname", 1},
3959 {"mouse", 1},
3960 {"mouseshape",
3961#ifdef FEAT_MOUSESHAPE
3962 1
3963#else
3964 0
3965#endif
3966 },
3967 {"mouse_dec",
3968#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
3969 1
3970#else
3971 0
3972#endif
3973 },
3974 {"mouse_gpm",
3975#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
3976 1
3977#else
3978 0
3979#endif
3980 },
3981 {"mouse_jsbterm",
3982#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
3983 1
3984#else
3985 0
3986#endif
3987 },
3988 {"mouse_netterm",
3989#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
3990 1
3991#else
3992 0
3993#endif
3994 },
3995 {"mouse_pterm",
3996#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
3997 1
3998#else
3999 0
4000#endif
4001 },
4002 {"mouse_sgr",
4003#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4004 1
4005#else
4006 0
4007#endif
4008 },
4009 {"mouse_sysmouse",
4010#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4011 1
4012#else
4013 0
4014#endif
4015 },
4016 {"mouse_urxvt",
4017#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4018 1
4019#else
4020 0
4021#endif
4022 },
4023 {"mouse_xterm",
4024#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4025 1
4026#else
4027 0
4028#endif
4029 },
4030 {"multi_byte", 1},
4031 {"multi_byte_ime",
4032#ifdef FEAT_MBYTE_IME
4033 1
4034#else
4035 0
4036#endif
4037 },
4038 {"multi_lang",
4039#ifdef FEAT_MULTI_LANG
4040 1
4041#else
4042 0
4043#endif
4044 },
4045 {"mzscheme",
4046#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4047 1
4048#else
4049 0
4050#endif
4051 },
4052 {"num64", 1},
4053 {"ole",
4054#ifdef FEAT_OLE
4055 1
4056#else
4057 0
4058#endif
4059 },
4060 {"packages",
4061#ifdef FEAT_EVAL
4062 1
4063#else
4064 0
4065#endif
4066 },
4067 {"path_extra",
4068#ifdef FEAT_PATH_EXTRA
4069 1
4070#else
4071 0
4072#endif
4073 },
4074 {"perl",
4075#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4076 1
4077#else
4078 0
4079#endif
4080 },
4081 {"persistent_undo",
4082#ifdef FEAT_PERSISTENT_UNDO
4083 1
4084#else
4085 0
4086#endif
4087 },
4088 {"python_compiled",
4089#if defined(FEAT_PYTHON)
4090 1
4091#else
4092 0
4093#endif
4094 },
4095 {"python_dynamic",
4096#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4097 1
4098#else
4099 0
4100#endif
4101 },
4102 {"python",
4103#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4104 1
4105#else
4106 0
4107#endif
4108 },
4109 {"pythonx",
4110#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4111 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4112 1
4113#else
4114 0
4115#endif
4116 },
4117 {"python3_compiled",
4118#if defined(FEAT_PYTHON3)
4119 1
4120#else
4121 0
4122#endif
4123 },
4124 {"python3_dynamic",
4125#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4126 1
4127#else
4128 0
4129#endif
4130 },
4131 {"python3",
4132#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4133 1
4134#else
4135 0
4136#endif
4137 },
4138 {"popupwin",
4139#ifdef FEAT_PROP_POPUP
4140 1
4141#else
4142 0
4143#endif
4144 },
4145 {"postscript",
4146#ifdef FEAT_POSTSCRIPT
4147 1
4148#else
4149 0
4150#endif
4151 },
4152 {"printer",
4153#ifdef FEAT_PRINTER
4154 1
4155#else
4156 0
4157#endif
4158 },
4159 {"profile",
4160#ifdef FEAT_PROFILE
4161 1
4162#else
4163 0
4164#endif
4165 },
4166 {"reltime",
4167#ifdef FEAT_RELTIME
4168 1
4169#else
4170 0
4171#endif
4172 },
4173 {"quickfix",
4174#ifdef FEAT_QUICKFIX
4175 1
4176#else
4177 0
4178#endif
4179 },
4180 {"rightleft",
4181#ifdef FEAT_RIGHTLEFT
4182 1
4183#else
4184 0
4185#endif
4186 },
4187 {"ruby",
4188#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4189 1
4190#else
4191 0
4192#endif
4193 },
4194 {"scrollbind", 1},
4195 {"showcmd",
4196#ifdef FEAT_CMDL_INFO
4197 1
4198#else
4199 0
4200#endif
4201 },
4202 {"cmdline_info",
4203#ifdef FEAT_CMDL_INFO
4204 1
4205#else
4206 0
4207#endif
4208 },
4209 {"signs",
4210#ifdef FEAT_SIGNS
4211 1
4212#else
4213 0
4214#endif
4215 },
4216 {"smartindent",
4217#ifdef FEAT_SMARTINDENT
4218 1
4219#else
4220 0
4221#endif
4222 },
4223 {"startuptime",
4224#ifdef STARTUPTIME
4225 1
4226#else
4227 0
4228#endif
4229 },
4230 {"statusline",
4231#ifdef FEAT_STL_OPT
4232 1
4233#else
4234 0
4235#endif
4236 },
4237 {"netbeans_intg",
4238#ifdef FEAT_NETBEANS_INTG
4239 1
4240#else
4241 0
4242#endif
4243 },
4244 {"sound",
4245#ifdef FEAT_SOUND
4246 1
4247#else
4248 0
4249#endif
4250 },
4251 {"spell",
4252#ifdef FEAT_SPELL
4253 1
4254#else
4255 0
4256#endif
4257 },
4258 {"syntax",
4259#ifdef FEAT_SYN_HL
4260 1
4261#else
4262 0
4263#endif
4264 },
4265 {"system",
4266#if defined(USE_SYSTEM) || !defined(UNIX)
4267 1
4268#else
4269 0
4270#endif
4271 },
4272 {"tag_binary",
4273#ifdef FEAT_TAG_BINS
4274 1
4275#else
4276 0
4277#endif
4278 },
4279 {"tcl",
4280#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4281 1
4282#else
4283 0
4284#endif
4285 },
4286 {"termguicolors",
4287#ifdef FEAT_TERMGUICOLORS
4288 1
4289#else
4290 0
4291#endif
4292 },
4293 {"terminal",
4294#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4295 1
4296#else
4297 0
4298#endif
4299 },
4300 {"terminfo",
4301#ifdef TERMINFO
4302 1
4303#else
4304 0
4305#endif
4306 },
4307 {"termresponse",
4308#ifdef FEAT_TERMRESPONSE
4309 1
4310#else
4311 0
4312#endif
4313 },
4314 {"textobjects",
4315#ifdef FEAT_TEXTOBJ
4316 1
4317#else
4318 0
4319#endif
4320 },
4321 {"textprop",
4322#ifdef FEAT_PROP_POPUP
4323 1
4324#else
4325 0
4326#endif
4327 },
4328 {"tgetent",
4329#ifdef HAVE_TGETENT
4330 1
4331#else
4332 0
4333#endif
4334 },
4335 {"timers",
4336#ifdef FEAT_TIMERS
4337 1
4338#else
4339 0
4340#endif
4341 },
4342 {"title",
4343#ifdef FEAT_TITLE
4344 1
4345#else
4346 0
4347#endif
4348 },
4349 {"toolbar",
4350#ifdef FEAT_TOOLBAR
4351 1
4352#else
4353 0
4354#endif
4355 },
4356 {"unnamedplus",
4357#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4358 1
4359#else
4360 0
4361#endif
4362 },
4363 {"user-commands", 1}, // was accidentally included in 5.4
4364 {"user_commands", 1},
4365 {"vartabs",
4366#ifdef FEAT_VARTABS
4367 1
4368#else
4369 0
4370#endif
4371 },
4372 {"vertsplit", 1},
4373 {"viminfo",
4374#ifdef FEAT_VIMINFO
4375 1
4376#else
4377 0
4378#endif
4379 },
4380 {"vimscript-1", 1},
4381 {"vimscript-2", 1},
4382 {"vimscript-3", 1},
4383 {"vimscript-4", 1},
4384 {"virtualedit", 1},
4385 {"visual", 1},
4386 {"visualextra", 1},
4387 {"vreplace", 1},
4388 {"vtp",
4389#ifdef FEAT_VTP
4390 1
4391#else
4392 0
4393#endif
4394 },
4395 {"wildignore",
4396#ifdef FEAT_WILDIGN
4397 1
4398#else
4399 0
4400#endif
4401 },
4402 {"wildmenu",
4403#ifdef FEAT_WILDMENU
4404 1
4405#else
4406 0
4407#endif
4408 },
4409 {"windows", 1},
4410 {"winaltkeys",
4411#ifdef FEAT_WAK
4412 1
4413#else
4414 0
4415#endif
4416 },
4417 {"writebackup",
4418#ifdef FEAT_WRITEBACKUP
4419 1
4420#else
4421 0
4422#endif
4423 },
4424 {"xim",
4425#ifdef FEAT_XIM
4426 1
4427#else
4428 0
4429#endif
4430 },
4431 {"xfontset",
4432#ifdef FEAT_XFONTSET
4433 1
4434#else
4435 0
4436#endif
4437 },
4438 {"xpm",
4439#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4440 1
4441#else
4442 0
4443#endif
4444 },
4445 {"xpm_w32", // for backward compatibility
4446#ifdef FEAT_XPM_W32
4447 1
4448#else
4449 0
4450#endif
4451 },
4452 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004453#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004454 1
4455#else
4456 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004458 },
4459 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004460#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004461 1
4462#else
4463 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004464#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004465 },
4466 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004467#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004468 1
4469#else
4470 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004471#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004472 },
4473 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004475 1
4476#else
4477 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004478#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004479 },
4480 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004481#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004482 1
4483#else
4484 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004485#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004486 },
4487 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004488 };
4489
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004490 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004491 for (i = 0; has_list[i].name != NULL; ++i)
4492 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004493 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004494 x = TRUE;
4495 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004496 break;
4497 }
4498
Bram Moolenaar79296512020-03-22 16:17:14 +01004499 // features also in has_list[] but sometimes enabled at runtime
4500 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004501 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004502 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004503 {
4504 // intentionally empty
4505 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004506#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 else if (STRICMP(name, "balloon_multiline") == 0)
4508 n = multiline_balloon_available();
4509#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004510#ifdef VIMDLL
4511 else if (STRICMP(name, "filterpipe") == 0)
4512 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004513#endif
4514#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4515 else if (STRICMP(name, "iconv") == 0)
4516 n = iconv_enabled(FALSE);
4517#endif
4518#ifdef DYNAMIC_LUA
4519 else if (STRICMP(name, "lua") == 0)
4520 n = lua_enabled(FALSE);
4521#endif
4522#ifdef DYNAMIC_MZSCHEME
4523 else if (STRICMP(name, "mzscheme") == 0)
4524 n = mzscheme_enabled(FALSE);
4525#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004526#ifdef DYNAMIC_PERL
4527 else if (STRICMP(name, "perl") == 0)
4528 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004529#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004530#ifdef DYNAMIC_PYTHON
4531 else if (STRICMP(name, "python") == 0)
4532 n = python_enabled(FALSE);
4533#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534#ifdef DYNAMIC_PYTHON3
4535 else if (STRICMP(name, "python3") == 0)
4536 n = python3_enabled(FALSE);
4537#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004538#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4539 else if (STRICMP(name, "pythonx") == 0)
4540 {
4541# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4542 if (p_pyx == 0)
4543 n = python3_enabled(FALSE) || python_enabled(FALSE);
4544 else if (p_pyx == 3)
4545 n = python3_enabled(FALSE);
4546 else if (p_pyx == 2)
4547 n = python_enabled(FALSE);
4548# elif defined(DYNAMIC_PYTHON)
4549 n = python_enabled(FALSE);
4550# elif defined(DYNAMIC_PYTHON3)
4551 n = python3_enabled(FALSE);
4552# endif
4553 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004554#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004555#ifdef DYNAMIC_RUBY
4556 else if (STRICMP(name, "ruby") == 0)
4557 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004558#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004559#ifdef DYNAMIC_TCL
4560 else if (STRICMP(name, "tcl") == 0)
4561 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004562#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004563#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004564 else if (STRICMP(name, "terminal") == 0)
4565 n = terminal_enabled();
4566#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004567 }
4568
Bram Moolenaar79296512020-03-22 16:17:14 +01004569 // features not in has_list[]
4570 if (x == FALSE)
4571 {
4572 if (STRNICMP(name, "patch", 5) == 0)
4573 {
4574 x = TRUE;
4575 if (name[5] == '-'
4576 && STRLEN(name) >= 11
4577 && vim_isdigit(name[6])
4578 && vim_isdigit(name[8])
4579 && vim_isdigit(name[10]))
4580 {
4581 int major = atoi((char *)name + 6);
4582 int minor = atoi((char *)name + 8);
4583
4584 // Expect "patch-9.9.01234".
4585 n = (major < VIM_VERSION_MAJOR
4586 || (major == VIM_VERSION_MAJOR
4587 && (minor < VIM_VERSION_MINOR
4588 || (minor == VIM_VERSION_MINOR
4589 && has_patch(atoi((char *)name + 10))))));
4590 }
4591 else
4592 n = has_patch(atoi((char *)name + 5));
4593 }
4594 else if (STRICMP(name, "vim_starting") == 0)
4595 {
4596 x = TRUE;
4597 n = (starting != 0);
4598 }
4599 else if (STRICMP(name, "ttyin") == 0)
4600 {
4601 x = TRUE;
4602 n = mch_input_isatty();
4603 }
4604 else if (STRICMP(name, "ttyout") == 0)
4605 {
4606 x = TRUE;
4607 n = stdout_isatty;
4608 }
4609 else if (STRICMP(name, "multi_byte_encoding") == 0)
4610 {
4611 x = TRUE;
4612 n = has_mbyte;
4613 }
4614 else if (STRICMP(name, "gui_running") == 0)
4615 {
4616 x = TRUE;
4617#ifdef FEAT_GUI
4618 n = (gui.in_use || gui.starting);
4619#endif
4620 }
4621 else if (STRICMP(name, "browse") == 0)
4622 {
4623 x = TRUE;
4624#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4625 n = gui.in_use; // gui_mch_browse() works when GUI is running
4626#endif
4627 }
4628 else if (STRICMP(name, "syntax_items") == 0)
4629 {
4630 x = TRUE;
4631#ifdef FEAT_SYN_HL
4632 n = syntax_present(curwin);
4633#endif
4634 }
4635 else if (STRICMP(name, "vcon") == 0)
4636 {
4637 x = TRUE;
4638#ifdef FEAT_VTP
4639 n = is_term_win32() && has_vtp_working();
4640#endif
4641 }
4642 else if (STRICMP(name, "netbeans_enabled") == 0)
4643 {
4644 x = TRUE;
4645#ifdef FEAT_NETBEANS_INTG
4646 n = netbeans_active();
4647#endif
4648 }
4649 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4650 {
4651 x = TRUE;
4652#ifdef FEAT_MOUSE_GPM
4653 n = gpm_enabled();
4654#endif
4655 }
4656 else if (STRICMP(name, "conpty") == 0)
4657 {
4658 x = TRUE;
4659#if defined(FEAT_TERMINAL) && defined(MSWIN)
4660 n = use_conpty();
4661#endif
4662 }
4663 else if (STRICMP(name, "clipboard_working") == 0)
4664 {
4665 x = TRUE;
4666#ifdef FEAT_CLIPBOARD
4667 n = clip_star.available;
4668#endif
4669 }
4670 }
4671
4672 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4673 // return whether feature could ever be enabled
4674 rettv->vval.v_number = x;
4675 else
4676 // return whether feature is enabled
4677 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004678}
4679
4680/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004681 * "haslocaldir()" function
4682 */
4683 static void
4684f_haslocaldir(typval_T *argvars, typval_T *rettv)
4685{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004686 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004687 win_T *wp = NULL;
4688
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004689 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4690
4691 // Check for window-local and tab-local directories
4692 if (wp != NULL && wp->w_localdir != NULL)
4693 rettv->vval.v_number = 1;
4694 else if (tp != NULL && tp->tp_localdir != NULL)
4695 rettv->vval.v_number = 2;
4696 else
4697 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004698}
4699
4700/*
4701 * "hasmapto()" function
4702 */
4703 static void
4704f_hasmapto(typval_T *argvars, typval_T *rettv)
4705{
4706 char_u *name;
4707 char_u *mode;
4708 char_u buf[NUMBUFLEN];
4709 int abbr = FALSE;
4710
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004711 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004712 if (argvars[1].v_type == VAR_UNKNOWN)
4713 mode = (char_u *)"nvo";
4714 else
4715 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004716 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004718 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719 }
4720
4721 if (map_to_exists(name, mode, abbr))
4722 rettv->vval.v_number = TRUE;
4723 else
4724 rettv->vval.v_number = FALSE;
4725}
4726
4727/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004728 * "highlightID(name)" function
4729 */
4730 static void
4731f_hlID(typval_T *argvars, typval_T *rettv)
4732{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004733 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734}
4735
4736/*
4737 * "highlight_exists()" function
4738 */
4739 static void
4740f_hlexists(typval_T *argvars, typval_T *rettv)
4741{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004742 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004743}
4744
4745/*
4746 * "hostname()" function
4747 */
4748 static void
4749f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4750{
4751 char_u hostname[256];
4752
4753 mch_get_host_name(hostname, 256);
4754 rettv->v_type = VAR_STRING;
4755 rettv->vval.v_string = vim_strsave(hostname);
4756}
4757
4758/*
4759 * iconv() function
4760 */
4761 static void
4762f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4763{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004764 char_u buf1[NUMBUFLEN];
4765 char_u buf2[NUMBUFLEN];
4766 char_u *from, *to, *str;
4767 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768
4769 rettv->v_type = VAR_STRING;
4770 rettv->vval.v_string = NULL;
4771
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004772 str = tv_get_string(&argvars[0]);
4773 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4774 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004775 vimconv.vc_type = CONV_NONE;
4776 convert_setup(&vimconv, from, to);
4777
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004778 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004779 if (vimconv.vc_type == CONV_NONE)
4780 rettv->vval.v_string = vim_strsave(str);
4781 else
4782 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4783
4784 convert_setup(&vimconv, NULL, NULL);
4785 vim_free(from);
4786 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787}
4788
4789/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004790 * "index()" function
4791 */
4792 static void
4793f_index(typval_T *argvars, typval_T *rettv)
4794{
4795 list_T *l;
4796 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004797 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004798 long idx = 0;
4799 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004800 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004801
4802 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004803 if (argvars[0].v_type == VAR_BLOB)
4804 {
4805 typval_T tv;
4806 int start = 0;
4807
4808 if (argvars[2].v_type != VAR_UNKNOWN)
4809 {
4810 start = tv_get_number_chk(&argvars[2], &error);
4811 if (error)
4812 return;
4813 }
4814 b = argvars[0].vval.v_blob;
4815 if (b == NULL)
4816 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004817 if (start < 0)
4818 {
4819 start = blob_len(b) + start;
4820 if (start < 0)
4821 start = 0;
4822 }
4823
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004824 for (idx = start; idx < blob_len(b); ++idx)
4825 {
4826 tv.v_type = VAR_NUMBER;
4827 tv.vval.v_number = blob_get(b, idx);
4828 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4829 {
4830 rettv->vval.v_number = idx;
4831 return;
4832 }
4833 }
4834 return;
4835 }
4836 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004837 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004838 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839 return;
4840 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004841
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004842 l = argvars[0].vval.v_list;
4843 if (l != NULL)
4844 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004845 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004846 item = l->lv_first;
4847 if (argvars[2].v_type != VAR_UNKNOWN)
4848 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004849 // Start at specified item. Use the cached index that list_find()
4850 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004851 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004852 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004854 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004855 if (error)
4856 item = NULL;
4857 }
4858
4859 for ( ; item != NULL; item = item->li_next, ++idx)
4860 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4861 {
4862 rettv->vval.v_number = idx;
4863 break;
4864 }
4865 }
4866}
4867
4868static int inputsecret_flag = 0;
4869
4870/*
4871 * "input()" function
4872 * Also handles inputsecret() when inputsecret is set.
4873 */
4874 static void
4875f_input(typval_T *argvars, typval_T *rettv)
4876{
4877 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4878}
4879
4880/*
4881 * "inputdialog()" function
4882 */
4883 static void
4884f_inputdialog(typval_T *argvars, typval_T *rettv)
4885{
4886#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004887 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004888 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4889 {
4890 char_u *message;
4891 char_u buf[NUMBUFLEN];
4892 char_u *defstr = (char_u *)"";
4893
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004894 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004895 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004896 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004897 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4898 else
4899 IObuff[0] = NUL;
4900 if (message != NULL && defstr != NULL
4901 && do_dialog(VIM_QUESTION, NULL, message,
4902 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4903 rettv->vval.v_string = vim_strsave(IObuff);
4904 else
4905 {
4906 if (message != NULL && defstr != NULL
4907 && argvars[1].v_type != VAR_UNKNOWN
4908 && argvars[2].v_type != VAR_UNKNOWN)
4909 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004910 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911 else
4912 rettv->vval.v_string = NULL;
4913 }
4914 rettv->v_type = VAR_STRING;
4915 }
4916 else
4917#endif
4918 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4919}
4920
4921/*
4922 * "inputlist()" function
4923 */
4924 static void
4925f_inputlist(typval_T *argvars, typval_T *rettv)
4926{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004927 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004928 listitem_T *li;
4929 int selected;
4930 int mouse_used;
4931
4932#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004933 // While starting up, there is no place to enter text. When running tests
4934 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004935 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004936 return;
4937#endif
4938 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4939 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004940 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004941 return;
4942 }
4943
4944 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004945 msg_row = Rows - 1; // for when 'cmdheight' > 1
4946 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 msg_scroll = TRUE;
4948 msg_clr_eos();
4949
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004950 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004951 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02004952 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004953 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004954 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955 msg_putchar('\n');
4956 }
4957
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004958 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004959 selected = prompt_for_number(&mouse_used);
4960 if (mouse_used)
4961 selected -= lines_left;
4962
4963 rettv->vval.v_number = selected;
4964}
4965
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004966static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4967
4968/*
4969 * "inputrestore()" function
4970 */
4971 static void
4972f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4973{
4974 if (ga_userinput.ga_len > 0)
4975 {
4976 --ga_userinput.ga_len;
4977 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4978 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004979 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004980 }
4981 else if (p_verbose > 1)
4982 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004983 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004984 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004985 }
4986}
4987
4988/*
4989 * "inputsave()" function
4990 */
4991 static void
4992f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4993{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004994 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004995 if (ga_grow(&ga_userinput, 1) == OK)
4996 {
4997 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4998 + ga_userinput.ga_len);
4999 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005000 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005001 }
5002 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005003 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005004}
5005
5006/*
5007 * "inputsecret()" function
5008 */
5009 static void
5010f_inputsecret(typval_T *argvars, typval_T *rettv)
5011{
5012 ++cmdline_star;
5013 ++inputsecret_flag;
5014 f_input(argvars, rettv);
5015 --cmdline_star;
5016 --inputsecret_flag;
5017}
5018
5019/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005020 * "interrupt()" function
5021 */
5022 static void
5023f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5024{
5025 got_int = TRUE;
5026}
5027
5028/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005029 * "invert(expr)" function
5030 */
5031 static void
5032f_invert(typval_T *argvars, typval_T *rettv)
5033{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005034 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035}
5036
5037/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005038 * "islocked()" function
5039 */
5040 static void
5041f_islocked(typval_T *argvars, typval_T *rettv)
5042{
5043 lval_T lv;
5044 char_u *end;
5045 dictitem_T *di;
5046
5047 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005048 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005049 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005050 if (end != NULL && lv.ll_name != NULL)
5051 {
5052 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005053 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005054 else
5055 {
5056 if (lv.ll_tv == NULL)
5057 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005058 di = find_var(lv.ll_name, NULL, TRUE);
5059 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005061 // Consider a variable locked when:
5062 // 1. the variable itself is locked
5063 // 2. the value of the variable is locked.
5064 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005065 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5066 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005067 }
5068 }
5069 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005070 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005071 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005072 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005073 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005074 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5076 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005077 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005078 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5079 }
5080 }
5081
5082 clear_lval(&lv);
5083}
5084
5085#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5086/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005087 * "isinf()" function
5088 */
5089 static void
5090f_isinf(typval_T *argvars, typval_T *rettv)
5091{
5092 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5093 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5094}
5095
5096/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097 * "isnan()" function
5098 */
5099 static void
5100f_isnan(typval_T *argvars, typval_T *rettv)
5101{
5102 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5103 && isnan(argvars[0].vval.v_float);
5104}
5105#endif
5106
5107/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108 * "last_buffer_nr()" function.
5109 */
5110 static void
5111f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5112{
5113 int n = 0;
5114 buf_T *buf;
5115
Bram Moolenaar29323592016-07-24 22:04:11 +02005116 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 if (n < buf->b_fnum)
5118 n = buf->b_fnum;
5119
5120 rettv->vval.v_number = n;
5121}
5122
5123/*
5124 * "len()" function
5125 */
5126 static void
5127f_len(typval_T *argvars, typval_T *rettv)
5128{
5129 switch (argvars[0].v_type)
5130 {
5131 case VAR_STRING:
5132 case VAR_NUMBER:
5133 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005134 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005136 case VAR_BLOB:
5137 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5138 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005139 case VAR_LIST:
5140 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5141 break;
5142 case VAR_DICT:
5143 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5144 break;
5145 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005146 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005147 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005148 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005149 case VAR_SPECIAL:
5150 case VAR_FLOAT:
5151 case VAR_FUNC:
5152 case VAR_PARTIAL:
5153 case VAR_JOB:
5154 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005155 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005156 break;
5157 }
5158}
5159
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005160 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005161libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005162{
5163#ifdef FEAT_LIBCALL
5164 char_u *string_in;
5165 char_u **string_result;
5166 int nr_result;
5167#endif
5168
5169 rettv->v_type = type;
5170 if (type != VAR_NUMBER)
5171 rettv->vval.v_string = NULL;
5172
5173 if (check_restricted() || check_secure())
5174 return;
5175
5176#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005177 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005178 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5179 {
5180 string_in = NULL;
5181 if (argvars[2].v_type == VAR_STRING)
5182 string_in = argvars[2].vval.v_string;
5183 if (type == VAR_NUMBER)
5184 string_result = NULL;
5185 else
5186 string_result = &rettv->vval.v_string;
5187 if (mch_libcall(argvars[0].vval.v_string,
5188 argvars[1].vval.v_string,
5189 string_in,
5190 argvars[2].vval.v_number,
5191 string_result,
5192 &nr_result) == OK
5193 && type == VAR_NUMBER)
5194 rettv->vval.v_number = nr_result;
5195 }
5196#endif
5197}
5198
5199/*
5200 * "libcall()" function
5201 */
5202 static void
5203f_libcall(typval_T *argvars, typval_T *rettv)
5204{
5205 libcall_common(argvars, rettv, VAR_STRING);
5206}
5207
5208/*
5209 * "libcallnr()" function
5210 */
5211 static void
5212f_libcallnr(typval_T *argvars, typval_T *rettv)
5213{
5214 libcall_common(argvars, rettv, VAR_NUMBER);
5215}
5216
5217/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005218 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005219 */
5220 static void
5221f_line(typval_T *argvars, typval_T *rettv)
5222{
5223 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005224 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005225 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005226 int id;
5227 tabpage_T *tp;
5228 win_T *wp;
5229 win_T *save_curwin;
5230 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005231
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005232 if (argvars[1].v_type != VAR_UNKNOWN)
5233 {
5234 // use window specified in the second argument
5235 id = (int)tv_get_number(&argvars[1]);
5236 wp = win_id2wp_tp(id, &tp);
5237 if (wp != NULL && tp != NULL)
5238 {
5239 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5240 == OK)
5241 {
5242 check_cursor();
5243 fp = var2fpos(&argvars[0], TRUE, &fnum);
5244 }
5245 restore_win_noblock(save_curwin, save_curtab, TRUE);
5246 }
5247 }
5248 else
5249 // use current window
5250 fp = var2fpos(&argvars[0], TRUE, &fnum);
5251
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005252 if (fp != NULL)
5253 lnum = fp->lnum;
5254 rettv->vval.v_number = lnum;
5255}
5256
5257/*
5258 * "line2byte(lnum)" function
5259 */
5260 static void
5261f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5262{
5263#ifndef FEAT_BYTEOFF
5264 rettv->vval.v_number = -1;
5265#else
5266 linenr_T lnum;
5267
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005268 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005269 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5270 rettv->vval.v_number = -1;
5271 else
5272 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5273 if (rettv->vval.v_number >= 0)
5274 ++rettv->vval.v_number;
5275#endif
5276}
5277
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005278#ifdef FEAT_FLOAT
5279/*
5280 * "log()" function
5281 */
5282 static void
5283f_log(typval_T *argvars, typval_T *rettv)
5284{
5285 float_T f = 0.0;
5286
5287 rettv->v_type = VAR_FLOAT;
5288 if (get_float_arg(argvars, &f) == OK)
5289 rettv->vval.v_float = log(f);
5290 else
5291 rettv->vval.v_float = 0.0;
5292}
5293
5294/*
5295 * "log10()" function
5296 */
5297 static void
5298f_log10(typval_T *argvars, typval_T *rettv)
5299{
5300 float_T f = 0.0;
5301
5302 rettv->v_type = VAR_FLOAT;
5303 if (get_float_arg(argvars, &f) == OK)
5304 rettv->vval.v_float = log10(f);
5305 else
5306 rettv->vval.v_float = 0.0;
5307}
5308#endif
5309
5310#ifdef FEAT_LUA
5311/*
5312 * "luaeval()" function
5313 */
5314 static void
5315f_luaeval(typval_T *argvars, typval_T *rettv)
5316{
5317 char_u *str;
5318 char_u buf[NUMBUFLEN];
5319
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005320 if (check_restricted() || check_secure())
5321 return;
5322
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005323 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005324 do_luaeval(str, argvars + 1, rettv);
5325}
5326#endif
5327
5328/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005329 * "maparg()" function
5330 */
5331 static void
5332f_maparg(typval_T *argvars, typval_T *rettv)
5333{
5334 get_maparg(argvars, rettv, TRUE);
5335}
5336
5337/*
5338 * "mapcheck()" function
5339 */
5340 static void
5341f_mapcheck(typval_T *argvars, typval_T *rettv)
5342{
5343 get_maparg(argvars, rettv, FALSE);
5344}
5345
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005346typedef enum
5347{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005348 MATCH_END, // matchend()
5349 MATCH_MATCH, // match()
5350 MATCH_STR, // matchstr()
5351 MATCH_LIST, // matchlist()
5352 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005353} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005354
5355 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005356find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005357{
5358 char_u *str = NULL;
5359 long len = 0;
5360 char_u *expr = NULL;
5361 char_u *pat;
5362 regmatch_T regmatch;
5363 char_u patbuf[NUMBUFLEN];
5364 char_u strbuf[NUMBUFLEN];
5365 char_u *save_cpo;
5366 long start = 0;
5367 long nth = 1;
5368 colnr_T startcol = 0;
5369 int match = 0;
5370 list_T *l = NULL;
5371 listitem_T *li = NULL;
5372 long idx = 0;
5373 char_u *tofree = NULL;
5374
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005375 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005376 save_cpo = p_cpo;
5377 p_cpo = (char_u *)"";
5378
5379 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005380 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005381 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005382 // type MATCH_LIST: return empty list when there are no matches.
5383 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005384 if (rettv_list_alloc(rettv) == FAIL)
5385 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005386 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005387 && (list_append_string(rettv->vval.v_list,
5388 (char_u *)"", 0) == FAIL
5389 || list_append_number(rettv->vval.v_list,
5390 (varnumber_T)-1) == FAIL
5391 || list_append_number(rettv->vval.v_list,
5392 (varnumber_T)-1) == FAIL
5393 || list_append_number(rettv->vval.v_list,
5394 (varnumber_T)-1) == FAIL))
5395 {
5396 list_free(rettv->vval.v_list);
5397 rettv->vval.v_list = NULL;
5398 goto theend;
5399 }
5400 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005401 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005402 {
5403 rettv->v_type = VAR_STRING;
5404 rettv->vval.v_string = NULL;
5405 }
5406
5407 if (argvars[0].v_type == VAR_LIST)
5408 {
5409 if ((l = argvars[0].vval.v_list) == NULL)
5410 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005411 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005412 li = l->lv_first;
5413 }
5414 else
5415 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005416 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 len = (long)STRLEN(str);
5418 }
5419
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005420 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005421 if (pat == NULL)
5422 goto theend;
5423
5424 if (argvars[2].v_type != VAR_UNKNOWN)
5425 {
5426 int error = FALSE;
5427
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005428 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005429 if (error)
5430 goto theend;
5431 if (l != NULL)
5432 {
5433 li = list_find(l, start);
5434 if (li == NULL)
5435 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005436 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005437 }
5438 else
5439 {
5440 if (start < 0)
5441 start = 0;
5442 if (start > len)
5443 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005444 // When "count" argument is there ignore matches before "start",
5445 // otherwise skip part of the string. Differs when pattern is "^"
5446 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005447 if (argvars[3].v_type != VAR_UNKNOWN)
5448 startcol = start;
5449 else
5450 {
5451 str += start;
5452 len -= start;
5453 }
5454 }
5455
5456 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005457 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005458 if (error)
5459 goto theend;
5460 }
5461
5462 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5463 if (regmatch.regprog != NULL)
5464 {
5465 regmatch.rm_ic = p_ic;
5466
5467 for (;;)
5468 {
5469 if (l != NULL)
5470 {
5471 if (li == NULL)
5472 {
5473 match = FALSE;
5474 break;
5475 }
5476 vim_free(tofree);
5477 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5478 if (str == NULL)
5479 break;
5480 }
5481
5482 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5483
5484 if (match && --nth <= 0)
5485 break;
5486 if (l == NULL && !match)
5487 break;
5488
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005489 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005490 if (l != NULL)
5491 {
5492 li = li->li_next;
5493 ++idx;
5494 }
5495 else
5496 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005497 startcol = (colnr_T)(regmatch.startp[0]
5498 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005499 if (startcol > (colnr_T)len
5500 || str + startcol <= regmatch.startp[0])
5501 {
5502 match = FALSE;
5503 break;
5504 }
5505 }
5506 }
5507
5508 if (match)
5509 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005510 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511 {
5512 listitem_T *li1 = rettv->vval.v_list->lv_first;
5513 listitem_T *li2 = li1->li_next;
5514 listitem_T *li3 = li2->li_next;
5515 listitem_T *li4 = li3->li_next;
5516
5517 vim_free(li1->li_tv.vval.v_string);
5518 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5519 (int)(regmatch.endp[0] - regmatch.startp[0]));
5520 li3->li_tv.vval.v_number =
5521 (varnumber_T)(regmatch.startp[0] - expr);
5522 li4->li_tv.vval.v_number =
5523 (varnumber_T)(regmatch.endp[0] - expr);
5524 if (l != NULL)
5525 li2->li_tv.vval.v_number = (varnumber_T)idx;
5526 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005527 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005528 {
5529 int i;
5530
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005531 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005532 for (i = 0; i < NSUBEXP; ++i)
5533 {
5534 if (regmatch.endp[i] == NULL)
5535 {
5536 if (list_append_string(rettv->vval.v_list,
5537 (char_u *)"", 0) == FAIL)
5538 break;
5539 }
5540 else if (list_append_string(rettv->vval.v_list,
5541 regmatch.startp[i],
5542 (int)(regmatch.endp[i] - regmatch.startp[i]))
5543 == FAIL)
5544 break;
5545 }
5546 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005547 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005549 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005550 if (l != NULL)
5551 copy_tv(&li->li_tv, rettv);
5552 else
5553 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
5554 (int)(regmatch.endp[0] - regmatch.startp[0]));
5555 }
5556 else if (l != NULL)
5557 rettv->vval.v_number = idx;
5558 else
5559 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005560 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005561 rettv->vval.v_number =
5562 (varnumber_T)(regmatch.startp[0] - str);
5563 else
5564 rettv->vval.v_number =
5565 (varnumber_T)(regmatch.endp[0] - str);
5566 rettv->vval.v_number += (varnumber_T)(str - expr);
5567 }
5568 }
5569 vim_regfree(regmatch.regprog);
5570 }
5571
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005572theend:
5573 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005574 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005575 listitem_remove(rettv->vval.v_list,
5576 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 vim_free(tofree);
5578 p_cpo = save_cpo;
5579}
5580
5581/*
5582 * "match()" function
5583 */
5584 static void
5585f_match(typval_T *argvars, typval_T *rettv)
5586{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005587 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005588}
5589
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005590/*
5591 * "matchend()" function
5592 */
5593 static void
5594f_matchend(typval_T *argvars, typval_T *rettv)
5595{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005596 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005597}
5598
5599/*
5600 * "matchlist()" function
5601 */
5602 static void
5603f_matchlist(typval_T *argvars, typval_T *rettv)
5604{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005605 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005606}
5607
5608/*
5609 * "matchstr()" function
5610 */
5611 static void
5612f_matchstr(typval_T *argvars, typval_T *rettv)
5613{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005614 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005615}
5616
5617/*
5618 * "matchstrpos()" function
5619 */
5620 static void
5621f_matchstrpos(typval_T *argvars, typval_T *rettv)
5622{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005623 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005624}
5625
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005626 static void
5627max_min(typval_T *argvars, typval_T *rettv, int domax)
5628{
5629 varnumber_T n = 0;
5630 varnumber_T i;
5631 int error = FALSE;
5632
5633 if (argvars[0].v_type == VAR_LIST)
5634 {
5635 list_T *l;
5636 listitem_T *li;
5637
5638 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005639 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005640 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005641 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005643 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5644 n = l->lv_u.nonmat.lv_start;
5645 else
5646 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5647 * l->lv_u.nonmat.lv_stride;
5648 }
5649 else
5650 {
5651 li = l->lv_first;
5652 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005653 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005654 n = tv_get_number_chk(&li->li_tv, &error);
5655 for (;;)
5656 {
5657 li = li->li_next;
5658 if (li == NULL)
5659 break;
5660 i = tv_get_number_chk(&li->li_tv, &error);
5661 if (domax ? i > n : i < n)
5662 n = i;
5663 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005664 }
5665 }
5666 }
5667 }
5668 else if (argvars[0].v_type == VAR_DICT)
5669 {
5670 dict_T *d;
5671 int first = TRUE;
5672 hashitem_T *hi;
5673 int todo;
5674
5675 d = argvars[0].vval.v_dict;
5676 if (d != NULL)
5677 {
5678 todo = (int)d->dv_hashtab.ht_used;
5679 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5680 {
5681 if (!HASHITEM_EMPTY(hi))
5682 {
5683 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005684 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685 if (first)
5686 {
5687 n = i;
5688 first = FALSE;
5689 }
5690 else if (domax ? i > n : i < n)
5691 n = i;
5692 }
5693 }
5694 }
5695 }
5696 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005697 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005698 rettv->vval.v_number = error ? 0 : n;
5699}
5700
5701/*
5702 * "max()" function
5703 */
5704 static void
5705f_max(typval_T *argvars, typval_T *rettv)
5706{
5707 max_min(argvars, rettv, TRUE);
5708}
5709
5710/*
5711 * "min()" function
5712 */
5713 static void
5714f_min(typval_T *argvars, typval_T *rettv)
5715{
5716 max_min(argvars, rettv, FALSE);
5717}
5718
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005719#if defined(FEAT_MZSCHEME) || defined(PROTO)
5720/*
5721 * "mzeval()" function
5722 */
5723 static void
5724f_mzeval(typval_T *argvars, typval_T *rettv)
5725{
5726 char_u *str;
5727 char_u buf[NUMBUFLEN];
5728
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005729 if (check_restricted() || check_secure())
5730 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005731 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005732 do_mzeval(str, rettv);
5733}
5734
5735 void
5736mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5737{
5738 typval_T argvars[3];
5739
5740 argvars[0].v_type = VAR_STRING;
5741 argvars[0].vval.v_string = name;
5742 copy_tv(args, &argvars[1]);
5743 argvars[2].v_type = VAR_UNKNOWN;
5744 f_call(argvars, rettv);
5745 clear_tv(&argvars[1]);
5746}
5747#endif
5748
5749/*
5750 * "nextnonblank()" function
5751 */
5752 static void
5753f_nextnonblank(typval_T *argvars, typval_T *rettv)
5754{
5755 linenr_T lnum;
5756
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005757 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005758 {
5759 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5760 {
5761 lnum = 0;
5762 break;
5763 }
5764 if (*skipwhite(ml_get(lnum)) != NUL)
5765 break;
5766 }
5767 rettv->vval.v_number = lnum;
5768}
5769
5770/*
5771 * "nr2char()" function
5772 */
5773 static void
5774f_nr2char(typval_T *argvars, typval_T *rettv)
5775{
5776 char_u buf[NUMBUFLEN];
5777
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005778 if (has_mbyte)
5779 {
5780 int utf8 = 0;
5781
5782 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005783 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005784 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005785 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005786 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005787 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005788 }
5789 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005791 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 buf[1] = NUL;
5793 }
5794 rettv->v_type = VAR_STRING;
5795 rettv->vval.v_string = vim_strsave(buf);
5796}
5797
5798/*
5799 * "or(expr, expr)" function
5800 */
5801 static void
5802f_or(typval_T *argvars, typval_T *rettv)
5803{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005804 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5805 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005806}
5807
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808#ifdef FEAT_PERL
5809/*
5810 * "perleval()" function
5811 */
5812 static void
5813f_perleval(typval_T *argvars, typval_T *rettv)
5814{
5815 char_u *str;
5816 char_u buf[NUMBUFLEN];
5817
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005818 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005819 do_perleval(str, rettv);
5820}
5821#endif
5822
5823#ifdef FEAT_FLOAT
5824/*
5825 * "pow()" function
5826 */
5827 static void
5828f_pow(typval_T *argvars, typval_T *rettv)
5829{
5830 float_T fx = 0.0, fy = 0.0;
5831
5832 rettv->v_type = VAR_FLOAT;
5833 if (get_float_arg(argvars, &fx) == OK
5834 && get_float_arg(&argvars[1], &fy) == OK)
5835 rettv->vval.v_float = pow(fx, fy);
5836 else
5837 rettv->vval.v_float = 0.0;
5838}
5839#endif
5840
5841/*
5842 * "prevnonblank()" function
5843 */
5844 static void
5845f_prevnonblank(typval_T *argvars, typval_T *rettv)
5846{
5847 linenr_T lnum;
5848
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005849 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5851 lnum = 0;
5852 else
5853 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5854 --lnum;
5855 rettv->vval.v_number = lnum;
5856}
5857
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005858// This dummy va_list is here because:
5859// - passing a NULL pointer doesn't work when va_list isn't a pointer
5860// - locally in the function results in a "used before set" warning
5861// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005862static va_list ap;
5863
5864/*
5865 * "printf()" function
5866 */
5867 static void
5868f_printf(typval_T *argvars, typval_T *rettv)
5869{
5870 char_u buf[NUMBUFLEN];
5871 int len;
5872 char_u *s;
5873 int saved_did_emsg = did_emsg;
5874 char *fmt;
5875
5876 rettv->v_type = VAR_STRING;
5877 rettv->vval.v_string = NULL;
5878
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005879 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005880 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005881 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005882 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005883 if (!did_emsg)
5884 {
5885 s = alloc(len + 1);
5886 if (s != NULL)
5887 {
5888 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005889 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5890 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005891 }
5892 }
5893 did_emsg |= saved_did_emsg;
5894}
5895
5896/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005897 * "pum_getpos()" function
5898 */
5899 static void
5900f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5901{
5902 if (rettv_dict_alloc(rettv) != OK)
5903 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005904 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005905}
5906
5907/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005908 * "pumvisible()" function
5909 */
5910 static void
5911f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5912{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005913 if (pum_visible())
5914 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005915}
5916
5917#ifdef FEAT_PYTHON3
5918/*
5919 * "py3eval()" function
5920 */
5921 static void
5922f_py3eval(typval_T *argvars, typval_T *rettv)
5923{
5924 char_u *str;
5925 char_u buf[NUMBUFLEN];
5926
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005927 if (check_restricted() || check_secure())
5928 return;
5929
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005930 if (p_pyx == 0)
5931 p_pyx = 3;
5932
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005933 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005934 do_py3eval(str, rettv);
5935}
5936#endif
5937
5938#ifdef FEAT_PYTHON
5939/*
5940 * "pyeval()" function
5941 */
5942 static void
5943f_pyeval(typval_T *argvars, typval_T *rettv)
5944{
5945 char_u *str;
5946 char_u buf[NUMBUFLEN];
5947
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005948 if (check_restricted() || check_secure())
5949 return;
5950
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005951 if (p_pyx == 0)
5952 p_pyx = 2;
5953
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005954 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005955 do_pyeval(str, rettv);
5956}
5957#endif
5958
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005959#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5960/*
5961 * "pyxeval()" function
5962 */
5963 static void
5964f_pyxeval(typval_T *argvars, typval_T *rettv)
5965{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005966 if (check_restricted() || check_secure())
5967 return;
5968
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005969# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5970 init_pyxversion();
5971 if (p_pyx == 2)
5972 f_pyeval(argvars, rettv);
5973 else
5974 f_py3eval(argvars, rettv);
5975# elif defined(FEAT_PYTHON)
5976 f_pyeval(argvars, rettv);
5977# elif defined(FEAT_PYTHON3)
5978 f_py3eval(argvars, rettv);
5979# endif
5980}
5981#endif
5982
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005983static UINT32_T srand_seed_for_testing = 0;
5984static int srand_seed_for_testing_is_used = FALSE;
5985
5986 static void
5987f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5988{
5989 if (argvars[0].v_type == VAR_UNKNOWN)
5990 srand_seed_for_testing_is_used = FALSE;
5991 else
5992 {
5993 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5994 srand_seed_for_testing_is_used = TRUE;
5995 }
5996}
5997
5998 static void
5999init_srand(UINT32_T *x)
6000{
6001#ifndef MSWIN
6002 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6003#endif
6004
6005 if (srand_seed_for_testing_is_used)
6006 {
6007 *x = srand_seed_for_testing;
6008 return;
6009 }
6010#ifndef MSWIN
6011 if (dev_urandom_state != FAIL)
6012 {
6013 int fd = open("/dev/urandom", O_RDONLY);
6014 struct {
6015 union {
6016 UINT32_T number;
6017 char bytes[sizeof(UINT32_T)];
6018 } contents;
6019 } buf;
6020
6021 // Attempt reading /dev/urandom.
6022 if (fd == -1)
6023 dev_urandom_state = FAIL;
6024 else
6025 {
6026 buf.contents.number = 0;
6027 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6028 != sizeof(UINT32_T))
6029 dev_urandom_state = FAIL;
6030 else
6031 {
6032 dev_urandom_state = OK;
6033 *x = buf.contents.number;
6034 }
6035 close(fd);
6036 }
6037 }
6038 if (dev_urandom_state != OK)
6039 // Reading /dev/urandom doesn't work, fall back to time().
6040#endif
6041 *x = vim_time();
6042}
6043
6044#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6045#define SPLITMIX32(x, z) ( \
6046 z = (x += 0x9e3779b9), \
6047 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6048 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6049 z ^ (z >> 16) \
6050 )
6051#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6052 result = ROTL(y * 5, 7) * 9; \
6053 t = y << 9; \
6054 z ^= x; \
6055 w ^= y; \
6056 y ^= z, x ^= w; \
6057 z ^= t; \
6058 w = ROTL(w, 11);
6059
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006060/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006061 * "rand()" function
6062 */
6063 static void
6064f_rand(typval_T *argvars, typval_T *rettv)
6065{
6066 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006067 static UINT32_T gx, gy, gz, gw;
6068 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006069 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006070 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006071
6072 if (argvars[0].v_type == VAR_UNKNOWN)
6073 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006074 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006075 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006076 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006077 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006078 init_srand(&x);
6079
6080 gx = SPLITMIX32(x, z);
6081 gy = SPLITMIX32(x, z);
6082 gz = SPLITMIX32(x, z);
6083 gw = SPLITMIX32(x, z);
6084 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006085 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006086
6087 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006088 }
6089 else if (argvars[0].v_type == VAR_LIST)
6090 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006091 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006092 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006093 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006094
6095 lx = list_find(l, 0L);
6096 ly = list_find(l, 1L);
6097 lz = list_find(l, 2L);
6098 lw = list_find(l, 3L);
6099 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6100 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6101 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6102 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6103 x = (UINT32_T)lx->li_tv.vval.v_number;
6104 y = (UINT32_T)ly->li_tv.vval.v_number;
6105 z = (UINT32_T)lz->li_tv.vval.v_number;
6106 w = (UINT32_T)lw->li_tv.vval.v_number;
6107
6108 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6109
6110 lx->li_tv.vval.v_number = (varnumber_T)x;
6111 ly->li_tv.vval.v_number = (varnumber_T)y;
6112 lz->li_tv.vval.v_number = (varnumber_T)z;
6113 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006114 }
6115 else
6116 goto theend;
6117
6118 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006119 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006120 return;
6121
6122theend:
6123 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006124 rettv->v_type = VAR_NUMBER;
6125 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006126}
6127
6128/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006129 * "srand()" function
6130 */
6131 static void
6132f_srand(typval_T *argvars, typval_T *rettv)
6133{
6134 UINT32_T x = 0, z;
6135
6136 if (rettv_list_alloc(rettv) == FAIL)
6137 return;
6138 if (argvars[0].v_type == VAR_UNKNOWN)
6139 {
6140 init_srand(&x);
6141 }
6142 else
6143 {
6144 int error = FALSE;
6145
6146 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6147 if (error)
6148 return;
6149 }
6150
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 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6155}
6156
6157#undef ROTL
6158#undef SPLITMIX32
6159#undef SHUFFLE_XOSHIRO128STARSTAR
6160
6161/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006162 * "range()" function
6163 */
6164 static void
6165f_range(typval_T *argvars, typval_T *rettv)
6166{
6167 varnumber_T start;
6168 varnumber_T end;
6169 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006170 int error = FALSE;
6171
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006172 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006173 if (argvars[1].v_type == VAR_UNKNOWN)
6174 {
6175 end = start - 1;
6176 start = 0;
6177 }
6178 else
6179 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006180 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006181 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006182 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183 }
6184
6185 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006186 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006187 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006188 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006189 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006190 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006191 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006192 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006193 list_T *list = rettv->vval.v_list;
6194
6195 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006196 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006197 // be called.
6198 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006199 list->lv_u.nonmat.lv_start = start;
6200 list->lv_u.nonmat.lv_end = end;
6201 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006202 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006203 }
6204}
6205
6206/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006207 * Materialize "list".
6208 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006209 */
6210 void
6211range_list_materialize(list_T *list)
6212{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006213 varnumber_T start = list->lv_u.nonmat.lv_start;
6214 varnumber_T end = list->lv_u.nonmat.lv_end;
6215 int stride = list->lv_u.nonmat.lv_stride;
6216 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006217
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006218 list->lv_first = NULL;
6219 list->lv_u.mat.lv_last = NULL;
6220 list->lv_len = 0;
6221 list->lv_u.mat.lv_idx_item = NULL;
6222 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6223 if (list_append_number(list, (varnumber_T)i) == FAIL)
6224 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006225}
6226
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006227 static void
6228return_register(int regname, typval_T *rettv)
6229{
6230 char_u buf[2] = {0, 0};
6231
6232 buf[0] = (char_u)regname;
6233 rettv->v_type = VAR_STRING;
6234 rettv->vval.v_string = vim_strsave(buf);
6235}
6236
6237/*
6238 * "reg_executing()" function
6239 */
6240 static void
6241f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6242{
6243 return_register(reg_executing, rettv);
6244}
6245
6246/*
6247 * "reg_recording()" function
6248 */
6249 static void
6250f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6251{
6252 return_register(reg_recording, rettv);
6253}
6254
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006255/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006256 * "rename({from}, {to})" function
6257 */
6258 static void
6259f_rename(typval_T *argvars, typval_T *rettv)
6260{
6261 char_u buf[NUMBUFLEN];
6262
6263 if (check_restricted() || check_secure())
6264 rettv->vval.v_number = -1;
6265 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006266 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6267 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268}
6269
6270/*
6271 * "repeat()" function
6272 */
6273 static void
6274f_repeat(typval_T *argvars, typval_T *rettv)
6275{
6276 char_u *p;
6277 int n;
6278 int slen;
6279 int len;
6280 char_u *r;
6281 int i;
6282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006283 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006284 if (argvars[0].v_type == VAR_LIST)
6285 {
6286 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6287 while (n-- > 0)
6288 if (list_extend(rettv->vval.v_list,
6289 argvars[0].vval.v_list, NULL) == FAIL)
6290 break;
6291 }
6292 else
6293 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006294 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006295 rettv->v_type = VAR_STRING;
6296 rettv->vval.v_string = NULL;
6297
6298 slen = (int)STRLEN(p);
6299 len = slen * n;
6300 if (len <= 0)
6301 return;
6302
6303 r = alloc(len + 1);
6304 if (r != NULL)
6305 {
6306 for (i = 0; i < n; i++)
6307 mch_memmove(r + i * slen, p, (size_t)slen);
6308 r[len] = NUL;
6309 }
6310
6311 rettv->vval.v_string = r;
6312 }
6313}
6314
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006315#define SP_NOMOVE 0x01 // don't move cursor
6316#define SP_REPEAT 0x02 // repeat to find outer pair
6317#define SP_RETCOUNT 0x04 // return matchcount
6318#define SP_SETPCMARK 0x08 // set previous context mark
6319#define SP_START 0x10 // accept match at start position
6320#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6321#define SP_END 0x40 // leave cursor at end of match
6322#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006324/*
6325 * Get flags for a search function.
6326 * Possibly sets "p_ws".
6327 * Returns BACKWARD, FORWARD or zero (for an error).
6328 */
6329 static int
6330get_search_arg(typval_T *varp, int *flagsp)
6331{
6332 int dir = FORWARD;
6333 char_u *flags;
6334 char_u nbuf[NUMBUFLEN];
6335 int mask;
6336
6337 if (varp->v_type != VAR_UNKNOWN)
6338 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006339 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006340 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006341 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006342 while (*flags != NUL)
6343 {
6344 switch (*flags)
6345 {
6346 case 'b': dir = BACKWARD; break;
6347 case 'w': p_ws = TRUE; break;
6348 case 'W': p_ws = FALSE; break;
6349 default: mask = 0;
6350 if (flagsp != NULL)
6351 switch (*flags)
6352 {
6353 case 'c': mask = SP_START; break;
6354 case 'e': mask = SP_END; break;
6355 case 'm': mask = SP_RETCOUNT; break;
6356 case 'n': mask = SP_NOMOVE; break;
6357 case 'p': mask = SP_SUBPAT; break;
6358 case 'r': mask = SP_REPEAT; break;
6359 case 's': mask = SP_SETPCMARK; break;
6360 case 'z': mask = SP_COLUMN; break;
6361 }
6362 if (mask == 0)
6363 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006364 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365 dir = 0;
6366 }
6367 else
6368 *flagsp |= mask;
6369 }
6370 if (dir == 0)
6371 break;
6372 ++flags;
6373 }
6374 }
6375 return dir;
6376}
6377
6378/*
6379 * Shared by search() and searchpos() functions.
6380 */
6381 static int
6382search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6383{
6384 int flags;
6385 char_u *pat;
6386 pos_T pos;
6387 pos_T save_cursor;
6388 int save_p_ws = p_ws;
6389 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006390 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006391 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006393 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394 long time_limit = 0;
6395#endif
6396 int options = SEARCH_KEEP;
6397 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006398 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006399
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006400 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006401 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006402 if (dir == 0)
6403 goto theend;
6404 flags = *flagsp;
6405 if (flags & SP_START)
6406 options |= SEARCH_START;
6407 if (flags & SP_END)
6408 options |= SEARCH_END;
6409 if (flags & SP_COLUMN)
6410 options |= SEARCH_COL;
6411
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006412 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006413 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006415 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 if (lnum_stop < 0)
6417 goto theend;
6418#ifdef FEAT_RELTIME
6419 if (argvars[3].v_type != VAR_UNKNOWN)
6420 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006421 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422 if (time_limit < 0)
6423 goto theend;
6424 }
6425#endif
6426 }
6427
6428#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006429 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430 profile_setlimit(time_limit, &tm);
6431#endif
6432
6433 /*
6434 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6435 * Check to make sure only those flags are set.
6436 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6437 * flags cannot be set. Check for that condition also.
6438 */
6439 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6440 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6441 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006442 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443 goto theend;
6444 }
6445
6446 pos = save_cursor = curwin->w_cursor;
Bram Moolenaara80faa82020-04-12 19:37:17 +02006447 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006448 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6449#ifdef FEAT_RELTIME
6450 sia.sa_tm = &tm;
6451#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006452 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006453 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006454 if (subpatnum != FAIL)
6455 {
6456 if (flags & SP_SUBPAT)
6457 retval = subpatnum;
6458 else
6459 retval = pos.lnum;
6460 if (flags & SP_SETPCMARK)
6461 setpcmark();
6462 curwin->w_cursor = pos;
6463 if (match_pos != NULL)
6464 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006465 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466 match_pos->lnum = pos.lnum;
6467 match_pos->col = pos.col + 1;
6468 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006469 // "/$" will put the cursor after the end of the line, may need to
6470 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006471 check_cursor();
6472 }
6473
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006474 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 if (flags & SP_NOMOVE)
6476 curwin->w_cursor = save_cursor;
6477 else
6478 curwin->w_set_curswant = TRUE;
6479theend:
6480 p_ws = save_p_ws;
6481
6482 return retval;
6483}
6484
6485#ifdef FEAT_FLOAT
6486
6487/*
6488 * round() is not in C90, use ceil() or floor() instead.
6489 */
6490 float_T
6491vim_round(float_T f)
6492{
6493 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6494}
6495
6496/*
6497 * "round({float})" function
6498 */
6499 static void
6500f_round(typval_T *argvars, typval_T *rettv)
6501{
6502 float_T f = 0.0;
6503
6504 rettv->v_type = VAR_FLOAT;
6505 if (get_float_arg(argvars, &f) == OK)
6506 rettv->vval.v_float = vim_round(f);
6507 else
6508 rettv->vval.v_float = 0.0;
6509}
6510#endif
6511
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006512#ifdef FEAT_RUBY
6513/*
6514 * "rubyeval()" function
6515 */
6516 static void
6517f_rubyeval(typval_T *argvars, typval_T *rettv)
6518{
6519 char_u *str;
6520 char_u buf[NUMBUFLEN];
6521
6522 str = tv_get_string_buf(&argvars[0], buf);
6523 do_rubyeval(str, rettv);
6524}
6525#endif
6526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527/*
6528 * "screenattr()" function
6529 */
6530 static void
6531f_screenattr(typval_T *argvars, typval_T *rettv)
6532{
6533 int row;
6534 int col;
6535 int c;
6536
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006537 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6538 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 if (row < 0 || row >= screen_Rows
6540 || col < 0 || col >= screen_Columns)
6541 c = -1;
6542 else
6543 c = ScreenAttrs[LineOffset[row] + col];
6544 rettv->vval.v_number = c;
6545}
6546
6547/*
6548 * "screenchar()" function
6549 */
6550 static void
6551f_screenchar(typval_T *argvars, typval_T *rettv)
6552{
6553 int row;
6554 int col;
6555 int off;
6556 int c;
6557
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006558 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6559 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006560 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006561 c = -1;
6562 else
6563 {
6564 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006565 if (enc_utf8 && ScreenLinesUC[off] != 0)
6566 c = ScreenLinesUC[off];
6567 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568 c = ScreenLines[off];
6569 }
6570 rettv->vval.v_number = c;
6571}
6572
6573/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006574 * "screenchars()" function
6575 */
6576 static void
6577f_screenchars(typval_T *argvars, typval_T *rettv)
6578{
6579 int row;
6580 int col;
6581 int off;
6582 int c;
6583 int i;
6584
6585 if (rettv_list_alloc(rettv) == FAIL)
6586 return;
6587 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6588 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6589 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6590 return;
6591
6592 off = LineOffset[row] + col;
6593 if (enc_utf8 && ScreenLinesUC[off] != 0)
6594 c = ScreenLinesUC[off];
6595 else
6596 c = ScreenLines[off];
6597 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6598
6599 if (enc_utf8)
6600
6601 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6602 list_append_number(rettv->vval.v_list,
6603 (varnumber_T)ScreenLinesC[i][off]);
6604}
6605
6606/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006607 * "screencol()" function
6608 *
6609 * First column is 1 to be consistent with virtcol().
6610 */
6611 static void
6612f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6613{
6614 rettv->vval.v_number = screen_screencol() + 1;
6615}
6616
6617/*
6618 * "screenrow()" function
6619 */
6620 static void
6621f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6622{
6623 rettv->vval.v_number = screen_screenrow() + 1;
6624}
6625
6626/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006627 * "screenstring()" function
6628 */
6629 static void
6630f_screenstring(typval_T *argvars, typval_T *rettv)
6631{
6632 int row;
6633 int col;
6634 int off;
6635 int c;
6636 int i;
6637 char_u buf[MB_MAXBYTES + 1];
6638 int buflen = 0;
6639
6640 rettv->vval.v_string = NULL;
6641 rettv->v_type = VAR_STRING;
6642
6643 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6644 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6645 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6646 return;
6647
6648 off = LineOffset[row] + col;
6649 if (enc_utf8 && ScreenLinesUC[off] != 0)
6650 c = ScreenLinesUC[off];
6651 else
6652 c = ScreenLines[off];
6653 buflen += mb_char2bytes(c, buf);
6654
6655 if (enc_utf8)
6656 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6657 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6658
6659 buf[buflen] = NUL;
6660 rettv->vval.v_string = vim_strsave(buf);
6661}
6662
6663/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006664 * "search()" function
6665 */
6666 static void
6667f_search(typval_T *argvars, typval_T *rettv)
6668{
6669 int flags = 0;
6670
6671 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6672}
6673
6674/*
6675 * "searchdecl()" function
6676 */
6677 static void
6678f_searchdecl(typval_T *argvars, typval_T *rettv)
6679{
6680 int locally = 1;
6681 int thisblock = 0;
6682 int error = FALSE;
6683 char_u *name;
6684
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006685 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006687 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688 if (argvars[1].v_type != VAR_UNKNOWN)
6689 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006690 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006691 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006692 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693 }
6694 if (!error && name != NULL)
6695 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6696 locally, thisblock, SEARCH_KEEP) == FAIL;
6697}
6698
6699/*
6700 * Used by searchpair() and searchpairpos()
6701 */
6702 static int
6703searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6704{
6705 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006706 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006707 int save_p_ws = p_ws;
6708 int dir;
6709 int flags = 0;
6710 char_u nbuf1[NUMBUFLEN];
6711 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006712 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006713 long lnum_stop = 0;
6714 long time_limit = 0;
6715
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006716 // Get the three pattern arguments: start, middle, end. Will result in an
6717 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006718 spat = tv_get_string_chk(&argvars[0]);
6719 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6720 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006721 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006722 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006723
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006724 // Handle the optional fourth argument: flags
6725 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 if (dir == 0)
6727 goto theend;
6728
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006729 // Don't accept SP_END or SP_SUBPAT.
6730 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006731 if ((flags & (SP_END | SP_SUBPAT)) != 0
6732 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6733 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006734 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006735 goto theend;
6736 }
6737
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006738 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 if (flags & SP_REPEAT)
6740 p_ws = FALSE;
6741
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006742 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006743 if (argvars[3].v_type == VAR_UNKNOWN
6744 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006745 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746 else
6747 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006748 skip = &argvars[4];
6749 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6750 && skip->v_type != VAR_STRING)
6751 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006752 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006753 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006754 goto theend;
6755 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006756 if (argvars[5].v_type != VAR_UNKNOWN)
6757 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006758 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006760 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006761 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006762 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006763 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006764#ifdef FEAT_RELTIME
6765 if (argvars[6].v_type != VAR_UNKNOWN)
6766 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006767 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006769 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006770 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006771 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006772 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 }
6774#endif
6775 }
6776 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006777
6778 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6779 match_pos, lnum_stop, time_limit);
6780
6781theend:
6782 p_ws = save_p_ws;
6783
6784 return retval;
6785}
6786
6787/*
6788 * "searchpair()" function
6789 */
6790 static void
6791f_searchpair(typval_T *argvars, typval_T *rettv)
6792{
6793 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6794}
6795
6796/*
6797 * "searchpairpos()" function
6798 */
6799 static void
6800f_searchpairpos(typval_T *argvars, typval_T *rettv)
6801{
6802 pos_T match_pos;
6803 int lnum = 0;
6804 int col = 0;
6805
6806 if (rettv_list_alloc(rettv) == FAIL)
6807 return;
6808
6809 if (searchpair_cmn(argvars, &match_pos) > 0)
6810 {
6811 lnum = match_pos.lnum;
6812 col = match_pos.col;
6813 }
6814
6815 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6816 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6817}
6818
6819/*
6820 * Search for a start/middle/end thing.
6821 * Used by searchpair(), see its documentation for the details.
6822 * Returns 0 or -1 for no match,
6823 */
6824 long
6825do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006826 char_u *spat, // start pattern
6827 char_u *mpat, // middle pattern
6828 char_u *epat, // end pattern
6829 int dir, // BACKWARD or FORWARD
6830 typval_T *skip, // skip expression
6831 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006832 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006833 linenr_T lnum_stop, // stop at this line if not zero
6834 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006835{
6836 char_u *save_cpo;
6837 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6838 long retval = 0;
6839 pos_T pos;
6840 pos_T firstpos;
6841 pos_T foundpos;
6842 pos_T save_cursor;
6843 pos_T save_pos;
6844 int n;
6845 int r;
6846 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006847 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006848 int err;
6849 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006850#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006852#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006853
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006854 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006855 save_cpo = p_cpo;
6856 p_cpo = empty_option;
6857
6858#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006859 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006860 profile_setlimit(time_limit, &tm);
6861#endif
6862
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006863 // Make two search patterns: start/end (pat2, for in nested pairs) and
6864 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006865 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6866 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006867 if (pat2 == NULL || pat3 == NULL)
6868 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006869 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870 if (*mpat == NUL)
6871 STRCPY(pat3, pat2);
6872 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006873 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874 spat, epat, mpat);
6875 if (flags & SP_START)
6876 options |= SEARCH_START;
6877
Bram Moolenaar48570482017-10-30 21:48:41 +01006878 if (skip != NULL)
6879 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006880 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006881 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6882 use_skip = skip->vval.v_string != NULL
6883 && *skip->vval.v_string != NUL;
6884 }
6885
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006886 save_cursor = curwin->w_cursor;
6887 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006888 CLEAR_POS(&firstpos);
6889 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006890 pat = pat3;
6891 for (;;)
6892 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006893 searchit_arg_T sia;
6894
Bram Moolenaara80faa82020-04-12 19:37:17 +02006895 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006896 sia.sa_stop_lnum = lnum_stop;
6897#ifdef FEAT_RELTIME
6898 sia.sa_tm = &tm;
6899#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006900 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006901 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006902 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006903 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006904 break;
6905
6906 if (firstpos.lnum == 0)
6907 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006908 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006909 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006910 // Found the same position again. Can happen with a pattern that
6911 // has "\zs" at the end and searching backwards. Advance one
6912 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006913 if (dir == BACKWARD)
6914 decl(&pos);
6915 else
6916 incl(&pos);
6917 }
6918 foundpos = pos;
6919
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006920 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006921 options &= ~SEARCH_START;
6922
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006923 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006924 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006925 {
6926 save_pos = curwin->w_cursor;
6927 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006928 err = FALSE;
6929 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006930 curwin->w_cursor = save_pos;
6931 if (err)
6932 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006933 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006934 curwin->w_cursor = save_cursor;
6935 retval = -1;
6936 break;
6937 }
6938 if (r)
6939 continue;
6940 }
6941
6942 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6943 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006944 // Found end when searching backwards or start when searching
6945 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006946 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006947 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 }
6949 else
6950 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006951 // Found end when searching forward or start when searching
6952 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006953 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006954 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006955 }
6956
6957 if (nest == 0)
6958 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006959 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960 if (flags & SP_RETCOUNT)
6961 ++retval;
6962 else
6963 retval = pos.lnum;
6964 if (flags & SP_SETPCMARK)
6965 setpcmark();
6966 curwin->w_cursor = pos;
6967 if (!(flags & SP_REPEAT))
6968 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006969 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 }
6971 }
6972
6973 if (match_pos != NULL)
6974 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006975 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006976 match_pos->lnum = curwin->w_cursor.lnum;
6977 match_pos->col = curwin->w_cursor.col + 1;
6978 }
6979
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006980 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981 if ((flags & SP_NOMOVE) || retval == 0)
6982 curwin->w_cursor = save_cursor;
6983
6984theend:
6985 vim_free(pat2);
6986 vim_free(pat3);
6987 if (p_cpo == empty_option)
6988 p_cpo = save_cpo;
6989 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006990 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991 free_string_option(save_cpo);
6992
6993 return retval;
6994}
6995
6996/*
6997 * "searchpos()" function
6998 */
6999 static void
7000f_searchpos(typval_T *argvars, typval_T *rettv)
7001{
7002 pos_T match_pos;
7003 int lnum = 0;
7004 int col = 0;
7005 int n;
7006 int flags = 0;
7007
7008 if (rettv_list_alloc(rettv) == FAIL)
7009 return;
7010
7011 n = search_cmn(argvars, &match_pos, &flags);
7012 if (n > 0)
7013 {
7014 lnum = match_pos.lnum;
7015 col = match_pos.col;
7016 }
7017
7018 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7019 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7020 if (flags & SP_SUBPAT)
7021 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7022}
7023
7024 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7026{
7027 dict_T *d;
7028 dictitem_T *di;
7029 char_u *csearch;
7030
7031 if (argvars[0].v_type != VAR_DICT)
7032 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007033 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 return;
7035 }
7036
7037 if ((d = argvars[0].vval.v_dict) != NULL)
7038 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007039 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007040 if (csearch != NULL)
7041 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007042 if (enc_utf8)
7043 {
7044 int pcc[MAX_MCO];
7045 int c = utfc_ptr2char(csearch, pcc);
7046
7047 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7048 }
7049 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007050 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007051 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007052 }
7053
7054 di = dict_find(d, (char_u *)"forward", -1);
7055 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007056 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007057 ? FORWARD : BACKWARD);
7058
7059 di = dict_find(d, (char_u *)"until", -1);
7060 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007061 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 }
7063}
7064
7065/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007066 * "setenv()" function
7067 */
7068 static void
7069f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7070{
7071 char_u namebuf[NUMBUFLEN];
7072 char_u valbuf[NUMBUFLEN];
7073 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7074
7075 if (argvars[1].v_type == VAR_SPECIAL
7076 && argvars[1].vval.v_number == VVAL_NULL)
7077 vim_unsetenv(name);
7078 else
7079 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7080}
7081
7082/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007083 * "setfperm({fname}, {mode})" function
7084 */
7085 static void
7086f_setfperm(typval_T *argvars, typval_T *rettv)
7087{
7088 char_u *fname;
7089 char_u modebuf[NUMBUFLEN];
7090 char_u *mode_str;
7091 int i;
7092 int mask;
7093 int mode = 0;
7094
7095 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007096 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007097 if (fname == NULL)
7098 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007099 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007100 if (mode_str == NULL)
7101 return;
7102 if (STRLEN(mode_str) != 9)
7103 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007104 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007105 return;
7106 }
7107
7108 mask = 1;
7109 for (i = 8; i >= 0; --i)
7110 {
7111 if (mode_str[i] != '-')
7112 mode |= mask;
7113 mask = mask << 1;
7114 }
7115 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7116}
7117
7118/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119 * "setpos()" function
7120 */
7121 static void
7122f_setpos(typval_T *argvars, typval_T *rettv)
7123{
7124 pos_T pos;
7125 int fnum;
7126 char_u *name;
7127 colnr_T curswant = -1;
7128
7129 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007130 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 if (name != NULL)
7132 {
7133 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7134 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007135 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 pos.col = 0;
7137 if (name[0] == '.' && name[1] == NUL)
7138 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007139 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007140 curwin->w_cursor = pos;
7141 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007143 curwin->w_curswant = curswant - 1;
7144 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007145 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007146 check_cursor();
7147 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 }
7149 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7150 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007151 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007152 if (setmark_pos(name[1], &pos, fnum) == OK)
7153 rettv->vval.v_number = 0;
7154 }
7155 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007156 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007157 }
7158 }
7159}
7160
7161/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007162 * "setreg()" function
7163 */
7164 static void
7165f_setreg(typval_T *argvars, typval_T *rettv)
7166{
7167 int regname;
7168 char_u *strregname;
7169 char_u *stropt;
7170 char_u *strval;
7171 int append;
7172 char_u yank_type;
7173 long block_len;
7174
7175 block_len = -1;
7176 yank_type = MAUTO;
7177 append = FALSE;
7178
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007179 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007180 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007181
7182 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007183 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007184 regname = *strregname;
7185 if (regname == 0 || regname == '@')
7186 regname = '"';
7187
7188 if (argvars[2].v_type != VAR_UNKNOWN)
7189 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007190 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007191 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007192 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007193 for (; *stropt != NUL; ++stropt)
7194 switch (*stropt)
7195 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007196 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 append = TRUE;
7198 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007199 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007200 yank_type = MCHAR;
7201 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007202 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007203 yank_type = MLINE;
7204 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007205 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 yank_type = MBLOCK;
7207 if (VIM_ISDIGIT(stropt[1]))
7208 {
7209 ++stropt;
7210 block_len = getdigits(&stropt) - 1;
7211 --stropt;
7212 }
7213 break;
7214 }
7215 }
7216
7217 if (argvars[1].v_type == VAR_LIST)
7218 {
7219 char_u **lstval;
7220 char_u **allocval;
7221 char_u buf[NUMBUFLEN];
7222 char_u **curval;
7223 char_u **curallocval;
7224 list_T *ll = argvars[1].vval.v_list;
7225 listitem_T *li;
7226 int len;
7227
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007228 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229 len = ll == NULL ? 0 : ll->lv_len;
7230
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007231 // First half: use for pointers to result lines; second half: use for
7232 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007233 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007234 if (lstval == NULL)
7235 return;
7236 curval = lstval;
7237 allocval = lstval + len + 2;
7238 curallocval = allocval;
7239
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007240 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007241 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007242 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007243 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007244 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007245 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007246 if (strval == NULL)
7247 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007248 if (strval == buf)
7249 {
7250 // Need to make a copy, next tv_get_string_buf_chk() will
7251 // overwrite the string.
7252 strval = vim_strsave(buf);
7253 if (strval == NULL)
7254 goto free_lstval;
7255 *curallocval++ = strval;
7256 }
7257 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007259 }
7260 *curval++ = NULL;
7261
7262 write_reg_contents_lst(regname, lstval, -1,
7263 append, yank_type, block_len);
7264free_lstval:
7265 while (curallocval > allocval)
7266 vim_free(*--curallocval);
7267 vim_free(lstval);
7268 }
7269 else
7270 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007271 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007272 if (strval == NULL)
7273 return;
7274 write_reg_contents_ex(regname, strval, -1,
7275 append, yank_type, block_len);
7276 }
7277 rettv->vval.v_number = 0;
7278}
7279
7280/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007281 * "settagstack()" function
7282 */
7283 static void
7284f_settagstack(typval_T *argvars, typval_T *rettv)
7285{
7286 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7287 win_T *wp;
7288 dict_T *d;
7289 int action = 'r';
7290
7291 rettv->vval.v_number = -1;
7292
7293 // first argument: window number or id
7294 wp = find_win_by_nr_or_id(&argvars[0]);
7295 if (wp == NULL)
7296 return;
7297
7298 // second argument: dict with items to set in the tag stack
7299 if (argvars[1].v_type != VAR_DICT)
7300 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007301 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007302 return;
7303 }
7304 d = argvars[1].vval.v_dict;
7305 if (d == NULL)
7306 return;
7307
7308 // third argument: action - 'a' for append and 'r' for replace.
7309 // default is to replace the stack.
7310 if (argvars[2].v_type == VAR_UNKNOWN)
7311 action = 'r';
7312 else if (argvars[2].v_type == VAR_STRING)
7313 {
7314 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007315 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007316 if (actstr == NULL)
7317 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007318 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7319 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007320 action = *actstr;
7321 else
7322 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007323 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007324 return;
7325 }
7326 }
7327 else
7328 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007329 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007330 return;
7331 }
7332
7333 if (set_tagstack(wp, d, action) == OK)
7334 rettv->vval.v_number = 0;
7335}
7336
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007337#ifdef FEAT_CRYPT
7338/*
7339 * "sha256({string})" function
7340 */
7341 static void
7342f_sha256(typval_T *argvars, typval_T *rettv)
7343{
7344 char_u *p;
7345
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007346 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347 rettv->vval.v_string = vim_strsave(
7348 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7349 rettv->v_type = VAR_STRING;
7350}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007351#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007352
7353/*
7354 * "shellescape({string})" function
7355 */
7356 static void
7357f_shellescape(typval_T *argvars, typval_T *rettv)
7358{
Bram Moolenaar20615522017-06-05 18:46:26 +02007359 int do_special = non_zero_arg(&argvars[1]);
7360
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007361 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007362 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007363 rettv->v_type = VAR_STRING;
7364}
7365
7366/*
7367 * shiftwidth() function
7368 */
7369 static void
7370f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7371{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007372 rettv->vval.v_number = 0;
7373
7374 if (argvars[0].v_type != VAR_UNKNOWN)
7375 {
7376 long col;
7377
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007378 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007379 if (col < 0)
7380 return; // type error; errmsg already given
7381#ifdef FEAT_VARTABS
7382 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7383 return;
7384#endif
7385 }
7386
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 rettv->vval.v_number = get_sw_value(curbuf);
7388}
7389
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007390#ifdef FEAT_FLOAT
7391/*
7392 * "sin()" function
7393 */
7394 static void
7395f_sin(typval_T *argvars, typval_T *rettv)
7396{
7397 float_T f = 0.0;
7398
7399 rettv->v_type = VAR_FLOAT;
7400 if (get_float_arg(argvars, &f) == OK)
7401 rettv->vval.v_float = sin(f);
7402 else
7403 rettv->vval.v_float = 0.0;
7404}
7405
7406/*
7407 * "sinh()" function
7408 */
7409 static void
7410f_sinh(typval_T *argvars, typval_T *rettv)
7411{
7412 float_T f = 0.0;
7413
7414 rettv->v_type = VAR_FLOAT;
7415 if (get_float_arg(argvars, &f) == OK)
7416 rettv->vval.v_float = sinh(f);
7417 else
7418 rettv->vval.v_float = 0.0;
7419}
7420#endif
7421
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007422/*
7423 * "soundfold({word})" function
7424 */
7425 static void
7426f_soundfold(typval_T *argvars, typval_T *rettv)
7427{
7428 char_u *s;
7429
7430 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007431 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432#ifdef FEAT_SPELL
7433 rettv->vval.v_string = eval_soundfold(s);
7434#else
7435 rettv->vval.v_string = vim_strsave(s);
7436#endif
7437}
7438
7439/*
7440 * "spellbadword()" function
7441 */
7442 static void
7443f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7444{
7445 char_u *word = (char_u *)"";
7446 hlf_T attr = HLF_COUNT;
7447 int len = 0;
7448
7449 if (rettv_list_alloc(rettv) == FAIL)
7450 return;
7451
7452#ifdef FEAT_SPELL
7453 if (argvars[0].v_type == VAR_UNKNOWN)
7454 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007455 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007456 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7457 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007458 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007459 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007460 curwin->w_set_curswant = TRUE;
7461 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007462 }
7463 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7464 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007465 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007466 int capcol = -1;
7467
7468 if (str != NULL)
7469 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007470 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 while (*str != NUL)
7472 {
7473 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7474 if (attr != HLF_COUNT)
7475 {
7476 word = str;
7477 break;
7478 }
7479 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007480 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007481 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007482 }
7483 }
7484 }
7485#endif
7486
7487 list_append_string(rettv->vval.v_list, word, len);
7488 list_append_string(rettv->vval.v_list, (char_u *)(
7489 attr == HLF_SPB ? "bad" :
7490 attr == HLF_SPR ? "rare" :
7491 attr == HLF_SPL ? "local" :
7492 attr == HLF_SPC ? "caps" :
7493 ""), -1);
7494}
7495
7496/*
7497 * "spellsuggest()" function
7498 */
7499 static void
7500f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7501{
7502#ifdef FEAT_SPELL
7503 char_u *str;
7504 int typeerr = FALSE;
7505 int maxcount;
7506 garray_T ga;
7507 int i;
7508 listitem_T *li;
7509 int need_capital = FALSE;
7510#endif
7511
7512 if (rettv_list_alloc(rettv) == FAIL)
7513 return;
7514
7515#ifdef FEAT_SPELL
7516 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7517 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007518 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519 if (argvars[1].v_type != VAR_UNKNOWN)
7520 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007521 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 if (maxcount <= 0)
7523 return;
7524 if (argvars[2].v_type != VAR_UNKNOWN)
7525 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007526 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527 if (typeerr)
7528 return;
7529 }
7530 }
7531 else
7532 maxcount = 25;
7533
7534 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7535
7536 for (i = 0; i < ga.ga_len; ++i)
7537 {
7538 str = ((char_u **)ga.ga_data)[i];
7539
7540 li = listitem_alloc();
7541 if (li == NULL)
7542 vim_free(str);
7543 else
7544 {
7545 li->li_tv.v_type = VAR_STRING;
7546 li->li_tv.v_lock = 0;
7547 li->li_tv.vval.v_string = str;
7548 list_append(rettv->vval.v_list, li);
7549 }
7550 }
7551 ga_clear(&ga);
7552 }
7553#endif
7554}
7555
7556 static void
7557f_split(typval_T *argvars, typval_T *rettv)
7558{
7559 char_u *str;
7560 char_u *end;
7561 char_u *pat = NULL;
7562 regmatch_T regmatch;
7563 char_u patbuf[NUMBUFLEN];
7564 char_u *save_cpo;
7565 int match;
7566 colnr_T col = 0;
7567 int keepempty = FALSE;
7568 int typeerr = FALSE;
7569
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007570 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007571 save_cpo = p_cpo;
7572 p_cpo = (char_u *)"";
7573
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007574 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575 if (argvars[1].v_type != VAR_UNKNOWN)
7576 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007577 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007578 if (pat == NULL)
7579 typeerr = TRUE;
7580 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007581 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007582 }
7583 if (pat == NULL || *pat == NUL)
7584 pat = (char_u *)"[\\x01- ]\\+";
7585
7586 if (rettv_list_alloc(rettv) == FAIL)
7587 return;
7588 if (typeerr)
7589 return;
7590
7591 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7592 if (regmatch.regprog != NULL)
7593 {
7594 regmatch.rm_ic = FALSE;
7595 while (*str != NUL || keepempty)
7596 {
7597 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007598 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007599 else
7600 match = vim_regexec_nl(&regmatch, str, col);
7601 if (match)
7602 end = regmatch.startp[0];
7603 else
7604 end = str + STRLEN(str);
7605 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7606 && *str != NUL && match && end < regmatch.endp[0]))
7607 {
7608 if (list_append_string(rettv->vval.v_list, str,
7609 (int)(end - str)) == FAIL)
7610 break;
7611 }
7612 if (!match)
7613 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007614 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007615 if (regmatch.endp[0] > str)
7616 col = 0;
7617 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007618 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007620 str = regmatch.endp[0];
7621 }
7622
7623 vim_regfree(regmatch.regprog);
7624 }
7625
7626 p_cpo = save_cpo;
7627}
7628
7629#ifdef FEAT_FLOAT
7630/*
7631 * "sqrt()" function
7632 */
7633 static void
7634f_sqrt(typval_T *argvars, typval_T *rettv)
7635{
7636 float_T f = 0.0;
7637
7638 rettv->v_type = VAR_FLOAT;
7639 if (get_float_arg(argvars, &f) == OK)
7640 rettv->vval.v_float = sqrt(f);
7641 else
7642 rettv->vval.v_float = 0.0;
7643}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007644#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007645
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007646#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007647/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 * "str2float()" function
7649 */
7650 static void
7651f_str2float(typval_T *argvars, typval_T *rettv)
7652{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007653 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007654 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655
Bram Moolenaar08243d22017-01-10 16:12:29 +01007656 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657 p = skipwhite(p + 1);
7658 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007659 if (isneg)
7660 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007661 rettv->v_type = VAR_FLOAT;
7662}
7663#endif
7664
7665/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007666 * "str2list()" function
7667 */
7668 static void
7669f_str2list(typval_T *argvars, typval_T *rettv)
7670{
7671 char_u *p;
7672 int utf8 = FALSE;
7673
7674 if (rettv_list_alloc(rettv) == FAIL)
7675 return;
7676
7677 if (argvars[1].v_type != VAR_UNKNOWN)
7678 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7679
7680 p = tv_get_string(&argvars[0]);
7681
7682 if (has_mbyte || utf8)
7683 {
7684 int (*ptr2len)(char_u *);
7685 int (*ptr2char)(char_u *);
7686
7687 if (utf8 || enc_utf8)
7688 {
7689 ptr2len = utf_ptr2len;
7690 ptr2char = utf_ptr2char;
7691 }
7692 else
7693 {
7694 ptr2len = mb_ptr2len;
7695 ptr2char = mb_ptr2char;
7696 }
7697
7698 for ( ; *p != NUL; p += (*ptr2len)(p))
7699 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7700 }
7701 else
7702 for ( ; *p != NUL; ++p)
7703 list_append_number(rettv->vval.v_list, *p);
7704}
7705
7706/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007707 * "str2nr()" function
7708 */
7709 static void
7710f_str2nr(typval_T *argvars, typval_T *rettv)
7711{
7712 int base = 10;
7713 char_u *p;
7714 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007715 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007716 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717
7718 if (argvars[1].v_type != VAR_UNKNOWN)
7719 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007720 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007721 if (base != 2 && base != 8 && base != 10 && base != 16)
7722 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007723 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007724 return;
7725 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007726 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7727 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728 }
7729
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007730 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007731 isneg = (*p == '-');
7732 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007733 p = skipwhite(p + 1);
7734 switch (base)
7735 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007736 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7737 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7738 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007739 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007740 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7741 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007742 if (isneg)
7743 rettv->vval.v_number = -n;
7744 else
7745 rettv->vval.v_number = n;
7746
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747}
7748
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749/*
7750 * "strgetchar()" function
7751 */
7752 static void
7753f_strgetchar(typval_T *argvars, typval_T *rettv)
7754{
7755 char_u *str;
7756 int len;
7757 int error = FALSE;
7758 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007759 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007760
7761 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007762 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007763 if (str == NULL)
7764 return;
7765 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007766 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767 if (error)
7768 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007769
Bram Moolenaar13505972019-01-24 15:04:48 +01007770 while (charidx >= 0 && byteidx < len)
7771 {
7772 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007773 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007774 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7775 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007777 --charidx;
7778 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007779 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780}
7781
7782/*
7783 * "stridx()" function
7784 */
7785 static void
7786f_stridx(typval_T *argvars, typval_T *rettv)
7787{
7788 char_u buf[NUMBUFLEN];
7789 char_u *needle;
7790 char_u *haystack;
7791 char_u *save_haystack;
7792 char_u *pos;
7793 int start_idx;
7794
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007795 needle = tv_get_string_chk(&argvars[1]);
7796 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007797 rettv->vval.v_number = -1;
7798 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007799 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007800
7801 if (argvars[2].v_type != VAR_UNKNOWN)
7802 {
7803 int error = FALSE;
7804
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007805 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007806 if (error || start_idx >= (int)STRLEN(haystack))
7807 return;
7808 if (start_idx >= 0)
7809 haystack += start_idx;
7810 }
7811
7812 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7813 if (pos != NULL)
7814 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7815}
7816
7817/*
7818 * "string()" function
7819 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007820 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007821f_string(typval_T *argvars, typval_T *rettv)
7822{
7823 char_u *tofree;
7824 char_u numbuf[NUMBUFLEN];
7825
7826 rettv->v_type = VAR_STRING;
7827 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7828 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007829 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007830 if (rettv->vval.v_string != NULL && tofree == NULL)
7831 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7832}
7833
7834/*
7835 * "strlen()" function
7836 */
7837 static void
7838f_strlen(typval_T *argvars, typval_T *rettv)
7839{
7840 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007841 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007842}
7843
7844/*
7845 * "strchars()" function
7846 */
7847 static void
7848f_strchars(typval_T *argvars, typval_T *rettv)
7849{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007850 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007851 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007852 varnumber_T len = 0;
7853 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854
7855 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007856 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007858 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 else
7860 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7862 while (*s != NUL)
7863 {
7864 func_mb_ptr2char_adv(&s);
7865 ++len;
7866 }
7867 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 }
7869}
7870
7871/*
7872 * "strdisplaywidth()" function
7873 */
7874 static void
7875f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7876{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007877 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007878 int col = 0;
7879
7880 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007881 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882
7883 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7884}
7885
7886/*
7887 * "strwidth()" function
7888 */
7889 static void
7890f_strwidth(typval_T *argvars, typval_T *rettv)
7891{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007892 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893
Bram Moolenaar13505972019-01-24 15:04:48 +01007894 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007895}
7896
7897/*
7898 * "strcharpart()" function
7899 */
7900 static void
7901f_strcharpart(typval_T *argvars, typval_T *rettv)
7902{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007903 char_u *p;
7904 int nchar;
7905 int nbyte = 0;
7906 int charlen;
7907 int len = 0;
7908 int slen;
7909 int error = FALSE;
7910
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007911 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007912 slen = (int)STRLEN(p);
7913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007914 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007915 if (!error)
7916 {
7917 if (nchar > 0)
7918 while (nchar > 0 && nbyte < slen)
7919 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007920 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 --nchar;
7922 }
7923 else
7924 nbyte = nchar;
7925 if (argvars[2].v_type != VAR_UNKNOWN)
7926 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007927 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007928 while (charlen > 0 && nbyte + len < slen)
7929 {
7930 int off = nbyte + len;
7931
7932 if (off < 0)
7933 len += 1;
7934 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007935 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 --charlen;
7937 }
7938 }
7939 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007940 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007941 }
7942
7943 /*
7944 * Only return the overlap between the specified part and the actual
7945 * string.
7946 */
7947 if (nbyte < 0)
7948 {
7949 len += nbyte;
7950 nbyte = 0;
7951 }
7952 else if (nbyte > slen)
7953 nbyte = slen;
7954 if (len < 0)
7955 len = 0;
7956 else if (nbyte + len > slen)
7957 len = slen - nbyte;
7958
7959 rettv->v_type = VAR_STRING;
7960 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007961}
7962
7963/*
7964 * "strpart()" function
7965 */
7966 static void
7967f_strpart(typval_T *argvars, typval_T *rettv)
7968{
7969 char_u *p;
7970 int n;
7971 int len;
7972 int slen;
7973 int error = FALSE;
7974
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007975 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976 slen = (int)STRLEN(p);
7977
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007978 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979 if (error)
7980 len = 0;
7981 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007982 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007983 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007984 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007985
7986 /*
7987 * Only return the overlap between the specified part and the actual
7988 * string.
7989 */
7990 if (n < 0)
7991 {
7992 len += n;
7993 n = 0;
7994 }
7995 else if (n > slen)
7996 n = slen;
7997 if (len < 0)
7998 len = 0;
7999 else if (n + len > slen)
8000 len = slen - n;
8001
8002 rettv->v_type = VAR_STRING;
8003 rettv->vval.v_string = vim_strnsave(p + n, len);
8004}
8005
8006/*
8007 * "strridx()" function
8008 */
8009 static void
8010f_strridx(typval_T *argvars, typval_T *rettv)
8011{
8012 char_u buf[NUMBUFLEN];
8013 char_u *needle;
8014 char_u *haystack;
8015 char_u *rest;
8016 char_u *lastmatch = NULL;
8017 int haystack_len, end_idx;
8018
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008019 needle = tv_get_string_chk(&argvars[1]);
8020 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008021
8022 rettv->vval.v_number = -1;
8023 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008024 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008025
8026 haystack_len = (int)STRLEN(haystack);
8027 if (argvars[2].v_type != VAR_UNKNOWN)
8028 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008029 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008030 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008031 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008032 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033 }
8034 else
8035 end_idx = haystack_len;
8036
8037 if (*needle == NUL)
8038 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008039 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008040 lastmatch = haystack + end_idx;
8041 }
8042 else
8043 {
8044 for (rest = haystack; *rest != '\0'; ++rest)
8045 {
8046 rest = (char_u *)strstr((char *)rest, (char *)needle);
8047 if (rest == NULL || rest > haystack + end_idx)
8048 break;
8049 lastmatch = rest;
8050 }
8051 }
8052
8053 if (lastmatch == NULL)
8054 rettv->vval.v_number = -1;
8055 else
8056 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8057}
8058
8059/*
8060 * "strtrans()" function
8061 */
8062 static void
8063f_strtrans(typval_T *argvars, typval_T *rettv)
8064{
8065 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008066 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008067}
8068
8069/*
8070 * "submatch()" function
8071 */
8072 static void
8073f_submatch(typval_T *argvars, typval_T *rettv)
8074{
8075 int error = FALSE;
8076 int no;
8077 int retList = 0;
8078
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008079 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008080 if (error)
8081 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008082 if (no < 0 || no >= NSUBEXP)
8083 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008084 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008085 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008086 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008088 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008089 if (error)
8090 return;
8091
8092 if (retList == 0)
8093 {
8094 rettv->v_type = VAR_STRING;
8095 rettv->vval.v_string = reg_submatch(no);
8096 }
8097 else
8098 {
8099 rettv->v_type = VAR_LIST;
8100 rettv->vval.v_list = reg_submatch_list(no);
8101 }
8102}
8103
8104/*
8105 * "substitute()" function
8106 */
8107 static void
8108f_substitute(typval_T *argvars, typval_T *rettv)
8109{
8110 char_u patbuf[NUMBUFLEN];
8111 char_u subbuf[NUMBUFLEN];
8112 char_u flagsbuf[NUMBUFLEN];
8113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008114 char_u *str = tv_get_string_chk(&argvars[0]);
8115 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008116 char_u *sub = NULL;
8117 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008118 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008120 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8121 expr = &argvars[2];
8122 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008123 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008124
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008125 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008126 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8127 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 rettv->vval.v_string = NULL;
8129 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008130 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008131}
8132
8133/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008134 * "swapinfo(swap_filename)" function
8135 */
8136 static void
8137f_swapinfo(typval_T *argvars, typval_T *rettv)
8138{
8139 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008140 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008141}
8142
8143/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008144 * "swapname(expr)" function
8145 */
8146 static void
8147f_swapname(typval_T *argvars, typval_T *rettv)
8148{
8149 buf_T *buf;
8150
8151 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008152 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008153 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8154 || buf->b_ml.ml_mfp->mf_fname == NULL)
8155 rettv->vval.v_string = NULL;
8156 else
8157 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8158}
8159
8160/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161 * "synID(lnum, col, trans)" function
8162 */
8163 static void
8164f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8165{
8166 int id = 0;
8167#ifdef FEAT_SYN_HL
8168 linenr_T lnum;
8169 colnr_T col;
8170 int trans;
8171 int transerr = FALSE;
8172
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008173 lnum = tv_get_lnum(argvars); // -1 on type error
8174 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008175 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176
8177 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8178 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8179 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8180#endif
8181
8182 rettv->vval.v_number = id;
8183}
8184
8185/*
8186 * "synIDattr(id, what [, mode])" function
8187 */
8188 static void
8189f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8190{
8191 char_u *p = NULL;
8192#ifdef FEAT_SYN_HL
8193 int id;
8194 char_u *what;
8195 char_u *mode;
8196 char_u modebuf[NUMBUFLEN];
8197 int modec;
8198
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008199 id = (int)tv_get_number(&argvars[0]);
8200 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201 if (argvars[2].v_type != VAR_UNKNOWN)
8202 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008203 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008204 modec = TOLOWER_ASC(mode[0]);
8205 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008206 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008207 }
8208 else
8209 {
8210#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8211 if (USE_24BIT)
8212 modec = 'g';
8213 else
8214#endif
8215 if (t_colors > 1)
8216 modec = 'c';
8217 else
8218 modec = 't';
8219 }
8220
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008221 switch (TOLOWER_ASC(what[0]))
8222 {
8223 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008224 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008226 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008227 p = highlight_has_attr(id, HL_BOLD, modec);
8228 break;
8229
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008230 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008231 p = highlight_color(id, what, modec);
8232 break;
8233
8234 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008235 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008236 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008237 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238 p = highlight_has_attr(id, HL_ITALIC, modec);
8239 break;
8240
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008241 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008242 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008243 break;
8244
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008245 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008246 p = highlight_has_attr(id, HL_INVERSE, modec);
8247 break;
8248
8249 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008250 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008251 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008252 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008253 else if (TOLOWER_ASC(what[1]) == 't' &&
8254 TOLOWER_ASC(what[2]) == 'r')
8255 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008256 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 p = highlight_has_attr(id, HL_STANDOUT, modec);
8258 break;
8259
8260 case 'u':
8261 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008262 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008263 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8264 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008265 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008266 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8267 break;
8268 }
8269
8270 if (p != NULL)
8271 p = vim_strsave(p);
8272#endif
8273 rettv->v_type = VAR_STRING;
8274 rettv->vval.v_string = p;
8275}
8276
8277/*
8278 * "synIDtrans(id)" function
8279 */
8280 static void
8281f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8282{
8283 int id;
8284
8285#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008286 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008287
8288 if (id > 0)
8289 id = syn_get_final_id(id);
8290 else
8291#endif
8292 id = 0;
8293
8294 rettv->vval.v_number = id;
8295}
8296
8297/*
8298 * "synconcealed(lnum, col)" function
8299 */
8300 static void
8301f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8302{
8303#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8304 linenr_T lnum;
8305 colnr_T col;
8306 int syntax_flags = 0;
8307 int cchar;
8308 int matchid = 0;
8309 char_u str[NUMBUFLEN];
8310#endif
8311
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008312 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008313
8314#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008315 lnum = tv_get_lnum(argvars); // -1 on type error
8316 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008317
Bram Moolenaara80faa82020-04-12 19:37:17 +02008318 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319
8320 if (rettv_list_alloc(rettv) != FAIL)
8321 {
8322 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8323 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8324 && curwin->w_p_cole > 0)
8325 {
8326 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8327 syntax_flags = get_syntax_info(&matchid);
8328
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008329 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008330 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8331 {
8332 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008333 if (cchar == NUL && curwin->w_p_cole == 1)
8334 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008335 if (cchar != NUL)
8336 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008337 if (has_mbyte)
8338 (*mb_char2bytes)(cchar, str);
8339 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008340 str[0] = cchar;
8341 }
8342 }
8343 }
8344
8345 list_append_number(rettv->vval.v_list,
8346 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008347 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008348 list_append_string(rettv->vval.v_list, str, -1);
8349 list_append_number(rettv->vval.v_list, matchid);
8350 }
8351#endif
8352}
8353
8354/*
8355 * "synstack(lnum, col)" function
8356 */
8357 static void
8358f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8359{
8360#ifdef FEAT_SYN_HL
8361 linenr_T lnum;
8362 colnr_T col;
8363 int i;
8364 int id;
8365#endif
8366
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008367 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008368
8369#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008370 lnum = tv_get_lnum(argvars); // -1 on type error
8371 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008372
8373 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8374 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8375 && rettv_list_alloc(rettv) != FAIL)
8376 {
8377 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8378 for (i = 0; ; ++i)
8379 {
8380 id = syn_get_stack_item(i);
8381 if (id < 0)
8382 break;
8383 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8384 break;
8385 }
8386 }
8387#endif
8388}
8389
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008390/*
8391 * "tabpagebuflist()" function
8392 */
8393 static void
8394f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8395{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008396 tabpage_T *tp;
8397 win_T *wp = NULL;
8398
8399 if (argvars[0].v_type == VAR_UNKNOWN)
8400 wp = firstwin;
8401 else
8402 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008403 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008404 if (tp != NULL)
8405 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8406 }
8407 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8408 {
8409 for (; wp != NULL; wp = wp->w_next)
8410 if (list_append_number(rettv->vval.v_list,
8411 wp->w_buffer->b_fnum) == FAIL)
8412 break;
8413 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008414}
8415
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008416/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008417 * "tagfiles()" function
8418 */
8419 static void
8420f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8421{
8422 char_u *fname;
8423 tagname_T tn;
8424 int first;
8425
8426 if (rettv_list_alloc(rettv) == FAIL)
8427 return;
8428 fname = alloc(MAXPATHL);
8429 if (fname == NULL)
8430 return;
8431
8432 for (first = TRUE; ; first = FALSE)
8433 if (get_tagfname(&tn, first, fname) == FAIL
8434 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8435 break;
8436 tagname_free(&tn);
8437 vim_free(fname);
8438}
8439
8440/*
8441 * "taglist()" function
8442 */
8443 static void
8444f_taglist(typval_T *argvars, typval_T *rettv)
8445{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008446 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008447 char_u *tag_pattern;
8448
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008449 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008450
8451 rettv->vval.v_number = FALSE;
8452 if (*tag_pattern == NUL)
8453 return;
8454
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008455 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008456 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008457 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008458 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459}
8460
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008461#ifdef FEAT_FLOAT
8462/*
8463 * "tan()" function
8464 */
8465 static void
8466f_tan(typval_T *argvars, typval_T *rettv)
8467{
8468 float_T f = 0.0;
8469
8470 rettv->v_type = VAR_FLOAT;
8471 if (get_float_arg(argvars, &f) == OK)
8472 rettv->vval.v_float = tan(f);
8473 else
8474 rettv->vval.v_float = 0.0;
8475}
8476
8477/*
8478 * "tanh()" function
8479 */
8480 static void
8481f_tanh(typval_T *argvars, typval_T *rettv)
8482{
8483 float_T f = 0.0;
8484
8485 rettv->v_type = VAR_FLOAT;
8486 if (get_float_arg(argvars, &f) == OK)
8487 rettv->vval.v_float = tanh(f);
8488 else
8489 rettv->vval.v_float = 0.0;
8490}
8491#endif
8492
8493/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008494 * "tolower(string)" function
8495 */
8496 static void
8497f_tolower(typval_T *argvars, typval_T *rettv)
8498{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008499 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008500 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008501}
8502
8503/*
8504 * "toupper(string)" function
8505 */
8506 static void
8507f_toupper(typval_T *argvars, typval_T *rettv)
8508{
8509 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008510 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008511}
8512
8513/*
8514 * "tr(string, fromstr, tostr)" function
8515 */
8516 static void
8517f_tr(typval_T *argvars, typval_T *rettv)
8518{
8519 char_u *in_str;
8520 char_u *fromstr;
8521 char_u *tostr;
8522 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008523 int inlen;
8524 int fromlen;
8525 int tolen;
8526 int idx;
8527 char_u *cpstr;
8528 int cplen;
8529 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530 char_u buf[NUMBUFLEN];
8531 char_u buf2[NUMBUFLEN];
8532 garray_T ga;
8533
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008534 in_str = tv_get_string(&argvars[0]);
8535 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8536 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008537
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008538 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008539 rettv->v_type = VAR_STRING;
8540 rettv->vval.v_string = NULL;
8541 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008542 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008543 ga_init2(&ga, (int)sizeof(char), 80);
8544
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008545 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008546 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547 if (STRLEN(fromstr) != STRLEN(tostr))
8548 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008549error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008550 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008551 ga_clear(&ga);
8552 return;
8553 }
8554
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008555 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008556 while (*in_str != NUL)
8557 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 if (has_mbyte)
8559 {
8560 inlen = (*mb_ptr2len)(in_str);
8561 cpstr = in_str;
8562 cplen = inlen;
8563 idx = 0;
8564 for (p = fromstr; *p != NUL; p += fromlen)
8565 {
8566 fromlen = (*mb_ptr2len)(p);
8567 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8568 {
8569 for (p = tostr; *p != NUL; p += tolen)
8570 {
8571 tolen = (*mb_ptr2len)(p);
8572 if (idx-- == 0)
8573 {
8574 cplen = tolen;
8575 cpstr = p;
8576 break;
8577 }
8578 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008579 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008580 goto error;
8581 break;
8582 }
8583 ++idx;
8584 }
8585
8586 if (first && cpstr == in_str)
8587 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008588 // Check that fromstr and tostr have the same number of
8589 // (multi-byte) characters. Done only once when a character
8590 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008591 first = FALSE;
8592 for (p = tostr; *p != NUL; p += tolen)
8593 {
8594 tolen = (*mb_ptr2len)(p);
8595 --idx;
8596 }
8597 if (idx != 0)
8598 goto error;
8599 }
8600
8601 (void)ga_grow(&ga, cplen);
8602 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8603 ga.ga_len += cplen;
8604
8605 in_str += inlen;
8606 }
8607 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008609 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008610 p = vim_strchr(fromstr, *in_str);
8611 if (p != NULL)
8612 ga_append(&ga, tostr[p - fromstr]);
8613 else
8614 ga_append(&ga, *in_str);
8615 ++in_str;
8616 }
8617 }
8618
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008619 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008620 (void)ga_grow(&ga, 1);
8621 ga_append(&ga, NUL);
8622
8623 rettv->vval.v_string = ga.ga_data;
8624}
8625
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008626/*
8627 * "trim({expr})" function
8628 */
8629 static void
8630f_trim(typval_T *argvars, typval_T *rettv)
8631{
8632 char_u buf1[NUMBUFLEN];
8633 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008634 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008635 char_u *mask = NULL;
8636 char_u *tail;
8637 char_u *prev;
8638 char_u *p;
8639 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008640 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008641
8642 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008643 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008644 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008645 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008646
8647 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008648 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008649 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008650
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008651 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008652 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008653 int error = 0;
8654
8655 // leading or trailing characters to trim
8656 dir = (int)tv_get_number_chk(&argvars[2], &error);
8657 if (error)
8658 return;
8659 if (dir < 0 || dir > 2)
8660 {
8661 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8662 return;
8663 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008664 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008665 }
8666
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008667 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008668 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008669 // Trim leading characters
8670 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008671 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008672 c1 = PTR2CHAR(head);
8673 if (mask == NULL)
8674 {
8675 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008676 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008677 }
8678 else
8679 {
8680 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8681 if (c1 == PTR2CHAR(p))
8682 break;
8683 if (*p == NUL)
8684 break;
8685 }
8686 MB_PTR_ADV(head);
8687 }
8688 }
8689
8690 tail = head + STRLEN(head);
8691 if (dir == 0 || dir == 2)
8692 {
8693 // Trim trailing characters
8694 for (; tail > head; tail = prev)
8695 {
8696 prev = tail;
8697 MB_PTR_BACK(head, prev);
8698 c1 = PTR2CHAR(prev);
8699 if (mask == NULL)
8700 {
8701 if (c1 > ' ' && c1 != 0xa0)
8702 break;
8703 }
8704 else
8705 {
8706 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8707 if (c1 == PTR2CHAR(p))
8708 break;
8709 if (*p == NUL)
8710 break;
8711 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008712 }
8713 }
8714 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8715}
8716
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008717#ifdef FEAT_FLOAT
8718/*
8719 * "trunc({float})" function
8720 */
8721 static void
8722f_trunc(typval_T *argvars, typval_T *rettv)
8723{
8724 float_T f = 0.0;
8725
8726 rettv->v_type = VAR_FLOAT;
8727 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008728 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008729 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8730 else
8731 rettv->vval.v_float = 0.0;
8732}
8733#endif
8734
8735/*
8736 * "type(expr)" function
8737 */
8738 static void
8739f_type(typval_T *argvars, typval_T *rettv)
8740{
8741 int n = -1;
8742
8743 switch (argvars[0].v_type)
8744 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008745 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8746 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008747 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008748 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8749 case VAR_LIST: n = VAR_TYPE_LIST; break;
8750 case VAR_DICT: n = VAR_TYPE_DICT; break;
8751 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8752 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8753 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008754 case VAR_JOB: n = VAR_TYPE_JOB; break;
8755 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008756 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008757 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02008758 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008759 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008760 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008761 n = -1;
8762 break;
8763 }
8764 rettv->vval.v_number = n;
8765}
8766
8767/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008768 * "virtcol(string)" function
8769 */
8770 static void
8771f_virtcol(typval_T *argvars, typval_T *rettv)
8772{
8773 colnr_T vcol = 0;
8774 pos_T *fp;
8775 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008776 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008777
8778 fp = var2fpos(&argvars[0], FALSE, &fnum);
8779 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8780 && fnum == curbuf->b_fnum)
8781 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008782 // Limit the column to a valid value, getvvcol() doesn't check.
8783 if (fp->col < 0)
8784 fp->col = 0;
8785 else
8786 {
8787 len = (int)STRLEN(ml_get(fp->lnum));
8788 if (fp->col > len)
8789 fp->col = len;
8790 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008791 getvvcol(curwin, fp, NULL, NULL, &vcol);
8792 ++vcol;
8793 }
8794
8795 rettv->vval.v_number = vcol;
8796}
8797
8798/*
8799 * "visualmode()" function
8800 */
8801 static void
8802f_visualmode(typval_T *argvars, typval_T *rettv)
8803{
8804 char_u str[2];
8805
8806 rettv->v_type = VAR_STRING;
8807 str[0] = curbuf->b_visual_mode_eval;
8808 str[1] = NUL;
8809 rettv->vval.v_string = vim_strsave(str);
8810
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008811 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008812 if (non_zero_arg(&argvars[0]))
8813 curbuf->b_visual_mode_eval = NUL;
8814}
8815
8816/*
8817 * "wildmenumode()" function
8818 */
8819 static void
8820f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8821{
8822#ifdef FEAT_WILDMENU
8823 if (wild_menu_showing)
8824 rettv->vval.v_number = 1;
8825#endif
8826}
8827
8828/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008829 * "windowsversion()" function
8830 */
8831 static void
8832f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8833{
8834 rettv->v_type = VAR_STRING;
8835 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8836}
8837
8838/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008839 * "wordcount()" function
8840 */
8841 static void
8842f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8843{
8844 if (rettv_dict_alloc(rettv) == FAIL)
8845 return;
8846 cursor_pos_info(rettv->vval.v_dict);
8847}
8848
8849/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008850 * "xor(expr, expr)" function
8851 */
8852 static void
8853f_xor(typval_T *argvars, typval_T *rettv)
8854{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008855 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8856 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008857}
8858
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008859#endif // FEAT_EVAL