blob: 06de421eb161f1e75406edbc84d3fbddd4533cba [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 Moolenaarf17e7ea2020-06-01 14:14:44 +0200582 {"getmarklist", 0, 1, FEARG_1, 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},
Bram Moolenaar6c9ba042020-06-01 16:09:41 +0200770 {"readdirex", 1, 2, FEARG_1, ret_list_dict_any, f_readdirex},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100771 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
772 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
773 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
774 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100775 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100776 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
777 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
778 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
779 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
780 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
781 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
782 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
783 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
784 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
785 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
786 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
787 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100788 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
789 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100790#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100791 f_rubyeval
792#else
793 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100794#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100795 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100796 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
797 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
798 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
799 {"screencol", 0, 0, 0, ret_number, f_screencol},
800 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
801 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
802 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
803 {"search", 1, 4, FEARG_1, ret_number, f_search},
Bram Moolenaare8f5ec02020-06-01 17:28:35 +0200804 {"searchcount", 0, 1, FEARG_1, ret_dict_any, f_searchcount},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100805 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
806 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
807 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
808 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
809 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
810 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
811 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
812 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
813 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
814 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
815 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
816 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
817 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
818 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
819 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
820 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
821 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
822 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
823 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
824 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
825 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
826 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100827 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200828#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100829 f_sha256
830#else
831 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200832#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100833 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100834 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
835 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100836 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
837 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
838 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
839 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
840 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
841 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
842 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
843 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
844 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200845 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100846 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
847 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100848 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100849 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
850 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
851 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
852 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100853 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
854 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
855 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
856 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100857 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100858 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
859 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100860 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100861 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
862 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
863 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
864 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
865 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100866 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200867#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100868 f_strftime
869#else
870 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200871#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100872 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100873 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
874 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
875 {"string", 1, 1, FEARG_1, ret_string, f_string},
876 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
877 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100878 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100879#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100880 f_strptime
881#else
882 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100883#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100884 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100885 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
886 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
887 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
888 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
889 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
890 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
891 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
892 {"synID", 3, 3, 0, ret_number, f_synID},
893 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
894 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
895 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
896 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
897 {"system", 1, 2, FEARG_1, ret_string, f_system},
898 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
899 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
900 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
901 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
902 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
903 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100904 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
905 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100906 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100907 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
908 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
909 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
910 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
911 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100912#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100913 f_term_getansicolors
914#else
915 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200916#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100917 },
918 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
919 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
920 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
921 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
922 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
923 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
924 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
925 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
926 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
927 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
928 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
929 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
930 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100931#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100932 f_term_setansicolors
933#else
934 NULL
935#endif
936 },
937 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
938 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
939 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
940 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
941 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
942 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100943 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
944 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
945 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
946 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
947 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
948 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
949 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
950 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100951 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100952 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200953 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100954 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100955 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200956 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100957 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
958 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
959 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
960 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100961 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +0200962#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +0100963 f_test_scrollbar
964#else
965 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +0200966#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100967 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100968 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
969 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
970 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
971 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
972 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100973 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
974 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
975 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
976 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
977 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100978 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
979 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
980 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +0200981 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100982 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100983 {"type", 1, 1, FEARG_1, ret_number, f_type},
984 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
985 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
986 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
987 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
988 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
989 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
990 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
991 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
992 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
993 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
994 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
995 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
996 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
997 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
998 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
999 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
1000 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
1001 {"wincol", 0, 0, 0, ret_number, f_wincol},
1002 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1003 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1004 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1005 {"winline", 0, 0, 0, ret_number, f_winline},
1006 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1007 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1008 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1009 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1010 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1011 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1012 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1013 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001014};
1015
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001016/*
1017 * Function given to ExpandGeneric() to obtain the list of internal
1018 * or user defined function names.
1019 */
1020 char_u *
1021get_function_name(expand_T *xp, int idx)
1022{
1023 static int intidx = -1;
1024 char_u *name;
1025
1026 if (idx == 0)
1027 intidx = -1;
1028 if (intidx < 0)
1029 {
1030 name = get_user_func_name(xp, idx);
1031 if (name != NULL)
1032 return name;
1033 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001034 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001035 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001036 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001037 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001038 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001039 STRCAT(IObuff, ")");
1040 return IObuff;
1041 }
1042
1043 return NULL;
1044}
1045
1046/*
1047 * Function given to ExpandGeneric() to obtain the list of internal or
1048 * user defined variable or function names.
1049 */
1050 char_u *
1051get_expr_name(expand_T *xp, int idx)
1052{
1053 static int intidx = -1;
1054 char_u *name;
1055
1056 if (idx == 0)
1057 intidx = -1;
1058 if (intidx < 0)
1059 {
1060 name = get_function_name(xp, idx);
1061 if (name != NULL)
1062 return name;
1063 }
1064 return get_user_var_name(xp, ++intidx);
1065}
1066
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001067/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001068 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001069 * Return index, or -1 if not found or "implemented" is TRUE and the function
1070 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001071 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001072 static int
1073find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001074{
1075 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001076 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001077 int cmp;
1078 int x;
1079
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001080 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001081
1082 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001083 while (first <= last)
1084 {
1085 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001086 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001087 if (cmp < 0)
1088 last = x - 1;
1089 else if (cmp > 0)
1090 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001091 else if (implemented && global_functions[x].f_func == NULL)
1092 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001093 else
1094 return x;
1095 }
1096 return -1;
1097}
1098
Bram Moolenaar15c47602020-03-26 22:16:48 +01001099/*
1100 * Find internal function "name" in table "global_functions".
1101 * Return index, or -1 if not found or the function is not implemented.
1102 */
1103 int
1104find_internal_func(char_u *name)
1105{
1106 return find_internal_func_opt(name, TRUE);
1107}
1108
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001109 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001110has_internal_func(char_u *name)
1111{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001112 return find_internal_func_opt(name, TRUE) >= 0;
1113}
1114
1115 static int
1116has_internal_func_name(char_u *name)
1117{
1118 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001119}
1120
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001121 char *
1122internal_func_name(int idx)
1123{
1124 return global_functions[idx].f_name;
1125}
1126
1127 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001128internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001129{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001130 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001131}
1132
1133/*
1134 * Check the argument count to use for internal function "idx".
1135 * Returns OK or FAIL;
1136 */
1137 int
1138check_internal_func(int idx, int argcount)
1139{
1140 int res;
1141 char *name;
1142
1143 if (argcount < global_functions[idx].f_min_argc)
1144 res = FCERR_TOOFEW;
1145 else if (argcount > global_functions[idx].f_max_argc)
1146 res = FCERR_TOOMANY;
1147 else
1148 return OK;
1149
1150 name = internal_func_name(idx);
1151 if (res == FCERR_TOOMANY)
1152 semsg(_(e_toomanyarg), name);
1153 else
1154 semsg(_(e_toofewarg), name);
1155 return FAIL;
1156}
1157
Bram Moolenaarac92e252019-08-03 21:58:38 +02001158 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001159call_internal_func(
1160 char_u *name,
1161 int argcount,
1162 typval_T *argvars,
1163 typval_T *rettv)
1164{
1165 int i;
1166
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001167 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001168 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001169 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001170 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001171 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001172 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001173 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001174 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001175 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001176 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001177}
1178
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001179 void
1180call_internal_func_by_idx(
1181 int idx,
1182 typval_T *argvars,
1183 typval_T *rettv)
1184{
1185 global_functions[idx].f_func(argvars, rettv);
1186}
1187
Bram Moolenaarac92e252019-08-03 21:58:38 +02001188/*
1189 * Invoke a method for base->method().
1190 */
1191 int
1192call_internal_method(
1193 char_u *name,
1194 int argcount,
1195 typval_T *argvars,
1196 typval_T *rettv,
1197 typval_T *basetv)
1198{
1199 int i;
1200 int fi;
1201 typval_T argv[MAX_FUNC_ARGS + 1];
1202
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001203 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001204 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001205 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001206 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001207 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001208 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001209 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001210 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001211 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001212
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001213 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001214 {
1215 // base value goes last
1216 for (i = 0; i < argcount; ++i)
1217 argv[i] = argvars[i];
1218 argv[argcount] = *basetv;
1219 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001220 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001221 {
1222 // base value goes second
1223 argv[0] = argvars[0];
1224 argv[1] = *basetv;
1225 for (i = 1; i < argcount; ++i)
1226 argv[i + 1] = argvars[i];
1227 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001228 else if (global_functions[fi].f_argtype == FEARG_3)
1229 {
1230 // base value goes third
1231 argv[0] = argvars[0];
1232 argv[1] = argvars[1];
1233 argv[2] = *basetv;
1234 for (i = 2; i < argcount; ++i)
1235 argv[i + 1] = argvars[i];
1236 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001237 else if (global_functions[fi].f_argtype == FEARG_4)
1238 {
1239 // base value goes fourth
1240 argv[0] = argvars[0];
1241 argv[1] = argvars[1];
1242 argv[2] = argvars[2];
1243 argv[3] = *basetv;
1244 for (i = 3; i < argcount; ++i)
1245 argv[i + 1] = argvars[i];
1246 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001247 else
1248 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001249 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001250 argv[0] = *basetv;
1251 for (i = 0; i < argcount; ++i)
1252 argv[i + 1] = argvars[i];
1253 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001254 argv[argcount + 1].v_type = VAR_UNKNOWN;
1255
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001256 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001257 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001258}
1259
1260/*
1261 * Return TRUE for a non-zero Number and a non-empty String.
1262 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001263 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001264non_zero_arg(typval_T *argvars)
1265{
1266 return ((argvars[0].v_type == VAR_NUMBER
1267 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001268 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001269 && argvars[0].vval.v_number == VVAL_TRUE)
1270 || (argvars[0].v_type == VAR_STRING
1271 && argvars[0].vval.v_string != NULL
1272 && *argvars[0].vval.v_string != NUL));
1273}
1274
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001275#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001276/*
1277 * Get the float value of "argvars[0]" into "f".
1278 * Returns FAIL when the argument is not a Number or Float.
1279 */
1280 static int
1281get_float_arg(typval_T *argvars, float_T *f)
1282{
1283 if (argvars[0].v_type == VAR_FLOAT)
1284 {
1285 *f = argvars[0].vval.v_float;
1286 return OK;
1287 }
1288 if (argvars[0].v_type == VAR_NUMBER)
1289 {
1290 *f = (float_T)argvars[0].vval.v_number;
1291 return OK;
1292 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001293 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001294 return FAIL;
1295}
1296
1297/*
1298 * "abs(expr)" function
1299 */
1300 static void
1301f_abs(typval_T *argvars, typval_T *rettv)
1302{
1303 if (argvars[0].v_type == VAR_FLOAT)
1304 {
1305 rettv->v_type = VAR_FLOAT;
1306 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1307 }
1308 else
1309 {
1310 varnumber_T n;
1311 int error = FALSE;
1312
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001313 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001314 if (error)
1315 rettv->vval.v_number = -1;
1316 else if (n > 0)
1317 rettv->vval.v_number = n;
1318 else
1319 rettv->vval.v_number = -n;
1320 }
1321}
1322
1323/*
1324 * "acos()" function
1325 */
1326 static void
1327f_acos(typval_T *argvars, typval_T *rettv)
1328{
1329 float_T f = 0.0;
1330
1331 rettv->v_type = VAR_FLOAT;
1332 if (get_float_arg(argvars, &f) == OK)
1333 rettv->vval.v_float = acos(f);
1334 else
1335 rettv->vval.v_float = 0.0;
1336}
1337#endif
1338
1339/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001340 * "and(expr, expr)" function
1341 */
1342 static void
1343f_and(typval_T *argvars, typval_T *rettv)
1344{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001345 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1346 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001347}
1348
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001349#ifdef FEAT_FLOAT
1350/*
1351 * "asin()" function
1352 */
1353 static void
1354f_asin(typval_T *argvars, typval_T *rettv)
1355{
1356 float_T f = 0.0;
1357
1358 rettv->v_type = VAR_FLOAT;
1359 if (get_float_arg(argvars, &f) == OK)
1360 rettv->vval.v_float = asin(f);
1361 else
1362 rettv->vval.v_float = 0.0;
1363}
1364
1365/*
1366 * "atan()" function
1367 */
1368 static void
1369f_atan(typval_T *argvars, typval_T *rettv)
1370{
1371 float_T f = 0.0;
1372
1373 rettv->v_type = VAR_FLOAT;
1374 if (get_float_arg(argvars, &f) == OK)
1375 rettv->vval.v_float = atan(f);
1376 else
1377 rettv->vval.v_float = 0.0;
1378}
1379
1380/*
1381 * "atan2()" function
1382 */
1383 static void
1384f_atan2(typval_T *argvars, typval_T *rettv)
1385{
1386 float_T fx = 0.0, fy = 0.0;
1387
1388 rettv->v_type = VAR_FLOAT;
1389 if (get_float_arg(argvars, &fx) == OK
1390 && get_float_arg(&argvars[1], &fy) == OK)
1391 rettv->vval.v_float = atan2(fx, fy);
1392 else
1393 rettv->vval.v_float = 0.0;
1394}
1395#endif
1396
1397/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001398 * "balloon_show()" function
1399 */
1400#ifdef FEAT_BEVAL
1401 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001402f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1403{
1404 rettv->v_type = VAR_STRING;
1405 if (balloonEval != NULL)
1406 {
1407 if (balloonEval->msg == NULL)
1408 rettv->vval.v_string = NULL;
1409 else
1410 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1411 }
1412}
1413
1414 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001415f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1416{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001417 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001418 {
1419 if (argvars[0].v_type == VAR_LIST
1420# ifdef FEAT_GUI
1421 && !gui.in_use
1422# endif
1423 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001424 {
1425 list_T *l = argvars[0].vval.v_list;
1426
1427 // empty list removes the balloon
1428 post_balloon(balloonEval, NULL,
1429 l == NULL || l->lv_len == 0 ? NULL : l);
1430 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001431 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001432 {
1433 char_u *mesg = tv_get_string_chk(&argvars[0]);
1434
1435 if (mesg != NULL)
1436 // empty string removes the balloon
1437 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1438 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001439 }
1440}
1441
Bram Moolenaar669a8282017-11-19 20:13:05 +01001442# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001443 static void
1444f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1445{
1446 if (rettv_list_alloc(rettv) == OK)
1447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001448 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001449
1450 if (msg != NULL)
1451 {
1452 pumitem_T *array;
1453 int size = split_message(msg, &array);
1454 int i;
1455
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001456 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001457 for (i = 1; i < size - 1; ++i)
1458 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001459 while (size > 0)
1460 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001461 vim_free(array);
1462 }
1463 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001464}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001465# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001466#endif
1467
1468/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001469 * Get the buffer from "arg" and give an error and return NULL if it is not
1470 * valid.
1471 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001472 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001473get_buf_arg(typval_T *arg)
1474{
1475 buf_T *buf;
1476
1477 ++emsg_off;
1478 buf = tv_get_buf(arg, FALSE);
1479 --emsg_off;
1480 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001481 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001482 return buf;
1483}
1484
1485/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486 * "byte2line(byte)" function
1487 */
1488 static void
1489f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1490{
1491#ifndef FEAT_BYTEOFF
1492 rettv->vval.v_number = -1;
1493#else
1494 long boff = 0;
1495
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001496 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497 if (boff < 0)
1498 rettv->vval.v_number = -1;
1499 else
1500 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1501 (linenr_T)0, &boff);
1502#endif
1503}
1504
1505 static void
1506byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1507{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001509 char_u *str;
1510 varnumber_T idx;
1511
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001512 str = tv_get_string_chk(&argvars[0]);
1513 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001514 rettv->vval.v_number = -1;
1515 if (str == NULL || idx < 0)
1516 return;
1517
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001518 t = str;
1519 for ( ; idx > 0; idx--)
1520 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001521 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001522 return;
1523 if (enc_utf8 && comp)
1524 t += utf_ptr2len(t);
1525 else
1526 t += (*mb_ptr2len)(t);
1527 }
1528 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529}
1530
1531/*
1532 * "byteidx()" function
1533 */
1534 static void
1535f_byteidx(typval_T *argvars, typval_T *rettv)
1536{
1537 byteidx(argvars, rettv, FALSE);
1538}
1539
1540/*
1541 * "byteidxcomp()" function
1542 */
1543 static void
1544f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1545{
1546 byteidx(argvars, rettv, TRUE);
1547}
1548
1549/*
1550 * "call(func, arglist [, dict])" function
1551 */
1552 static void
1553f_call(typval_T *argvars, typval_T *rettv)
1554{
1555 char_u *func;
1556 partial_T *partial = NULL;
1557 dict_T *selfdict = NULL;
1558
1559 if (argvars[1].v_type != VAR_LIST)
1560 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001561 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001562 return;
1563 }
1564 if (argvars[1].vval.v_list == NULL)
1565 return;
1566
1567 if (argvars[0].v_type == VAR_FUNC)
1568 func = argvars[0].vval.v_string;
1569 else if (argvars[0].v_type == VAR_PARTIAL)
1570 {
1571 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001572 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001573 }
1574 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001575 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001577 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578
1579 if (argvars[2].v_type != VAR_UNKNOWN)
1580 {
1581 if (argvars[2].v_type != VAR_DICT)
1582 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001583 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001584 return;
1585 }
1586 selfdict = argvars[2].vval.v_dict;
1587 }
1588
1589 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1590}
1591
1592#ifdef FEAT_FLOAT
1593/*
1594 * "ceil({float})" function
1595 */
1596 static void
1597f_ceil(typval_T *argvars, typval_T *rettv)
1598{
1599 float_T f = 0.0;
1600
1601 rettv->v_type = VAR_FLOAT;
1602 if (get_float_arg(argvars, &f) == OK)
1603 rettv->vval.v_float = ceil(f);
1604 else
1605 rettv->vval.v_float = 0.0;
1606}
1607#endif
1608
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609/*
1610 * "changenr()" function
1611 */
1612 static void
1613f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1614{
1615 rettv->vval.v_number = curbuf->b_u_seq_cur;
1616}
1617
1618/*
1619 * "char2nr(string)" function
1620 */
1621 static void
1622f_char2nr(typval_T *argvars, typval_T *rettv)
1623{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624 if (has_mbyte)
1625 {
1626 int utf8 = 0;
1627
1628 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001629 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630
1631 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001632 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001633 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001634 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635 }
1636 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001637 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001638}
1639
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001640 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001641get_optional_window(typval_T *argvars, int idx)
1642{
1643 win_T *win = curwin;
1644
1645 if (argvars[idx].v_type != VAR_UNKNOWN)
1646 {
1647 win = find_win_by_nr_or_id(&argvars[idx]);
1648 if (win == NULL)
1649 {
1650 emsg(_(e_invalwindow));
1651 return NULL;
1652 }
1653 }
1654 return win;
1655}
1656
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001657/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001658 * "col(string)" function
1659 */
1660 static void
1661f_col(typval_T *argvars, typval_T *rettv)
1662{
1663 colnr_T col = 0;
1664 pos_T *fp;
1665 int fnum = curbuf->b_fnum;
1666
1667 fp = var2fpos(&argvars[0], FALSE, &fnum);
1668 if (fp != NULL && fnum == curbuf->b_fnum)
1669 {
1670 if (fp->col == MAXCOL)
1671 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001672 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1674 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1675 else
1676 col = MAXCOL;
1677 }
1678 else
1679 {
1680 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001681 // col(".") when the cursor is on the NUL at the end of the line
1682 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001683 if (virtual_active() && fp == &curwin->w_cursor)
1684 {
1685 char_u *p = ml_get_cursor();
1686
1687 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1688 curwin->w_virtcol - curwin->w_cursor.coladd))
1689 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001690 int l;
1691
1692 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1693 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001694 }
1695 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001696 }
1697 }
1698 rettv->vval.v_number = col;
1699}
1700
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001701/*
1702 * "confirm(message, buttons[, default [, type]])" function
1703 */
1704 static void
1705f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1706{
1707#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1708 char_u *message;
1709 char_u *buttons = NULL;
1710 char_u buf[NUMBUFLEN];
1711 char_u buf2[NUMBUFLEN];
1712 int def = 1;
1713 int type = VIM_GENERIC;
1714 char_u *typestr;
1715 int error = FALSE;
1716
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001717 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001718 if (message == NULL)
1719 error = TRUE;
1720 if (argvars[1].v_type != VAR_UNKNOWN)
1721 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001722 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001723 if (buttons == NULL)
1724 error = TRUE;
1725 if (argvars[2].v_type != VAR_UNKNOWN)
1726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001727 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728 if (argvars[3].v_type != VAR_UNKNOWN)
1729 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001730 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001731 if (typestr == NULL)
1732 error = TRUE;
1733 else
1734 {
1735 switch (TOUPPER_ASC(*typestr))
1736 {
1737 case 'E': type = VIM_ERROR; break;
1738 case 'Q': type = VIM_QUESTION; break;
1739 case 'I': type = VIM_INFO; break;
1740 case 'W': type = VIM_WARNING; break;
1741 case 'G': type = VIM_GENERIC; break;
1742 }
1743 }
1744 }
1745 }
1746 }
1747
1748 if (buttons == NULL || *buttons == NUL)
1749 buttons = (char_u *)_("&Ok");
1750
1751 if (!error)
1752 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1753 def, NULL, FALSE);
1754#endif
1755}
1756
1757/*
1758 * "copy()" function
1759 */
1760 static void
1761f_copy(typval_T *argvars, typval_T *rettv)
1762{
1763 item_copy(&argvars[0], rettv, FALSE, 0);
1764}
1765
1766#ifdef FEAT_FLOAT
1767/*
1768 * "cos()" function
1769 */
1770 static void
1771f_cos(typval_T *argvars, typval_T *rettv)
1772{
1773 float_T f = 0.0;
1774
1775 rettv->v_type = VAR_FLOAT;
1776 if (get_float_arg(argvars, &f) == OK)
1777 rettv->vval.v_float = cos(f);
1778 else
1779 rettv->vval.v_float = 0.0;
1780}
1781
1782/*
1783 * "cosh()" function
1784 */
1785 static void
1786f_cosh(typval_T *argvars, typval_T *rettv)
1787{
1788 float_T f = 0.0;
1789
1790 rettv->v_type = VAR_FLOAT;
1791 if (get_float_arg(argvars, &f) == OK)
1792 rettv->vval.v_float = cosh(f);
1793 else
1794 rettv->vval.v_float = 0.0;
1795}
1796#endif
1797
1798/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001799 * "cursor(lnum, col)" function, or
1800 * "cursor(list)"
1801 *
1802 * Moves the cursor to the specified line and column.
1803 * Returns 0 when the position could be set, -1 otherwise.
1804 */
1805 static void
1806f_cursor(typval_T *argvars, typval_T *rettv)
1807{
1808 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001809 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001810 int set_curswant = TRUE;
1811
1812 rettv->vval.v_number = -1;
1813 if (argvars[1].v_type == VAR_UNKNOWN)
1814 {
1815 pos_T pos;
1816 colnr_T curswant = -1;
1817
1818 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1819 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001820 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001821 return;
1822 }
1823 line = pos.lnum;
1824 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001826 if (curswant >= 0)
1827 {
1828 curwin->w_curswant = curswant - 1;
1829 set_curswant = FALSE;
1830 }
1831 }
1832 else
1833 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001834 line = tv_get_lnum(argvars);
1835 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001836 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001837 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001838 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001839 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001840 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001841 if (line > 0)
1842 curwin->w_cursor.lnum = line;
1843 if (col > 0)
1844 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001845 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001847 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001848 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001849 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001850 if (has_mbyte)
1851 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001852
1853 curwin->w_set_curswant = set_curswant;
1854 rettv->vval.v_number = 0;
1855}
1856
Bram Moolenaar4f974752019-02-17 17:44:42 +01001857#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001858/*
1859 * "debugbreak()" function
1860 */
1861 static void
1862f_debugbreak(typval_T *argvars, typval_T *rettv)
1863{
1864 int pid;
1865
1866 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001867 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001868 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001869 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001870 else
1871 {
1872 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1873
1874 if (hProcess != NULL)
1875 {
1876 DebugBreakProcess(hProcess);
1877 CloseHandle(hProcess);
1878 rettv->vval.v_number = OK;
1879 }
1880 }
1881}
1882#endif
1883
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001884/*
1885 * "deepcopy()" function
1886 */
1887 static void
1888f_deepcopy(typval_T *argvars, typval_T *rettv)
1889{
1890 int noref = 0;
1891 int copyID;
1892
1893 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001894 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001895 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001896 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001897 else
1898 {
1899 copyID = get_copyID();
1900 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1901 }
1902}
1903
1904/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001905 * "did_filetype()" function
1906 */
1907 static void
1908f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1909{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001910 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001911}
1912
1913/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001914 * "echoraw({expr})" function
1915 */
1916 static void
1917f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1918{
1919 char_u *str = tv_get_string_chk(&argvars[0]);
1920
1921 if (str != NULL && *str != NUL)
1922 {
1923 out_str(str);
1924 out_flush();
1925 }
1926}
1927
1928/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001929 * "empty({expr})" function
1930 */
1931 static void
1932f_empty(typval_T *argvars, typval_T *rettv)
1933{
1934 int n = FALSE;
1935
1936 switch (argvars[0].v_type)
1937 {
1938 case VAR_STRING:
1939 case VAR_FUNC:
1940 n = argvars[0].vval.v_string == NULL
1941 || *argvars[0].vval.v_string == NUL;
1942 break;
1943 case VAR_PARTIAL:
1944 n = FALSE;
1945 break;
1946 case VAR_NUMBER:
1947 n = argvars[0].vval.v_number == 0;
1948 break;
1949 case VAR_FLOAT:
1950#ifdef FEAT_FLOAT
1951 n = argvars[0].vval.v_float == 0.0;
1952 break;
1953#endif
1954 case VAR_LIST:
1955 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001956 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 break;
1958 case VAR_DICT:
1959 n = argvars[0].vval.v_dict == NULL
1960 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1961 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001962 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001963 case VAR_SPECIAL:
1964 n = argvars[0].vval.v_number != VVAL_TRUE;
1965 break;
1966
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001967 case VAR_BLOB:
1968 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001969 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1970 break;
1971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001972 case VAR_JOB:
1973#ifdef FEAT_JOB_CHANNEL
1974 n = argvars[0].vval.v_job == NULL
1975 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1976 break;
1977#endif
1978 case VAR_CHANNEL:
1979#ifdef FEAT_JOB_CHANNEL
1980 n = argvars[0].vval.v_channel == NULL
1981 || !channel_is_open(argvars[0].vval.v_channel);
1982 break;
1983#endif
1984 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02001985 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001986 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001987 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988 n = TRUE;
1989 break;
1990 }
1991
1992 rettv->vval.v_number = n;
1993}
1994
1995/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001996 * "environ()" function
1997 */
1998 static void
1999f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2000{
2001#if !defined(AMIGA)
2002 int i = 0;
2003 char_u *entry, *value;
2004# ifdef MSWIN
2005 extern wchar_t **_wenviron;
2006# else
2007 extern char **environ;
2008# endif
2009
2010 if (rettv_dict_alloc(rettv) != OK)
2011 return;
2012
2013# ifdef MSWIN
2014 if (*_wenviron == NULL)
2015 return;
2016# else
2017 if (*environ == NULL)
2018 return;
2019# endif
2020
2021 for (i = 0; ; ++i)
2022 {
2023# ifdef MSWIN
2024 short_u *p;
2025
2026 if ((p = (short_u *)_wenviron[i]) == NULL)
2027 return;
2028 entry = utf16_to_enc(p, NULL);
2029# else
2030 if ((entry = (char_u *)environ[i]) == NULL)
2031 return;
2032 entry = vim_strsave(entry);
2033# endif
2034 if (entry == NULL) // out of memory
2035 return;
2036 if ((value = vim_strchr(entry, '=')) == NULL)
2037 {
2038 vim_free(entry);
2039 continue;
2040 }
2041 *value++ = NUL;
2042 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2043 vim_free(entry);
2044 }
2045#endif
2046}
2047
2048/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049 * "escape({string}, {chars})" function
2050 */
2051 static void
2052f_escape(typval_T *argvars, typval_T *rettv)
2053{
2054 char_u buf[NUMBUFLEN];
2055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002056 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2057 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058 rettv->v_type = VAR_STRING;
2059}
2060
2061/*
2062 * "eval()" function
2063 */
2064 static void
2065f_eval(typval_T *argvars, typval_T *rettv)
2066{
2067 char_u *s, *p;
2068
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002069 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002070 if (s != NULL)
2071 s = skipwhite(s);
2072
2073 p = s;
Bram Moolenaar32e35112020-05-14 22:41:15 +02002074 if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002075 {
2076 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002077 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002078 need_clr_eos = FALSE;
2079 rettv->v_type = VAR_NUMBER;
2080 rettv->vval.v_number = 0;
2081 }
2082 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002083 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002084}
2085
2086/*
2087 * "eventhandler()" function
2088 */
2089 static void
2090f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2091{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002092 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093}
2094
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095static garray_T redir_execute_ga;
2096
2097/*
2098 * Append "value[value_len]" to the execute() output.
2099 */
2100 void
2101execute_redir_str(char_u *value, int value_len)
2102{
2103 int len;
2104
2105 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002106 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002107 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002108 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002109 if (ga_grow(&redir_execute_ga, len) == OK)
2110 {
2111 mch_memmove((char *)redir_execute_ga.ga_data
2112 + redir_execute_ga.ga_len, value, len);
2113 redir_execute_ga.ga_len += len;
2114 }
2115}
2116
2117/*
2118 * Get next line from a list.
2119 * Called by do_cmdline() to get the next line.
2120 * Returns allocated string, or NULL for end of function.
2121 */
2122
2123 static char_u *
2124get_list_line(
2125 int c UNUSED,
2126 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002127 int indent UNUSED,
2128 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002129{
2130 listitem_T **p = (listitem_T **)cookie;
2131 listitem_T *item = *p;
2132 char_u buf[NUMBUFLEN];
2133 char_u *s;
2134
2135 if (item == NULL)
2136 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002137 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138 *p = item->li_next;
2139 return s == NULL ? NULL : vim_strsave(s);
2140}
2141
2142/*
2143 * "execute()" function
2144 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002145 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002146execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147{
2148 char_u *cmd = NULL;
2149 list_T *list = NULL;
2150 int save_msg_silent = msg_silent;
2151 int save_emsg_silent = emsg_silent;
2152 int save_emsg_noredir = emsg_noredir;
2153 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002154 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002155 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002156 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002157 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158
2159 rettv->vval.v_string = NULL;
2160 rettv->v_type = VAR_STRING;
2161
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002162 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002163 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002164 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002165 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002166 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167 return;
2168 ++list->lv_refcount;
2169 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002170 else if (argvars[arg_off].v_type == VAR_JOB
2171 || argvars[arg_off].v_type == VAR_CHANNEL)
2172 {
2173 emsg(_(e_inval_string));
2174 return;
2175 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 else
2177 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002178 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002179 if (cmd == NULL)
2180 return;
2181 }
2182
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002183 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002184 {
2185 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002186 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002187
2188 if (s == NULL)
2189 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002190 if (*s == NUL)
2191 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 if (STRNCMP(s, "silent", 6) == 0)
2193 ++msg_silent;
2194 if (STRCMP(s, "silent!") == 0)
2195 {
2196 emsg_silent = TRUE;
2197 emsg_noredir = TRUE;
2198 }
2199 }
2200 else
2201 ++msg_silent;
2202
2203 if (redir_execute)
2204 save_ga = redir_execute_ga;
2205 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2206 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002207 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002208 if (!echo_output)
2209 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210
2211 if (cmd != NULL)
2212 do_cmdline_cmd(cmd);
2213 else
2214 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002215 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002217 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002218 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002219 do_cmdline(NULL, get_list_line, (void *)&item,
2220 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2221 --list->lv_refcount;
2222 }
2223
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002224 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002225 if (ga_grow(&redir_execute_ga, 1) == OK)
2226 {
2227 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2228 rettv->vval.v_string = redir_execute_ga.ga_data;
2229 }
2230 else
2231 {
2232 ga_clear(&redir_execute_ga);
2233 rettv->vval.v_string = NULL;
2234 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002235 msg_silent = save_msg_silent;
2236 emsg_silent = save_emsg_silent;
2237 emsg_noredir = save_emsg_noredir;
2238
2239 redir_execute = save_redir_execute;
2240 if (redir_execute)
2241 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002242 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002243
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002244 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002245 if (echo_output)
2246 // When not working silently: put it in column zero. A following
2247 // "echon" will overwrite the message, unavoidably.
2248 msg_col = 0;
2249 else
2250 // When working silently: Put it back where it was, since nothing
2251 // should have been written.
2252 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002253}
2254
2255/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002256 * "execute()" function
2257 */
2258 static void
2259f_execute(typval_T *argvars, typval_T *rettv)
2260{
2261 execute_common(argvars, rettv, 0);
2262}
2263
2264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002265 * "exists()" function
2266 */
2267 static void
2268f_exists(typval_T *argvars, typval_T *rettv)
2269{
2270 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002271 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002272
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002273 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002274 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002276 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002277 if (mch_getenv(p + 1) != NULL)
2278 n = TRUE;
2279 else
2280 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002281 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 p = expand_env_save(p);
2283 if (p != NULL && *p != '$')
2284 n = TRUE;
2285 vim_free(p);
2286 }
2287 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002288 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002289 {
2290 n = (get_option_tv(&p, NULL, TRUE) == OK);
2291 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002292 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002294 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002296 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002298 else if (*p == '?') // internal function only
2299 {
2300 n = has_internal_func_name(p + 1);
2301 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002302 else if (*p == ':')
2303 {
2304 n = cmd_exists(p + 1);
2305 }
2306 else if (*p == '#')
2307 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 if (p[1] == '#')
2309 n = autocmd_supported(p + 2);
2310 else
2311 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002312 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002313 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002314 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002315 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002316 }
2317
2318 rettv->vval.v_number = n;
2319}
2320
2321#ifdef FEAT_FLOAT
2322/*
2323 * "exp()" function
2324 */
2325 static void
2326f_exp(typval_T *argvars, typval_T *rettv)
2327{
2328 float_T f = 0.0;
2329
2330 rettv->v_type = VAR_FLOAT;
2331 if (get_float_arg(argvars, &f) == OK)
2332 rettv->vval.v_float = exp(f);
2333 else
2334 rettv->vval.v_float = 0.0;
2335}
2336#endif
2337
2338/*
2339 * "expand()" function
2340 */
2341 static void
2342f_expand(typval_T *argvars, typval_T *rettv)
2343{
2344 char_u *s;
2345 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002346 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2348 expand_T xpc;
2349 int error = FALSE;
2350 char_u *result;
2351
2352 rettv->v_type = VAR_STRING;
2353 if (argvars[1].v_type != VAR_UNKNOWN
2354 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002355 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002357 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002358
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002359 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360 if (*s == '%' || *s == '#' || *s == '<')
2361 {
2362 ++emsg_off;
2363 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2364 --emsg_off;
2365 if (rettv->v_type == VAR_LIST)
2366 {
2367 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2368 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002369 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370 }
2371 else
2372 rettv->vval.v_string = result;
2373 }
2374 else
2375 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002376 // When the optional second argument is non-zero, don't remove matches
2377 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002378 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002379 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002380 options |= WILD_KEEP_ALL;
2381 if (!error)
2382 {
2383 ExpandInit(&xpc);
2384 xpc.xp_context = EXPAND_FILES;
2385 if (p_wic)
2386 options += WILD_ICASE;
2387 if (rettv->v_type == VAR_STRING)
2388 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2389 options, WILD_ALL);
2390 else if (rettv_list_alloc(rettv) != FAIL)
2391 {
2392 int i;
2393
2394 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2395 for (i = 0; i < xpc.xp_numfiles; i++)
2396 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2397 ExpandCleanup(&xpc);
2398 }
2399 }
2400 else
2401 rettv->vval.v_string = NULL;
2402 }
2403}
2404
2405/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002406 * "expandcmd()" function
2407 * Expand all the special characters in a command string.
2408 */
2409 static void
2410f_expandcmd(typval_T *argvars, typval_T *rettv)
2411{
2412 exarg_T eap;
2413 char_u *cmdstr;
2414 char *errormsg = NULL;
2415
2416 rettv->v_type = VAR_STRING;
2417 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2418
2419 memset(&eap, 0, sizeof(eap));
2420 eap.cmd = cmdstr;
2421 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002422 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002423 eap.usefilter = FALSE;
2424 eap.nextcmd = NULL;
2425 eap.cmdidx = CMD_USER;
2426
2427 expand_filename(&eap, &cmdstr, &errormsg);
2428 if (errormsg != NULL && *errormsg != NUL)
2429 emsg(errormsg);
2430
2431 rettv->vval.v_string = cmdstr;
2432}
2433
2434/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002435 * "feedkeys()" function
2436 */
2437 static void
2438f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2439{
2440 int remap = TRUE;
2441 int insert = FALSE;
2442 char_u *keys, *flags;
2443 char_u nbuf[NUMBUFLEN];
2444 int typed = FALSE;
2445 int execute = FALSE;
2446 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002447 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 char_u *keys_esc;
2449
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002450 // This is not allowed in the sandbox. If the commands would still be
2451 // executed in the sandbox it would be OK, but it probably happens later,
2452 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002453 if (check_secure())
2454 return;
2455
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002456 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457
2458 if (argvars[1].v_type != VAR_UNKNOWN)
2459 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002460 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 for ( ; *flags != NUL; ++flags)
2462 {
2463 switch (*flags)
2464 {
2465 case 'n': remap = FALSE; break;
2466 case 'm': remap = TRUE; break;
2467 case 't': typed = TRUE; break;
2468 case 'i': insert = TRUE; break;
2469 case 'x': execute = TRUE; break;
2470 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002471 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002472 }
2473 }
2474 }
2475
2476 if (*keys != NUL || execute)
2477 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002478 // Need to escape K_SPECIAL and CSI before putting the string in the
2479 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002480 keys_esc = vim_strsave_escape_csi(keys);
2481 if (keys_esc != NULL)
2482 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002483 if (lowlevel)
2484 {
2485#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002486 int idx;
2487 int len = (int)STRLEN(keys);
2488
2489 for (idx = 0; idx < len; ++idx)
2490 {
2491 // if a CTRL-C was typed, set got_int, similar to what
2492 // happens in fill_input_buf()
2493 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2494 got_int = TRUE;
2495 add_to_input_buf(keys + idx, 1);
2496 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002497#else
2498 emsg(_("E980: lowlevel input not supported"));
2499#endif
2500 }
2501 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002502 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002503 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002504 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002505 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002506#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002507 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002508#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002509 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002510 typebuf_was_filled = TRUE;
2511 }
2512 vim_free(keys_esc);
2513
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002514 if (execute)
2515 {
2516 int save_msg_scroll = msg_scroll;
2517
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002518 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002519 msg_scroll = FALSE;
2520
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002521 if (!dangerous)
2522 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002523 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002524 if (!dangerous)
2525 --ex_normal_busy;
2526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002527 msg_scroll |= save_msg_scroll;
2528 }
2529 }
2530 }
2531}
2532
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002533#ifdef FEAT_FLOAT
2534/*
2535 * "float2nr({float})" function
2536 */
2537 static void
2538f_float2nr(typval_T *argvars, typval_T *rettv)
2539{
2540 float_T f = 0.0;
2541
2542 if (get_float_arg(argvars, &f) == OK)
2543 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002544 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002545 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002546 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002547 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002548 else
2549 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002550 }
2551}
2552
2553/*
2554 * "floor({float})" function
2555 */
2556 static void
2557f_floor(typval_T *argvars, typval_T *rettv)
2558{
2559 float_T f = 0.0;
2560
2561 rettv->v_type = VAR_FLOAT;
2562 if (get_float_arg(argvars, &f) == OK)
2563 rettv->vval.v_float = floor(f);
2564 else
2565 rettv->vval.v_float = 0.0;
2566}
2567
2568/*
2569 * "fmod()" function
2570 */
2571 static void
2572f_fmod(typval_T *argvars, typval_T *rettv)
2573{
2574 float_T fx = 0.0, fy = 0.0;
2575
2576 rettv->v_type = VAR_FLOAT;
2577 if (get_float_arg(argvars, &fx) == OK
2578 && get_float_arg(&argvars[1], &fy) == OK)
2579 rettv->vval.v_float = fmod(fx, fy);
2580 else
2581 rettv->vval.v_float = 0.0;
2582}
2583#endif
2584
2585/*
2586 * "fnameescape({string})" function
2587 */
2588 static void
2589f_fnameescape(typval_T *argvars, typval_T *rettv)
2590{
2591 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002592 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 rettv->v_type = VAR_STRING;
2594}
2595
2596/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002597 * "foreground()" function
2598 */
2599 static void
2600f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2601{
2602#ifdef FEAT_GUI
2603 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002604 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002605 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002606 return;
2607 }
2608#endif
2609#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002610 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002611#endif
2612}
2613
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002615common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002616{
2617 char_u *s;
2618 char_u *name;
2619 int use_string = FALSE;
2620 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002621 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002622 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002623
2624 if (argvars[0].v_type == VAR_FUNC)
2625 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002626 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 s = argvars[0].vval.v_string;
2628 }
2629 else if (argvars[0].v_type == VAR_PARTIAL
2630 && argvars[0].vval.v_partial != NULL)
2631 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002632 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002633 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002634 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002635 }
2636 else
2637 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002638 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002639 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002640 use_string = TRUE;
2641 }
2642
Bram Moolenaar843b8842016-08-21 14:36:15 +02002643 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644 {
2645 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002646 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002647 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2648 if (*name != NUL)
2649 s = NULL;
2650 }
2651
Bram Moolenaar843b8842016-08-21 14:36:15 +02002652 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2653 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002654 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002655 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002656 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002657 ? find_func(trans_name, is_global, NULL) == NULL
2658 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002659 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002660 else
2661 {
2662 int dict_idx = 0;
2663 int arg_idx = 0;
2664 list_T *list = NULL;
2665
2666 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2667 {
2668 char sid_buf[25];
2669 int off = *s == 's' ? 2 : 5;
2670
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002671 // Expand s: and <SID> into <SNR>nr_, so that the function can
2672 // also be called from another script. Using trans_function_name()
2673 // would also work, but some plugins depend on the name being
2674 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002675 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002676 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 if (name != NULL)
2678 {
2679 STRCPY(name, sid_buf);
2680 STRCAT(name, s + off);
2681 }
2682 }
2683 else
2684 name = vim_strsave(s);
2685
2686 if (argvars[1].v_type != VAR_UNKNOWN)
2687 {
2688 if (argvars[2].v_type != VAR_UNKNOWN)
2689 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002690 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 arg_idx = 1;
2692 dict_idx = 2;
2693 }
2694 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002695 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002696 dict_idx = 1;
2697 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002698 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699 arg_idx = 1;
2700 if (dict_idx > 0)
2701 {
2702 if (argvars[dict_idx].v_type != VAR_DICT)
2703 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002704 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002706 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002707 }
2708 if (argvars[dict_idx].vval.v_dict == NULL)
2709 dict_idx = 0;
2710 }
2711 if (arg_idx > 0)
2712 {
2713 if (argvars[arg_idx].v_type != VAR_LIST)
2714 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002715 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002716 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002717 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002718 }
2719 list = argvars[arg_idx].vval.v_list;
2720 if (list == NULL || list->lv_len == 0)
2721 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002722 else if (list->lv_len > MAX_FUNC_ARGS)
2723 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002724 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002725 vim_free(name);
2726 goto theend;
2727 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 }
2729 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002730 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002731 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002732 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002733
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002734 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002735 if (pt == NULL)
2736 vim_free(name);
2737 else
2738 {
2739 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2740 {
2741 listitem_T *li;
2742 int i = 0;
2743 int arg_len = 0;
2744 int lv_len = 0;
2745
2746 if (arg_pt != NULL)
2747 arg_len = arg_pt->pt_argc;
2748 if (list != NULL)
2749 lv_len = list->lv_len;
2750 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002751 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002752 if (pt->pt_argv == NULL)
2753 {
2754 vim_free(pt);
2755 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002756 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002757 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002758 for (i = 0; i < arg_len; i++)
2759 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2760 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002761 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002762 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002763 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002764 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002765 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002766 }
2767
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002768 // For "function(dict.func, [], dict)" and "func" is a partial
2769 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 if (dict_idx > 0)
2771 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002772 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002773 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2774 ++pt->pt_dict->dv_refcount;
2775 }
2776 else if (arg_pt != NULL)
2777 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002778 // If the dict was bound automatically the result is also
2779 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002780 pt->pt_dict = arg_pt->pt_dict;
2781 pt->pt_auto = arg_pt->pt_auto;
2782 if (pt->pt_dict != NULL)
2783 ++pt->pt_dict->dv_refcount;
2784 }
2785
2786 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002787 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2788 {
2789 pt->pt_func = arg_pt->pt_func;
2790 func_ptr_ref(pt->pt_func);
2791 vim_free(name);
2792 }
2793 else if (is_funcref)
2794 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002795 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002796 func_ptr_ref(pt->pt_func);
2797 vim_free(name);
2798 }
2799 else
2800 {
2801 pt->pt_name = name;
2802 func_ref(name);
2803 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002804 }
2805 rettv->v_type = VAR_PARTIAL;
2806 rettv->vval.v_partial = pt;
2807 }
2808 else
2809 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002810 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002811 rettv->v_type = VAR_FUNC;
2812 rettv->vval.v_string = name;
2813 func_ref(name);
2814 }
2815 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002816theend:
2817 vim_free(trans_name);
2818}
2819
2820/*
2821 * "funcref()" function
2822 */
2823 static void
2824f_funcref(typval_T *argvars, typval_T *rettv)
2825{
2826 common_function(argvars, rettv, TRUE);
2827}
2828
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002829 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002830ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002831{
2832 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2833 return &t_func_any;
Bram Moolenaard77a8522020-04-03 21:59:57 +02002834 return &t_func_void;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002835}
2836
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002837/*
2838 * "function()" function
2839 */
2840 static void
2841f_function(typval_T *argvars, typval_T *rettv)
2842{
2843 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002844}
2845
2846/*
2847 * "garbagecollect()" function
2848 */
2849 static void
2850f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2851{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002852 // This is postponed until we are back at the toplevel, because we may be
2853 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002854 want_garbage_collect = TRUE;
2855
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002856 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002857 garbage_collect_at_exit = TRUE;
2858}
2859
2860/*
2861 * "get()" function
2862 */
2863 static void
2864f_get(typval_T *argvars, typval_T *rettv)
2865{
2866 listitem_T *li;
2867 list_T *l;
2868 dictitem_T *di;
2869 dict_T *d;
2870 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002871 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002872
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002873 if (argvars[0].v_type == VAR_BLOB)
2874 {
2875 int error = FALSE;
2876 int idx = tv_get_number_chk(&argvars[1], &error);
2877
2878 if (!error)
2879 {
2880 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002881 if (idx < 0)
2882 idx = blob_len(argvars[0].vval.v_blob) + idx;
2883 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2884 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002885 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002886 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002887 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002888 tv = rettv;
2889 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002890 }
2891 }
2892 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002893 {
2894 if ((l = argvars[0].vval.v_list) != NULL)
2895 {
2896 int error = FALSE;
2897
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002898 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002899 if (!error && li != NULL)
2900 tv = &li->li_tv;
2901 }
2902 }
2903 else if (argvars[0].v_type == VAR_DICT)
2904 {
2905 if ((d = argvars[0].vval.v_dict) != NULL)
2906 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002907 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002908 if (di != NULL)
2909 tv = &di->di_tv;
2910 }
2911 }
2912 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2913 {
2914 partial_T *pt;
2915 partial_T fref_pt;
2916
2917 if (argvars[0].v_type == VAR_PARTIAL)
2918 pt = argvars[0].vval.v_partial;
2919 else
2920 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02002921 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922 fref_pt.pt_name = argvars[0].vval.v_string;
2923 pt = &fref_pt;
2924 }
2925
2926 if (pt != NULL)
2927 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002928 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002929 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002930
2931 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2932 {
2933 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002934 n = partial_name(pt);
2935 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002936 rettv->vval.v_string = NULL;
2937 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002938 {
2939 rettv->vval.v_string = vim_strsave(n);
2940 if (rettv->v_type == VAR_FUNC)
2941 func_ref(rettv->vval.v_string);
2942 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002943 }
2944 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002945 {
2946 what_is_dict = TRUE;
2947 if (pt->pt_dict != NULL)
2948 rettv_dict_set(rettv, pt->pt_dict);
2949 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002950 else if (STRCMP(what, "args") == 0)
2951 {
2952 rettv->v_type = VAR_LIST;
2953 if (rettv_list_alloc(rettv) == OK)
2954 {
2955 int i;
2956
2957 for (i = 0; i < pt->pt_argc; ++i)
2958 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2959 }
2960 }
2961 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002962 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002963
2964 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2965 // third argument
2966 if (!what_is_dict)
2967 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002968 }
2969 }
2970 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002971 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002972
2973 if (tv == NULL)
2974 {
2975 if (argvars[2].v_type != VAR_UNKNOWN)
2976 copy_tv(&argvars[2], rettv);
2977 }
2978 else
2979 copy_tv(tv, rettv);
2980}
2981
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002982/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002983 * "getchangelist()" function
2984 */
2985 static void
2986f_getchangelist(typval_T *argvars, typval_T *rettv)
2987{
2988#ifdef FEAT_JUMPLIST
2989 buf_T *buf;
2990 int i;
2991 list_T *l;
2992 dict_T *d;
2993#endif
2994
2995 if (rettv_list_alloc(rettv) != OK)
2996 return;
2997
2998#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002999 if (argvars[0].v_type == VAR_UNKNOWN)
3000 buf = curbuf;
3001 else
3002 {
3003 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3004 ++emsg_off;
3005 buf = tv_get_buf(&argvars[0], FALSE);
3006 --emsg_off;
3007 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003008 if (buf == NULL)
3009 return;
3010
3011 l = list_alloc();
3012 if (l == NULL)
3013 return;
3014
3015 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3016 return;
3017 /*
3018 * The current window change list index tracks only the position in the
3019 * current buffer change list. For other buffers, use the change list
3020 * length as the current index.
3021 */
3022 list_append_number(rettv->vval.v_list,
3023 (varnumber_T)((buf == curwin->w_buffer)
3024 ? curwin->w_changelistidx : buf->b_changelistlen));
3025
3026 for (i = 0; i < buf->b_changelistlen; ++i)
3027 {
3028 if (buf->b_changelist[i].lnum == 0)
3029 continue;
3030 if ((d = dict_alloc()) == NULL)
3031 return;
3032 if (list_append_dict(l, d) == FAIL)
3033 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003034 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3035 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003036 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003037 }
3038#endif
3039}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003040
3041/*
3042 * "getcharsearch()" function
3043 */
3044 static void
3045f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3046{
3047 if (rettv_dict_alloc(rettv) != FAIL)
3048 {
3049 dict_T *dict = rettv->vval.v_dict;
3050
Bram Moolenaare0be1672018-07-08 16:50:37 +02003051 dict_add_string(dict, "char", last_csearch());
3052 dict_add_number(dict, "forward", last_csearch_forward());
3053 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003054 }
3055}
3056
3057/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003058 * "getenv()" function
3059 */
3060 static void
3061f_getenv(typval_T *argvars, typval_T *rettv)
3062{
3063 int mustfree = FALSE;
3064 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3065
3066 if (p == NULL)
3067 {
3068 rettv->v_type = VAR_SPECIAL;
3069 rettv->vval.v_number = VVAL_NULL;
3070 return;
3071 }
3072 if (!mustfree)
3073 p = vim_strsave(p);
3074 rettv->vval.v_string = p;
3075 rettv->v_type = VAR_STRING;
3076}
3077
3078/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079 * "getfontname()" function
3080 */
3081 static void
3082f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3083{
3084 rettv->v_type = VAR_STRING;
3085 rettv->vval.v_string = NULL;
3086#ifdef FEAT_GUI
3087 if (gui.in_use)
3088 {
3089 GuiFont font;
3090 char_u *name = NULL;
3091
3092 if (argvars[0].v_type == VAR_UNKNOWN)
3093 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003094 // Get the "Normal" font. Either the name saved by
3095 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 font = gui.norm_font;
3097 name = hl_get_font_name();
3098 }
3099 else
3100 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003101 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003102 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003103 return;
3104 font = gui_mch_get_font(name, FALSE);
3105 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003106 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003107 }
3108 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3109 if (argvars[0].v_type != VAR_UNKNOWN)
3110 gui_mch_free_font(font);
3111 }
3112#endif
3113}
3114
3115/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003116 * "getjumplist()" function
3117 */
3118 static void
3119f_getjumplist(typval_T *argvars, typval_T *rettv)
3120{
3121#ifdef FEAT_JUMPLIST
3122 win_T *wp;
3123 int i;
3124 list_T *l;
3125 dict_T *d;
3126#endif
3127
3128 if (rettv_list_alloc(rettv) != OK)
3129 return;
3130
3131#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003132 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003133 if (wp == NULL)
3134 return;
3135
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003136 cleanup_jumplist(wp, TRUE);
3137
Bram Moolenaar4f505882018-02-10 21:06:32 +01003138 l = list_alloc();
3139 if (l == NULL)
3140 return;
3141
3142 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3143 return;
3144 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3145
3146 for (i = 0; i < wp->w_jumplistlen; ++i)
3147 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003148 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3149 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003150 if ((d = dict_alloc()) == NULL)
3151 return;
3152 if (list_append_dict(l, d) == FAIL)
3153 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003154 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3155 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003156 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003157 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003158 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003159 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003160 }
3161#endif
3162}
3163
3164/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003165 * "getpid()" function
3166 */
3167 static void
3168f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3169{
3170 rettv->vval.v_number = mch_get_pid();
3171}
3172
3173 static void
3174getpos_both(
3175 typval_T *argvars,
3176 typval_T *rettv,
3177 int getcurpos)
3178{
3179 pos_T *fp;
3180 list_T *l;
3181 int fnum = -1;
3182
3183 if (rettv_list_alloc(rettv) == OK)
3184 {
3185 l = rettv->vval.v_list;
3186 if (getcurpos)
3187 fp = &curwin->w_cursor;
3188 else
3189 fp = var2fpos(&argvars[0], TRUE, &fnum);
3190 if (fnum != -1)
3191 list_append_number(l, (varnumber_T)fnum);
3192 else
3193 list_append_number(l, (varnumber_T)0);
3194 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3195 : (varnumber_T)0);
3196 list_append_number(l, (fp != NULL)
3197 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3198 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003199 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003200 (varnumber_T)0);
3201 if (getcurpos)
3202 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003203 int save_set_curswant = curwin->w_set_curswant;
3204 colnr_T save_curswant = curwin->w_curswant;
3205 colnr_T save_virtcol = curwin->w_virtcol;
3206
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003207 update_curswant();
3208 list_append_number(l, curwin->w_curswant == MAXCOL ?
3209 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003210
3211 // Do not change "curswant", as it is unexpected that a get
3212 // function has a side effect.
3213 if (save_set_curswant)
3214 {
3215 curwin->w_set_curswant = save_set_curswant;
3216 curwin->w_curswant = save_curswant;
3217 curwin->w_virtcol = save_virtcol;
3218 curwin->w_valid &= ~VALID_VIRTCOL;
3219 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003220 }
3221 }
3222 else
3223 rettv->vval.v_number = FALSE;
3224}
3225
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003226/*
3227 * "getcurpos()" function
3228 */
3229 static void
3230f_getcurpos(typval_T *argvars, typval_T *rettv)
3231{
3232 getpos_both(argvars, rettv, TRUE);
3233}
3234
3235/*
3236 * "getpos(string)" function
3237 */
3238 static void
3239f_getpos(typval_T *argvars, typval_T *rettv)
3240{
3241 getpos_both(argvars, rettv, FALSE);
3242}
3243
3244/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003245 * "getreg()" function
3246 */
3247 static void
3248f_getreg(typval_T *argvars, typval_T *rettv)
3249{
3250 char_u *strregname;
3251 int regname;
3252 int arg2 = FALSE;
3253 int return_list = FALSE;
3254 int error = FALSE;
3255
3256 if (argvars[0].v_type != VAR_UNKNOWN)
3257 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003258 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003259 error = strregname == NULL;
3260 if (argvars[1].v_type != VAR_UNKNOWN)
3261 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003262 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003263 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003264 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003265 }
3266 }
3267 else
3268 strregname = get_vim_var_str(VV_REG);
3269
3270 if (error)
3271 return;
3272
3273 regname = (strregname == NULL ? '"' : *strregname);
3274 if (regname == 0)
3275 regname = '"';
3276
3277 if (return_list)
3278 {
3279 rettv->v_type = VAR_LIST;
3280 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3281 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3282 if (rettv->vval.v_list == NULL)
3283 (void)rettv_list_alloc(rettv);
3284 else
3285 ++rettv->vval.v_list->lv_refcount;
3286 }
3287 else
3288 {
3289 rettv->v_type = VAR_STRING;
3290 rettv->vval.v_string = get_reg_contents(regname,
3291 arg2 ? GREG_EXPR_SRC : 0);
3292 }
3293}
3294
3295/*
3296 * "getregtype()" function
3297 */
3298 static void
3299f_getregtype(typval_T *argvars, typval_T *rettv)
3300{
3301 char_u *strregname;
3302 int regname;
3303 char_u buf[NUMBUFLEN + 2];
3304 long reglen = 0;
3305
3306 if (argvars[0].v_type != VAR_UNKNOWN)
3307 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003308 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003309 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003310 {
3311 rettv->v_type = VAR_STRING;
3312 rettv->vval.v_string = NULL;
3313 return;
3314 }
3315 }
3316 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003317 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003318 strregname = get_vim_var_str(VV_REG);
3319
3320 regname = (strregname == NULL ? '"' : *strregname);
3321 if (regname == 0)
3322 regname = '"';
3323
3324 buf[0] = NUL;
3325 buf[1] = NUL;
3326 switch (get_reg_type(regname, &reglen))
3327 {
3328 case MLINE: buf[0] = 'V'; break;
3329 case MCHAR: buf[0] = 'v'; break;
3330 case MBLOCK:
3331 buf[0] = Ctrl_V;
3332 sprintf((char *)buf + 1, "%ld", reglen + 1);
3333 break;
3334 }
3335 rettv->v_type = VAR_STRING;
3336 rettv->vval.v_string = vim_strsave(buf);
3337}
3338
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003339/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003340 * "gettagstack()" function
3341 */
3342 static void
3343f_gettagstack(typval_T *argvars, typval_T *rettv)
3344{
3345 win_T *wp = curwin; // default is current window
3346
3347 if (rettv_dict_alloc(rettv) != OK)
3348 return;
3349
3350 if (argvars[0].v_type != VAR_UNKNOWN)
3351 {
3352 wp = find_win_by_nr_or_id(&argvars[0]);
3353 if (wp == NULL)
3354 return;
3355 }
3356
3357 get_tagstack(wp, rettv->vval.v_dict);
3358}
3359
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003360// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003361#include "version.h"
3362
3363/*
3364 * "has()" function
3365 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003366 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003367f_has(typval_T *argvars, typval_T *rettv)
3368{
3369 int i;
3370 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003371 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003372 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003373 typedef struct {
3374 char *name;
3375 short present;
3376 } has_item_T;
3377 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003379 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003381 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003382#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003383 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003384#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003385 },
3386 {"arp",
3387#if defined(AMIGA) && defined(FEAT_ARP)
3388 1
3389#else
3390 0
3391#endif
3392 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003393 {"haiku",
3394#ifdef __HAIKU__
3395 1
3396#else
3397 0
3398#endif
3399 },
3400 {"bsd",
3401#if defined(BSD) && !defined(MACOS_X)
3402 1
3403#else
3404 0
3405#endif
3406 },
3407 {"hpux",
3408#ifdef hpux
3409 1
3410#else
3411 0
3412#endif
3413 },
3414 {"linux",
3415#ifdef __linux__
3416 1
3417#else
3418 0
3419#endif
3420 },
3421 {"mac", // Mac OS X (and, once, Mac OS Classic)
3422#ifdef MACOS_X
3423 1
3424#else
3425 0
3426#endif
3427 },
3428 {"osx", // Mac OS X
3429#ifdef MACOS_X
3430 1
3431#else
3432 0
3433#endif
3434 },
3435 {"macunix", // Mac OS X, with the darwin feature
3436#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3437 1
3438#else
3439 0
3440#endif
3441 },
3442 {"osxdarwin", // synonym for macunix
3443#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3444 1
3445#else
3446 0
3447#endif
3448 },
3449 {"qnx",
3450#ifdef __QNX__
3451 1
3452#else
3453 0
3454#endif
3455 },
3456 {"sun",
3457#ifdef SUN_SYSTEM
3458 1
3459#else
3460 0
3461#endif
3462 },
3463 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003464#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003465 1
3466#else
3467 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003469 },
3470 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003472 1
3473#else
3474 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003476 },
3477 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003478#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003479 1
3480#else
3481 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003482#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003483 },
3484 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003485#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003486 1
3487#else
3488 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003489#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003490 },
3491 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003492#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003493 1
3494#else
3495 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003496#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003497 },
3498 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003499#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003500 1
3501#else
3502 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003504 },
3505 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003507 1
3508#else
3509 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003510#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003511 },
3512 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003513#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003514 1
3515#else
3516 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003518 },
3519 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003521 1
3522#else
3523 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003524#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003525 },
3526 {"autocmd", 1},
3527 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003528#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003529 1
3530#else
3531 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003532#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003533 },
3534 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003535#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003536 1
3537#else
3538 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003539#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003540 },
3541 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003542#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003543 1
3544#else
3545 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003547 },
3548 {"balloon_multiline",
3549#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3550 // MS-Windows requires runtime check, see below
3551 1
3552#else
3553 0
3554#endif
3555 },
3556 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003557#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003558 1
3559#else
3560 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003561#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003562 },
3563 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003564#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003565 1
3566#else
3567 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003569 },
3570 {"all_builtin_terms",
3571#if defined(ALL_BUILTIN_TCAPS)
3572 1
3573#else
3574 0
3575#endif
3576 },
3577 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003579 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003580 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003581 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003583 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003584#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003585 },
3586 {"byte_offset",
3587#ifdef FEAT_BYTEOFF
3588 1
3589#else
3590 0
3591#endif
3592 },
3593 {"channel",
3594#ifdef FEAT_JOB_CHANNEL
3595 1
3596#else
3597 0
3598#endif
3599 },
3600 {"cindent",
3601#ifdef FEAT_CINDENT
3602 1
3603#else
3604 0
3605#endif
3606 },
3607 {"clientserver",
3608#ifdef FEAT_CLIENTSERVER
3609 1
3610#else
3611 0
3612#endif
3613 },
3614 {"clipboard",
3615#ifdef FEAT_CLIPBOARD
3616 1
3617#else
3618 0
3619#endif
3620 },
3621 {"cmdline_compl", 1},
3622 {"cmdline_hist", 1},
3623 {"comments", 1},
3624 {"conceal",
3625#ifdef FEAT_CONCEAL
3626 1
3627#else
3628 0
3629#endif
3630 },
3631 {"cryptv",
3632#ifdef FEAT_CRYPT
3633 1
3634#else
3635 0
3636#endif
3637 },
3638 {"crypt-blowfish",
3639#ifdef FEAT_CRYPT
3640 1
3641#else
3642 0
3643#endif
3644 },
3645 {"crypt-blowfish2",
3646#ifdef FEAT_CRYPT
3647 1
3648#else
3649 0
3650#endif
3651 },
3652 {"cscope",
3653#ifdef FEAT_CSCOPE
3654 1
3655#else
3656 0
3657#endif
3658 },
3659 {"cursorbind", 1},
3660 {"cursorshape",
3661#ifdef CURSOR_SHAPE
3662 1
3663#else
3664 0
3665#endif
3666 },
3667 {"debug",
3668#ifdef DEBUG
3669 1
3670#else
3671 0
3672#endif
3673 },
3674 {"dialog_con",
3675#ifdef FEAT_CON_DIALOG
3676 1
3677#else
3678 0
3679#endif
3680 },
3681 {"dialog_gui",
3682#ifdef FEAT_GUI_DIALOG
3683 1
3684#else
3685 0
3686#endif
3687 },
3688 {"diff",
3689#ifdef FEAT_DIFF
3690 1
3691#else
3692 0
3693#endif
3694 },
3695 {"digraphs",
3696#ifdef FEAT_DIGRAPHS
3697 1
3698#else
3699 0
3700#endif
3701 },
3702 {"directx",
3703#ifdef FEAT_DIRECTX
3704 1
3705#else
3706 0
3707#endif
3708 },
3709 {"dnd",
3710#ifdef FEAT_DND
3711 1
3712#else
3713 0
3714#endif
3715 },
3716 {"emacs_tags",
3717#ifdef FEAT_EMACS_TAGS
3718 1
3719#else
3720 0
3721#endif
3722 },
3723 {"eval", 1}, // always present, of course!
3724 {"ex_extra", 1}, // graduated feature
3725 {"extra_search",
3726#ifdef FEAT_SEARCH_EXTRA
3727 1
3728#else
3729 0
3730#endif
3731 },
3732 {"file_in_path",
3733#ifdef FEAT_SEARCHPATH
3734 1
3735#else
3736 0
3737#endif
3738 },
3739 {"filterpipe",
3740#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3741 1
3742#else
3743 0
3744#endif
3745 },
3746 {"find_in_path",
3747#ifdef FEAT_FIND_ID
3748 1
3749#else
3750 0
3751#endif
3752 },
3753 {"float",
3754#ifdef FEAT_FLOAT
3755 1
3756#else
3757 0
3758#endif
3759 },
3760 {"folding",
3761#ifdef FEAT_FOLDING
3762 1
3763#else
3764 0
3765#endif
3766 },
3767 {"footer",
3768#ifdef FEAT_FOOTER
3769 1
3770#else
3771 0
3772#endif
3773 },
3774 {"fork",
3775#if !defined(USE_SYSTEM) && defined(UNIX)
3776 1
3777#else
3778 0
3779#endif
3780 },
3781 {"gettext",
3782#ifdef FEAT_GETTEXT
3783 1
3784#else
3785 0
3786#endif
3787 },
3788 {"gui",
3789#ifdef FEAT_GUI
3790 1
3791#else
3792 0
3793#endif
3794 },
3795 {"gui_neXtaw",
3796#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3797 1
3798#else
3799 0
3800#endif
3801 },
3802 {"gui_athena",
3803#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3804 1
3805#else
3806 0
3807#endif
3808 },
3809 {"gui_gtk",
3810#ifdef FEAT_GUI_GTK
3811 1
3812#else
3813 0
3814#endif
3815 },
3816 {"gui_gtk2",
3817#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3818 1
3819#else
3820 0
3821#endif
3822 },
3823 {"gui_gtk3",
3824#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3825 1
3826#else
3827 0
3828#endif
3829 },
3830 {"gui_gnome",
3831#ifdef FEAT_GUI_GNOME
3832 1
3833#else
3834 0
3835#endif
3836 },
3837 {"gui_haiku",
3838#ifdef FEAT_GUI_HAIKU
3839 1
3840#else
3841 0
3842#endif
3843 },
3844 {"gui_mac",
3845#ifdef FEAT_GUI_MAC
3846 1
3847#else
3848 0
3849#endif
3850 },
3851 {"gui_motif",
3852#ifdef FEAT_GUI_MOTIF
3853 1
3854#else
3855 0
3856#endif
3857 },
3858 {"gui_photon",
3859#ifdef FEAT_GUI_PHOTON
3860 1
3861#else
3862 0
3863#endif
3864 },
3865 {"gui_win32",
3866#ifdef FEAT_GUI_MSWIN
3867 1
3868#else
3869 0
3870#endif
3871 },
3872 {"iconv",
3873#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3874 1
3875#else
3876 0
3877#endif
3878 },
3879 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003880 {"ipv6",
3881#ifdef FEAT_IPV6
3882 1
3883#else
3884 0
3885#endif
3886 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003887 {"job",
3888#ifdef FEAT_JOB_CHANNEL
3889 1
3890#else
3891 0
3892#endif
3893 },
3894 {"jumplist",
3895#ifdef FEAT_JUMPLIST
3896 1
3897#else
3898 0
3899#endif
3900 },
3901 {"keymap",
3902#ifdef FEAT_KEYMAP
3903 1
3904#else
3905 0
3906#endif
3907 },
3908 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
3909 {"langmap",
3910#ifdef FEAT_LANGMAP
3911 1
3912#else
3913 0
3914#endif
3915 },
3916 {"libcall",
3917#ifdef FEAT_LIBCALL
3918 1
3919#else
3920 0
3921#endif
3922 },
3923 {"linebreak",
3924#ifdef FEAT_LINEBREAK
3925 1
3926#else
3927 0
3928#endif
3929 },
3930 {"lispindent",
3931#ifdef FEAT_LISP
3932 1
3933#else
3934 0
3935#endif
3936 },
3937 {"listcmds", 1},
3938 {"localmap", 1},
3939 {"lua",
3940#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
3941 1
3942#else
3943 0
3944#endif
3945 },
3946 {"menu",
3947#ifdef FEAT_MENU
3948 1
3949#else
3950 0
3951#endif
3952 },
3953 {"mksession",
3954#ifdef FEAT_SESSION
3955 1
3956#else
3957 0
3958#endif
3959 },
3960 {"modify_fname", 1},
3961 {"mouse", 1},
3962 {"mouseshape",
3963#ifdef FEAT_MOUSESHAPE
3964 1
3965#else
3966 0
3967#endif
3968 },
3969 {"mouse_dec",
3970#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
3971 1
3972#else
3973 0
3974#endif
3975 },
3976 {"mouse_gpm",
3977#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
3978 1
3979#else
3980 0
3981#endif
3982 },
3983 {"mouse_jsbterm",
3984#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
3985 1
3986#else
3987 0
3988#endif
3989 },
3990 {"mouse_netterm",
3991#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
3992 1
3993#else
3994 0
3995#endif
3996 },
3997 {"mouse_pterm",
3998#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
3999 1
4000#else
4001 0
4002#endif
4003 },
4004 {"mouse_sgr",
4005#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4006 1
4007#else
4008 0
4009#endif
4010 },
4011 {"mouse_sysmouse",
4012#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4013 1
4014#else
4015 0
4016#endif
4017 },
4018 {"mouse_urxvt",
4019#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4020 1
4021#else
4022 0
4023#endif
4024 },
4025 {"mouse_xterm",
4026#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4027 1
4028#else
4029 0
4030#endif
4031 },
4032 {"multi_byte", 1},
4033 {"multi_byte_ime",
4034#ifdef FEAT_MBYTE_IME
4035 1
4036#else
4037 0
4038#endif
4039 },
4040 {"multi_lang",
4041#ifdef FEAT_MULTI_LANG
4042 1
4043#else
4044 0
4045#endif
4046 },
4047 {"mzscheme",
4048#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4049 1
4050#else
4051 0
4052#endif
4053 },
4054 {"num64", 1},
4055 {"ole",
4056#ifdef FEAT_OLE
4057 1
4058#else
4059 0
4060#endif
4061 },
4062 {"packages",
4063#ifdef FEAT_EVAL
4064 1
4065#else
4066 0
4067#endif
4068 },
4069 {"path_extra",
4070#ifdef FEAT_PATH_EXTRA
4071 1
4072#else
4073 0
4074#endif
4075 },
4076 {"perl",
4077#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4078 1
4079#else
4080 0
4081#endif
4082 },
4083 {"persistent_undo",
4084#ifdef FEAT_PERSISTENT_UNDO
4085 1
4086#else
4087 0
4088#endif
4089 },
4090 {"python_compiled",
4091#if defined(FEAT_PYTHON)
4092 1
4093#else
4094 0
4095#endif
4096 },
4097 {"python_dynamic",
4098#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4099 1
4100#else
4101 0
4102#endif
4103 },
4104 {"python",
4105#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4106 1
4107#else
4108 0
4109#endif
4110 },
4111 {"pythonx",
4112#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4113 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4114 1
4115#else
4116 0
4117#endif
4118 },
4119 {"python3_compiled",
4120#if defined(FEAT_PYTHON3)
4121 1
4122#else
4123 0
4124#endif
4125 },
4126 {"python3_dynamic",
4127#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4128 1
4129#else
4130 0
4131#endif
4132 },
4133 {"python3",
4134#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4135 1
4136#else
4137 0
4138#endif
4139 },
4140 {"popupwin",
4141#ifdef FEAT_PROP_POPUP
4142 1
4143#else
4144 0
4145#endif
4146 },
4147 {"postscript",
4148#ifdef FEAT_POSTSCRIPT
4149 1
4150#else
4151 0
4152#endif
4153 },
4154 {"printer",
4155#ifdef FEAT_PRINTER
4156 1
4157#else
4158 0
4159#endif
4160 },
4161 {"profile",
4162#ifdef FEAT_PROFILE
4163 1
4164#else
4165 0
4166#endif
4167 },
4168 {"reltime",
4169#ifdef FEAT_RELTIME
4170 1
4171#else
4172 0
4173#endif
4174 },
4175 {"quickfix",
4176#ifdef FEAT_QUICKFIX
4177 1
4178#else
4179 0
4180#endif
4181 },
4182 {"rightleft",
4183#ifdef FEAT_RIGHTLEFT
4184 1
4185#else
4186 0
4187#endif
4188 },
4189 {"ruby",
4190#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4191 1
4192#else
4193 0
4194#endif
4195 },
4196 {"scrollbind", 1},
4197 {"showcmd",
4198#ifdef FEAT_CMDL_INFO
4199 1
4200#else
4201 0
4202#endif
4203 },
4204 {"cmdline_info",
4205#ifdef FEAT_CMDL_INFO
4206 1
4207#else
4208 0
4209#endif
4210 },
4211 {"signs",
4212#ifdef FEAT_SIGNS
4213 1
4214#else
4215 0
4216#endif
4217 },
4218 {"smartindent",
4219#ifdef FEAT_SMARTINDENT
4220 1
4221#else
4222 0
4223#endif
4224 },
4225 {"startuptime",
4226#ifdef STARTUPTIME
4227 1
4228#else
4229 0
4230#endif
4231 },
4232 {"statusline",
4233#ifdef FEAT_STL_OPT
4234 1
4235#else
4236 0
4237#endif
4238 },
4239 {"netbeans_intg",
4240#ifdef FEAT_NETBEANS_INTG
4241 1
4242#else
4243 0
4244#endif
4245 },
4246 {"sound",
4247#ifdef FEAT_SOUND
4248 1
4249#else
4250 0
4251#endif
4252 },
4253 {"spell",
4254#ifdef FEAT_SPELL
4255 1
4256#else
4257 0
4258#endif
4259 },
4260 {"syntax",
4261#ifdef FEAT_SYN_HL
4262 1
4263#else
4264 0
4265#endif
4266 },
4267 {"system",
4268#if defined(USE_SYSTEM) || !defined(UNIX)
4269 1
4270#else
4271 0
4272#endif
4273 },
4274 {"tag_binary",
4275#ifdef FEAT_TAG_BINS
4276 1
4277#else
4278 0
4279#endif
4280 },
4281 {"tcl",
4282#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4283 1
4284#else
4285 0
4286#endif
4287 },
4288 {"termguicolors",
4289#ifdef FEAT_TERMGUICOLORS
4290 1
4291#else
4292 0
4293#endif
4294 },
4295 {"terminal",
4296#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4297 1
4298#else
4299 0
4300#endif
4301 },
4302 {"terminfo",
4303#ifdef TERMINFO
4304 1
4305#else
4306 0
4307#endif
4308 },
4309 {"termresponse",
4310#ifdef FEAT_TERMRESPONSE
4311 1
4312#else
4313 0
4314#endif
4315 },
4316 {"textobjects",
4317#ifdef FEAT_TEXTOBJ
4318 1
4319#else
4320 0
4321#endif
4322 },
4323 {"textprop",
4324#ifdef FEAT_PROP_POPUP
4325 1
4326#else
4327 0
4328#endif
4329 },
4330 {"tgetent",
4331#ifdef HAVE_TGETENT
4332 1
4333#else
4334 0
4335#endif
4336 },
4337 {"timers",
4338#ifdef FEAT_TIMERS
4339 1
4340#else
4341 0
4342#endif
4343 },
4344 {"title",
4345#ifdef FEAT_TITLE
4346 1
4347#else
4348 0
4349#endif
4350 },
4351 {"toolbar",
4352#ifdef FEAT_TOOLBAR
4353 1
4354#else
4355 0
4356#endif
4357 },
4358 {"unnamedplus",
4359#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4360 1
4361#else
4362 0
4363#endif
4364 },
4365 {"user-commands", 1}, // was accidentally included in 5.4
4366 {"user_commands", 1},
4367 {"vartabs",
4368#ifdef FEAT_VARTABS
4369 1
4370#else
4371 0
4372#endif
4373 },
4374 {"vertsplit", 1},
4375 {"viminfo",
4376#ifdef FEAT_VIMINFO
4377 1
4378#else
4379 0
4380#endif
4381 },
4382 {"vimscript-1", 1},
4383 {"vimscript-2", 1},
4384 {"vimscript-3", 1},
4385 {"vimscript-4", 1},
4386 {"virtualedit", 1},
4387 {"visual", 1},
4388 {"visualextra", 1},
4389 {"vreplace", 1},
4390 {"vtp",
4391#ifdef FEAT_VTP
4392 1
4393#else
4394 0
4395#endif
4396 },
4397 {"wildignore",
4398#ifdef FEAT_WILDIGN
4399 1
4400#else
4401 0
4402#endif
4403 },
4404 {"wildmenu",
4405#ifdef FEAT_WILDMENU
4406 1
4407#else
4408 0
4409#endif
4410 },
4411 {"windows", 1},
4412 {"winaltkeys",
4413#ifdef FEAT_WAK
4414 1
4415#else
4416 0
4417#endif
4418 },
4419 {"writebackup",
4420#ifdef FEAT_WRITEBACKUP
4421 1
4422#else
4423 0
4424#endif
4425 },
4426 {"xim",
4427#ifdef FEAT_XIM
4428 1
4429#else
4430 0
4431#endif
4432 },
4433 {"xfontset",
4434#ifdef FEAT_XFONTSET
4435 1
4436#else
4437 0
4438#endif
4439 },
4440 {"xpm",
4441#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4442 1
4443#else
4444 0
4445#endif
4446 },
4447 {"xpm_w32", // for backward compatibility
4448#ifdef FEAT_XPM_W32
4449 1
4450#else
4451 0
4452#endif
4453 },
4454 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004455#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004456 1
4457#else
4458 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004460 },
4461 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004462#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004463 1
4464#else
4465 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004467 },
4468 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004470 1
4471#else
4472 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004473#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004474 },
4475 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004477 1
4478#else
4479 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004480#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004481 },
4482 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004483#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004484 1
4485#else
4486 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004488 },
4489 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004490 };
4491
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004492 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004493 for (i = 0; has_list[i].name != NULL; ++i)
4494 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004495 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004496 x = TRUE;
4497 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004498 break;
4499 }
4500
Bram Moolenaar79296512020-03-22 16:17:14 +01004501 // features also in has_list[] but sometimes enabled at runtime
4502 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004503 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004504 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004505 {
4506 // intentionally empty
4507 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004508#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004509 else if (STRICMP(name, "balloon_multiline") == 0)
4510 n = multiline_balloon_available();
4511#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004512#ifdef VIMDLL
4513 else if (STRICMP(name, "filterpipe") == 0)
4514 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004515#endif
4516#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4517 else if (STRICMP(name, "iconv") == 0)
4518 n = iconv_enabled(FALSE);
4519#endif
4520#ifdef DYNAMIC_LUA
4521 else if (STRICMP(name, "lua") == 0)
4522 n = lua_enabled(FALSE);
4523#endif
4524#ifdef DYNAMIC_MZSCHEME
4525 else if (STRICMP(name, "mzscheme") == 0)
4526 n = mzscheme_enabled(FALSE);
4527#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004528#ifdef DYNAMIC_PERL
4529 else if (STRICMP(name, "perl") == 0)
4530 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004531#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004532#ifdef DYNAMIC_PYTHON
4533 else if (STRICMP(name, "python") == 0)
4534 n = python_enabled(FALSE);
4535#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004536#ifdef DYNAMIC_PYTHON3
4537 else if (STRICMP(name, "python3") == 0)
4538 n = python3_enabled(FALSE);
4539#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004540#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4541 else if (STRICMP(name, "pythonx") == 0)
4542 {
4543# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4544 if (p_pyx == 0)
4545 n = python3_enabled(FALSE) || python_enabled(FALSE);
4546 else if (p_pyx == 3)
4547 n = python3_enabled(FALSE);
4548 else if (p_pyx == 2)
4549 n = python_enabled(FALSE);
4550# elif defined(DYNAMIC_PYTHON)
4551 n = python_enabled(FALSE);
4552# elif defined(DYNAMIC_PYTHON3)
4553 n = python3_enabled(FALSE);
4554# endif
4555 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004556#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004557#ifdef DYNAMIC_RUBY
4558 else if (STRICMP(name, "ruby") == 0)
4559 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004561#ifdef DYNAMIC_TCL
4562 else if (STRICMP(name, "tcl") == 0)
4563 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004564#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004565#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004566 else if (STRICMP(name, "terminal") == 0)
4567 n = terminal_enabled();
4568#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004569 }
4570
Bram Moolenaar79296512020-03-22 16:17:14 +01004571 // features not in has_list[]
4572 if (x == FALSE)
4573 {
4574 if (STRNICMP(name, "patch", 5) == 0)
4575 {
4576 x = TRUE;
4577 if (name[5] == '-'
4578 && STRLEN(name) >= 11
4579 && vim_isdigit(name[6])
4580 && vim_isdigit(name[8])
4581 && vim_isdigit(name[10]))
4582 {
4583 int major = atoi((char *)name + 6);
4584 int minor = atoi((char *)name + 8);
4585
4586 // Expect "patch-9.9.01234".
4587 n = (major < VIM_VERSION_MAJOR
4588 || (major == VIM_VERSION_MAJOR
4589 && (minor < VIM_VERSION_MINOR
4590 || (minor == VIM_VERSION_MINOR
4591 && has_patch(atoi((char *)name + 10))))));
4592 }
4593 else
4594 n = has_patch(atoi((char *)name + 5));
4595 }
4596 else if (STRICMP(name, "vim_starting") == 0)
4597 {
4598 x = TRUE;
4599 n = (starting != 0);
4600 }
4601 else if (STRICMP(name, "ttyin") == 0)
4602 {
4603 x = TRUE;
4604 n = mch_input_isatty();
4605 }
4606 else if (STRICMP(name, "ttyout") == 0)
4607 {
4608 x = TRUE;
4609 n = stdout_isatty;
4610 }
4611 else if (STRICMP(name, "multi_byte_encoding") == 0)
4612 {
4613 x = TRUE;
4614 n = has_mbyte;
4615 }
4616 else if (STRICMP(name, "gui_running") == 0)
4617 {
4618 x = TRUE;
4619#ifdef FEAT_GUI
4620 n = (gui.in_use || gui.starting);
4621#endif
4622 }
4623 else if (STRICMP(name, "browse") == 0)
4624 {
4625 x = TRUE;
4626#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4627 n = gui.in_use; // gui_mch_browse() works when GUI is running
4628#endif
4629 }
4630 else if (STRICMP(name, "syntax_items") == 0)
4631 {
4632 x = TRUE;
4633#ifdef FEAT_SYN_HL
4634 n = syntax_present(curwin);
4635#endif
4636 }
4637 else if (STRICMP(name, "vcon") == 0)
4638 {
4639 x = TRUE;
4640#ifdef FEAT_VTP
4641 n = is_term_win32() && has_vtp_working();
4642#endif
4643 }
4644 else if (STRICMP(name, "netbeans_enabled") == 0)
4645 {
4646 x = TRUE;
4647#ifdef FEAT_NETBEANS_INTG
4648 n = netbeans_active();
4649#endif
4650 }
4651 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4652 {
4653 x = TRUE;
4654#ifdef FEAT_MOUSE_GPM
4655 n = gpm_enabled();
4656#endif
4657 }
4658 else if (STRICMP(name, "conpty") == 0)
4659 {
4660 x = TRUE;
4661#if defined(FEAT_TERMINAL) && defined(MSWIN)
4662 n = use_conpty();
4663#endif
4664 }
4665 else if (STRICMP(name, "clipboard_working") == 0)
4666 {
4667 x = TRUE;
4668#ifdef FEAT_CLIPBOARD
4669 n = clip_star.available;
4670#endif
4671 }
4672 }
4673
4674 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4675 // return whether feature could ever be enabled
4676 rettv->vval.v_number = x;
4677 else
4678 // return whether feature is enabled
4679 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004680}
4681
4682/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004683 * "haslocaldir()" function
4684 */
4685 static void
4686f_haslocaldir(typval_T *argvars, typval_T *rettv)
4687{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004688 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004689 win_T *wp = NULL;
4690
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004691 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4692
4693 // Check for window-local and tab-local directories
4694 if (wp != NULL && wp->w_localdir != NULL)
4695 rettv->vval.v_number = 1;
4696 else if (tp != NULL && tp->tp_localdir != NULL)
4697 rettv->vval.v_number = 2;
4698 else
4699 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700}
4701
4702/*
4703 * "hasmapto()" function
4704 */
4705 static void
4706f_hasmapto(typval_T *argvars, typval_T *rettv)
4707{
4708 char_u *name;
4709 char_u *mode;
4710 char_u buf[NUMBUFLEN];
4711 int abbr = FALSE;
4712
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004713 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004714 if (argvars[1].v_type == VAR_UNKNOWN)
4715 mode = (char_u *)"nvo";
4716 else
4717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004718 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004720 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004721 }
4722
4723 if (map_to_exists(name, mode, abbr))
4724 rettv->vval.v_number = TRUE;
4725 else
4726 rettv->vval.v_number = FALSE;
4727}
4728
4729/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004730 * "highlightID(name)" function
4731 */
4732 static void
4733f_hlID(typval_T *argvars, typval_T *rettv)
4734{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004735 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004736}
4737
4738/*
4739 * "highlight_exists()" function
4740 */
4741 static void
4742f_hlexists(typval_T *argvars, typval_T *rettv)
4743{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004744 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004745}
4746
4747/*
4748 * "hostname()" function
4749 */
4750 static void
4751f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4752{
4753 char_u hostname[256];
4754
4755 mch_get_host_name(hostname, 256);
4756 rettv->v_type = VAR_STRING;
4757 rettv->vval.v_string = vim_strsave(hostname);
4758}
4759
4760/*
4761 * iconv() function
4762 */
4763 static void
4764f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4765{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766 char_u buf1[NUMBUFLEN];
4767 char_u buf2[NUMBUFLEN];
4768 char_u *from, *to, *str;
4769 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004770
4771 rettv->v_type = VAR_STRING;
4772 rettv->vval.v_string = NULL;
4773
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004774 str = tv_get_string(&argvars[0]);
4775 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4776 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004777 vimconv.vc_type = CONV_NONE;
4778 convert_setup(&vimconv, from, to);
4779
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004780 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004781 if (vimconv.vc_type == CONV_NONE)
4782 rettv->vval.v_string = vim_strsave(str);
4783 else
4784 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4785
4786 convert_setup(&vimconv, NULL, NULL);
4787 vim_free(from);
4788 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004789}
4790
4791/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004792 * "index()" function
4793 */
4794 static void
4795f_index(typval_T *argvars, typval_T *rettv)
4796{
4797 list_T *l;
4798 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004799 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004800 long idx = 0;
4801 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004802 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004803
4804 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004805 if (argvars[0].v_type == VAR_BLOB)
4806 {
4807 typval_T tv;
4808 int start = 0;
4809
4810 if (argvars[2].v_type != VAR_UNKNOWN)
4811 {
4812 start = tv_get_number_chk(&argvars[2], &error);
4813 if (error)
4814 return;
4815 }
4816 b = argvars[0].vval.v_blob;
4817 if (b == NULL)
4818 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004819 if (start < 0)
4820 {
4821 start = blob_len(b) + start;
4822 if (start < 0)
4823 start = 0;
4824 }
4825
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004826 for (idx = start; idx < blob_len(b); ++idx)
4827 {
4828 tv.v_type = VAR_NUMBER;
4829 tv.vval.v_number = blob_get(b, idx);
4830 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4831 {
4832 rettv->vval.v_number = idx;
4833 return;
4834 }
4835 }
4836 return;
4837 }
4838 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004840 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841 return;
4842 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004843
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844 l = argvars[0].vval.v_list;
4845 if (l != NULL)
4846 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004847 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004848 item = l->lv_first;
4849 if (argvars[2].v_type != VAR_UNKNOWN)
4850 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004851 // Start at specified item. Use the cached index that list_find()
4852 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004853 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004854 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004855 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004856 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004857 if (error)
4858 item = NULL;
4859 }
4860
4861 for ( ; item != NULL; item = item->li_next, ++idx)
4862 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4863 {
4864 rettv->vval.v_number = idx;
4865 break;
4866 }
4867 }
4868}
4869
4870static int inputsecret_flag = 0;
4871
4872/*
4873 * "input()" function
4874 * Also handles inputsecret() when inputsecret is set.
4875 */
4876 static void
4877f_input(typval_T *argvars, typval_T *rettv)
4878{
4879 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4880}
4881
4882/*
4883 * "inputdialog()" function
4884 */
4885 static void
4886f_inputdialog(typval_T *argvars, typval_T *rettv)
4887{
4888#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004889 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004890 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4891 {
4892 char_u *message;
4893 char_u buf[NUMBUFLEN];
4894 char_u *defstr = (char_u *)"";
4895
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004896 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004897 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004898 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004899 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4900 else
4901 IObuff[0] = NUL;
4902 if (message != NULL && defstr != NULL
4903 && do_dialog(VIM_QUESTION, NULL, message,
4904 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4905 rettv->vval.v_string = vim_strsave(IObuff);
4906 else
4907 {
4908 if (message != NULL && defstr != NULL
4909 && argvars[1].v_type != VAR_UNKNOWN
4910 && argvars[2].v_type != VAR_UNKNOWN)
4911 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004912 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004913 else
4914 rettv->vval.v_string = NULL;
4915 }
4916 rettv->v_type = VAR_STRING;
4917 }
4918 else
4919#endif
4920 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4921}
4922
4923/*
4924 * "inputlist()" function
4925 */
4926 static void
4927f_inputlist(typval_T *argvars, typval_T *rettv)
4928{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004929 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930 listitem_T *li;
4931 int selected;
4932 int mouse_used;
4933
4934#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004935 // While starting up, there is no place to enter text. When running tests
4936 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004937 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004938 return;
4939#endif
4940 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4941 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004942 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004943 return;
4944 }
4945
4946 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004947 msg_row = Rows - 1; // for when 'cmdheight' > 1
4948 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004949 msg_scroll = TRUE;
4950 msg_clr_eos();
4951
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004952 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004953 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02004954 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004956 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004957 msg_putchar('\n');
4958 }
4959
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004960 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961 selected = prompt_for_number(&mouse_used);
4962 if (mouse_used)
4963 selected -= lines_left;
4964
4965 rettv->vval.v_number = selected;
4966}
4967
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004968static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4969
4970/*
4971 * "inputrestore()" function
4972 */
4973 static void
4974f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4975{
4976 if (ga_userinput.ga_len > 0)
4977 {
4978 --ga_userinput.ga_len;
4979 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4980 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004981 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004982 }
4983 else if (p_verbose > 1)
4984 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004985 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004986 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004987 }
4988}
4989
4990/*
4991 * "inputsave()" function
4992 */
4993 static void
4994f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4995{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004996 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004997 if (ga_grow(&ga_userinput, 1) == OK)
4998 {
4999 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5000 + ga_userinput.ga_len);
5001 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005002 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005003 }
5004 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005005 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005006}
5007
5008/*
5009 * "inputsecret()" function
5010 */
5011 static void
5012f_inputsecret(typval_T *argvars, typval_T *rettv)
5013{
5014 ++cmdline_star;
5015 ++inputsecret_flag;
5016 f_input(argvars, rettv);
5017 --cmdline_star;
5018 --inputsecret_flag;
5019}
5020
5021/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005022 * "interrupt()" function
5023 */
5024 static void
5025f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5026{
5027 got_int = TRUE;
5028}
5029
5030/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031 * "invert(expr)" function
5032 */
5033 static void
5034f_invert(typval_T *argvars, typval_T *rettv)
5035{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005036 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037}
5038
5039/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005040 * "islocked()" function
5041 */
5042 static void
5043f_islocked(typval_T *argvars, typval_T *rettv)
5044{
5045 lval_T lv;
5046 char_u *end;
5047 dictitem_T *di;
5048
5049 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005050 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005051 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005052 if (end != NULL && lv.ll_name != NULL)
5053 {
5054 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005055 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005056 else
5057 {
5058 if (lv.ll_tv == NULL)
5059 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005060 di = find_var(lv.ll_name, NULL, TRUE);
5061 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005062 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005063 // Consider a variable locked when:
5064 // 1. the variable itself is locked
5065 // 2. the value of the variable is locked.
5066 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005067 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5068 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005069 }
5070 }
5071 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005072 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005073 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005074 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005076 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5078 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005079 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005080 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5081 }
5082 }
5083
5084 clear_lval(&lv);
5085}
5086
5087#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5088/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005089 * "isinf()" function
5090 */
5091 static void
5092f_isinf(typval_T *argvars, typval_T *rettv)
5093{
5094 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5095 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5096}
5097
5098/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 * "isnan()" function
5100 */
5101 static void
5102f_isnan(typval_T *argvars, typval_T *rettv)
5103{
5104 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5105 && isnan(argvars[0].vval.v_float);
5106}
5107#endif
5108
5109/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110 * "last_buffer_nr()" function.
5111 */
5112 static void
5113f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5114{
5115 int n = 0;
5116 buf_T *buf;
5117
Bram Moolenaar29323592016-07-24 22:04:11 +02005118 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005119 if (n < buf->b_fnum)
5120 n = buf->b_fnum;
5121
5122 rettv->vval.v_number = n;
5123}
5124
5125/*
5126 * "len()" function
5127 */
5128 static void
5129f_len(typval_T *argvars, typval_T *rettv)
5130{
5131 switch (argvars[0].v_type)
5132 {
5133 case VAR_STRING:
5134 case VAR_NUMBER:
5135 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005136 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005138 case VAR_BLOB:
5139 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5140 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005141 case VAR_LIST:
5142 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5143 break;
5144 case VAR_DICT:
5145 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5146 break;
5147 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005148 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005149 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005150 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005151 case VAR_SPECIAL:
5152 case VAR_FLOAT:
5153 case VAR_FUNC:
5154 case VAR_PARTIAL:
5155 case VAR_JOB:
5156 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005157 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005158 break;
5159 }
5160}
5161
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005162 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005163libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005164{
5165#ifdef FEAT_LIBCALL
5166 char_u *string_in;
5167 char_u **string_result;
5168 int nr_result;
5169#endif
5170
5171 rettv->v_type = type;
5172 if (type != VAR_NUMBER)
5173 rettv->vval.v_string = NULL;
5174
5175 if (check_restricted() || check_secure())
5176 return;
5177
5178#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005179 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005180 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5181 {
5182 string_in = NULL;
5183 if (argvars[2].v_type == VAR_STRING)
5184 string_in = argvars[2].vval.v_string;
5185 if (type == VAR_NUMBER)
5186 string_result = NULL;
5187 else
5188 string_result = &rettv->vval.v_string;
5189 if (mch_libcall(argvars[0].vval.v_string,
5190 argvars[1].vval.v_string,
5191 string_in,
5192 argvars[2].vval.v_number,
5193 string_result,
5194 &nr_result) == OK
5195 && type == VAR_NUMBER)
5196 rettv->vval.v_number = nr_result;
5197 }
5198#endif
5199}
5200
5201/*
5202 * "libcall()" function
5203 */
5204 static void
5205f_libcall(typval_T *argvars, typval_T *rettv)
5206{
5207 libcall_common(argvars, rettv, VAR_STRING);
5208}
5209
5210/*
5211 * "libcallnr()" function
5212 */
5213 static void
5214f_libcallnr(typval_T *argvars, typval_T *rettv)
5215{
5216 libcall_common(argvars, rettv, VAR_NUMBER);
5217}
5218
5219/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005220 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005221 */
5222 static void
5223f_line(typval_T *argvars, typval_T *rettv)
5224{
5225 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005226 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005227 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005228 int id;
5229 tabpage_T *tp;
5230 win_T *wp;
5231 win_T *save_curwin;
5232 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005233
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005234 if (argvars[1].v_type != VAR_UNKNOWN)
5235 {
5236 // use window specified in the second argument
5237 id = (int)tv_get_number(&argvars[1]);
5238 wp = win_id2wp_tp(id, &tp);
5239 if (wp != NULL && tp != NULL)
5240 {
5241 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5242 == OK)
5243 {
5244 check_cursor();
5245 fp = var2fpos(&argvars[0], TRUE, &fnum);
5246 }
5247 restore_win_noblock(save_curwin, save_curtab, TRUE);
5248 }
5249 }
5250 else
5251 // use current window
5252 fp = var2fpos(&argvars[0], TRUE, &fnum);
5253
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005254 if (fp != NULL)
5255 lnum = fp->lnum;
5256 rettv->vval.v_number = lnum;
5257}
5258
5259/*
5260 * "line2byte(lnum)" function
5261 */
5262 static void
5263f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5264{
5265#ifndef FEAT_BYTEOFF
5266 rettv->vval.v_number = -1;
5267#else
5268 linenr_T lnum;
5269
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005270 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005271 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5272 rettv->vval.v_number = -1;
5273 else
5274 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5275 if (rettv->vval.v_number >= 0)
5276 ++rettv->vval.v_number;
5277#endif
5278}
5279
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005280#ifdef FEAT_FLOAT
5281/*
5282 * "log()" function
5283 */
5284 static void
5285f_log(typval_T *argvars, typval_T *rettv)
5286{
5287 float_T f = 0.0;
5288
5289 rettv->v_type = VAR_FLOAT;
5290 if (get_float_arg(argvars, &f) == OK)
5291 rettv->vval.v_float = log(f);
5292 else
5293 rettv->vval.v_float = 0.0;
5294}
5295
5296/*
5297 * "log10()" function
5298 */
5299 static void
5300f_log10(typval_T *argvars, typval_T *rettv)
5301{
5302 float_T f = 0.0;
5303
5304 rettv->v_type = VAR_FLOAT;
5305 if (get_float_arg(argvars, &f) == OK)
5306 rettv->vval.v_float = log10(f);
5307 else
5308 rettv->vval.v_float = 0.0;
5309}
5310#endif
5311
5312#ifdef FEAT_LUA
5313/*
5314 * "luaeval()" function
5315 */
5316 static void
5317f_luaeval(typval_T *argvars, typval_T *rettv)
5318{
5319 char_u *str;
5320 char_u buf[NUMBUFLEN];
5321
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005322 if (check_restricted() || check_secure())
5323 return;
5324
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005325 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005326 do_luaeval(str, argvars + 1, rettv);
5327}
5328#endif
5329
5330/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005331 * "maparg()" function
5332 */
5333 static void
5334f_maparg(typval_T *argvars, typval_T *rettv)
5335{
5336 get_maparg(argvars, rettv, TRUE);
5337}
5338
5339/*
5340 * "mapcheck()" function
5341 */
5342 static void
5343f_mapcheck(typval_T *argvars, typval_T *rettv)
5344{
5345 get_maparg(argvars, rettv, FALSE);
5346}
5347
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005348typedef enum
5349{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005350 MATCH_END, // matchend()
5351 MATCH_MATCH, // match()
5352 MATCH_STR, // matchstr()
5353 MATCH_LIST, // matchlist()
5354 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005355} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005356
5357 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005358find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005359{
5360 char_u *str = NULL;
5361 long len = 0;
5362 char_u *expr = NULL;
5363 char_u *pat;
5364 regmatch_T regmatch;
5365 char_u patbuf[NUMBUFLEN];
5366 char_u strbuf[NUMBUFLEN];
5367 char_u *save_cpo;
5368 long start = 0;
5369 long nth = 1;
5370 colnr_T startcol = 0;
5371 int match = 0;
5372 list_T *l = NULL;
5373 listitem_T *li = NULL;
5374 long idx = 0;
5375 char_u *tofree = NULL;
5376
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005377 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005378 save_cpo = p_cpo;
5379 p_cpo = (char_u *)"";
5380
5381 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005382 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005383 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005384 // type MATCH_LIST: return empty list when there are no matches.
5385 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005386 if (rettv_list_alloc(rettv) == FAIL)
5387 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005388 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005389 && (list_append_string(rettv->vval.v_list,
5390 (char_u *)"", 0) == 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 || list_append_number(rettv->vval.v_list,
5396 (varnumber_T)-1) == FAIL))
5397 {
5398 list_free(rettv->vval.v_list);
5399 rettv->vval.v_list = NULL;
5400 goto theend;
5401 }
5402 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005403 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005404 {
5405 rettv->v_type = VAR_STRING;
5406 rettv->vval.v_string = NULL;
5407 }
5408
5409 if (argvars[0].v_type == VAR_LIST)
5410 {
5411 if ((l = argvars[0].vval.v_list) == NULL)
5412 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005413 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005414 li = l->lv_first;
5415 }
5416 else
5417 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005418 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005419 len = (long)STRLEN(str);
5420 }
5421
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005422 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005423 if (pat == NULL)
5424 goto theend;
5425
5426 if (argvars[2].v_type != VAR_UNKNOWN)
5427 {
5428 int error = FALSE;
5429
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005430 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005431 if (error)
5432 goto theend;
5433 if (l != NULL)
5434 {
5435 li = list_find(l, start);
5436 if (li == NULL)
5437 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005438 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005439 }
5440 else
5441 {
5442 if (start < 0)
5443 start = 0;
5444 if (start > len)
5445 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005446 // When "count" argument is there ignore matches before "start",
5447 // otherwise skip part of the string. Differs when pattern is "^"
5448 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005449 if (argvars[3].v_type != VAR_UNKNOWN)
5450 startcol = start;
5451 else
5452 {
5453 str += start;
5454 len -= start;
5455 }
5456 }
5457
5458 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005459 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005460 if (error)
5461 goto theend;
5462 }
5463
5464 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5465 if (regmatch.regprog != NULL)
5466 {
5467 regmatch.rm_ic = p_ic;
5468
5469 for (;;)
5470 {
5471 if (l != NULL)
5472 {
5473 if (li == NULL)
5474 {
5475 match = FALSE;
5476 break;
5477 }
5478 vim_free(tofree);
5479 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5480 if (str == NULL)
5481 break;
5482 }
5483
5484 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5485
5486 if (match && --nth <= 0)
5487 break;
5488 if (l == NULL && !match)
5489 break;
5490
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005491 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005492 if (l != NULL)
5493 {
5494 li = li->li_next;
5495 ++idx;
5496 }
5497 else
5498 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005499 startcol = (colnr_T)(regmatch.startp[0]
5500 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005501 if (startcol > (colnr_T)len
5502 || str + startcol <= regmatch.startp[0])
5503 {
5504 match = FALSE;
5505 break;
5506 }
5507 }
5508 }
5509
5510 if (match)
5511 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005512 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005513 {
5514 listitem_T *li1 = rettv->vval.v_list->lv_first;
5515 listitem_T *li2 = li1->li_next;
5516 listitem_T *li3 = li2->li_next;
5517 listitem_T *li4 = li3->li_next;
5518
5519 vim_free(li1->li_tv.vval.v_string);
5520 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5521 (int)(regmatch.endp[0] - regmatch.startp[0]));
5522 li3->li_tv.vval.v_number =
5523 (varnumber_T)(regmatch.startp[0] - expr);
5524 li4->li_tv.vval.v_number =
5525 (varnumber_T)(regmatch.endp[0] - expr);
5526 if (l != NULL)
5527 li2->li_tv.vval.v_number = (varnumber_T)idx;
5528 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005529 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005530 {
5531 int i;
5532
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005533 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005534 for (i = 0; i < NSUBEXP; ++i)
5535 {
5536 if (regmatch.endp[i] == NULL)
5537 {
5538 if (list_append_string(rettv->vval.v_list,
5539 (char_u *)"", 0) == FAIL)
5540 break;
5541 }
5542 else if (list_append_string(rettv->vval.v_list,
5543 regmatch.startp[i],
5544 (int)(regmatch.endp[i] - regmatch.startp[i]))
5545 == FAIL)
5546 break;
5547 }
5548 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005549 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005550 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005551 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005552 if (l != NULL)
5553 copy_tv(&li->li_tv, rettv);
5554 else
5555 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
5556 (int)(regmatch.endp[0] - regmatch.startp[0]));
5557 }
5558 else if (l != NULL)
5559 rettv->vval.v_number = idx;
5560 else
5561 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005562 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005563 rettv->vval.v_number =
5564 (varnumber_T)(regmatch.startp[0] - str);
5565 else
5566 rettv->vval.v_number =
5567 (varnumber_T)(regmatch.endp[0] - str);
5568 rettv->vval.v_number += (varnumber_T)(str - expr);
5569 }
5570 }
5571 vim_regfree(regmatch.regprog);
5572 }
5573
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005574theend:
5575 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005576 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 listitem_remove(rettv->vval.v_list,
5578 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005579 vim_free(tofree);
5580 p_cpo = save_cpo;
5581}
5582
5583/*
5584 * "match()" function
5585 */
5586 static void
5587f_match(typval_T *argvars, typval_T *rettv)
5588{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005589 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005590}
5591
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005592/*
5593 * "matchend()" function
5594 */
5595 static void
5596f_matchend(typval_T *argvars, typval_T *rettv)
5597{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005598 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005599}
5600
5601/*
5602 * "matchlist()" function
5603 */
5604 static void
5605f_matchlist(typval_T *argvars, typval_T *rettv)
5606{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005607 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005608}
5609
5610/*
5611 * "matchstr()" function
5612 */
5613 static void
5614f_matchstr(typval_T *argvars, typval_T *rettv)
5615{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005616 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005617}
5618
5619/*
5620 * "matchstrpos()" function
5621 */
5622 static void
5623f_matchstrpos(typval_T *argvars, typval_T *rettv)
5624{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005625 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005626}
5627
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005628 static void
5629max_min(typval_T *argvars, typval_T *rettv, int domax)
5630{
5631 varnumber_T n = 0;
5632 varnumber_T i;
5633 int error = FALSE;
5634
5635 if (argvars[0].v_type == VAR_LIST)
5636 {
5637 list_T *l;
5638 listitem_T *li;
5639
5640 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005641 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005643 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005644 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005645 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5646 n = l->lv_u.nonmat.lv_start;
5647 else
5648 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5649 * l->lv_u.nonmat.lv_stride;
5650 }
5651 else
5652 {
5653 li = l->lv_first;
5654 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005655 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005656 n = tv_get_number_chk(&li->li_tv, &error);
5657 for (;;)
5658 {
5659 li = li->li_next;
5660 if (li == NULL)
5661 break;
5662 i = tv_get_number_chk(&li->li_tv, &error);
5663 if (domax ? i > n : i < n)
5664 n = i;
5665 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005666 }
5667 }
5668 }
5669 }
5670 else if (argvars[0].v_type == VAR_DICT)
5671 {
5672 dict_T *d;
5673 int first = TRUE;
5674 hashitem_T *hi;
5675 int todo;
5676
5677 d = argvars[0].vval.v_dict;
5678 if (d != NULL)
5679 {
5680 todo = (int)d->dv_hashtab.ht_used;
5681 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5682 {
5683 if (!HASHITEM_EMPTY(hi))
5684 {
5685 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005686 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005687 if (first)
5688 {
5689 n = i;
5690 first = FALSE;
5691 }
5692 else if (domax ? i > n : i < n)
5693 n = i;
5694 }
5695 }
5696 }
5697 }
5698 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005699 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005700 rettv->vval.v_number = error ? 0 : n;
5701}
5702
5703/*
5704 * "max()" function
5705 */
5706 static void
5707f_max(typval_T *argvars, typval_T *rettv)
5708{
5709 max_min(argvars, rettv, TRUE);
5710}
5711
5712/*
5713 * "min()" function
5714 */
5715 static void
5716f_min(typval_T *argvars, typval_T *rettv)
5717{
5718 max_min(argvars, rettv, FALSE);
5719}
5720
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005721#if defined(FEAT_MZSCHEME) || defined(PROTO)
5722/*
5723 * "mzeval()" function
5724 */
5725 static void
5726f_mzeval(typval_T *argvars, typval_T *rettv)
5727{
5728 char_u *str;
5729 char_u buf[NUMBUFLEN];
5730
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005731 if (check_restricted() || check_secure())
5732 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005733 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734 do_mzeval(str, rettv);
5735}
5736
5737 void
5738mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5739{
5740 typval_T argvars[3];
5741
5742 argvars[0].v_type = VAR_STRING;
5743 argvars[0].vval.v_string = name;
5744 copy_tv(args, &argvars[1]);
5745 argvars[2].v_type = VAR_UNKNOWN;
5746 f_call(argvars, rettv);
5747 clear_tv(&argvars[1]);
5748}
5749#endif
5750
5751/*
5752 * "nextnonblank()" function
5753 */
5754 static void
5755f_nextnonblank(typval_T *argvars, typval_T *rettv)
5756{
5757 linenr_T lnum;
5758
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005759 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005760 {
5761 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5762 {
5763 lnum = 0;
5764 break;
5765 }
5766 if (*skipwhite(ml_get(lnum)) != NUL)
5767 break;
5768 }
5769 rettv->vval.v_number = lnum;
5770}
5771
5772/*
5773 * "nr2char()" function
5774 */
5775 static void
5776f_nr2char(typval_T *argvars, typval_T *rettv)
5777{
5778 char_u buf[NUMBUFLEN];
5779
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005780 if (has_mbyte)
5781 {
5782 int utf8 = 0;
5783
5784 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005785 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005786 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005787 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005788 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005789 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790 }
5791 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005793 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794 buf[1] = NUL;
5795 }
5796 rettv->v_type = VAR_STRING;
5797 rettv->vval.v_string = vim_strsave(buf);
5798}
5799
5800/*
5801 * "or(expr, expr)" function
5802 */
5803 static void
5804f_or(typval_T *argvars, typval_T *rettv)
5805{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005806 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5807 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808}
5809
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005810#ifdef FEAT_PERL
5811/*
5812 * "perleval()" function
5813 */
5814 static void
5815f_perleval(typval_T *argvars, typval_T *rettv)
5816{
5817 char_u *str;
5818 char_u buf[NUMBUFLEN];
5819
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005820 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005821 do_perleval(str, rettv);
5822}
5823#endif
5824
5825#ifdef FEAT_FLOAT
5826/*
5827 * "pow()" function
5828 */
5829 static void
5830f_pow(typval_T *argvars, typval_T *rettv)
5831{
5832 float_T fx = 0.0, fy = 0.0;
5833
5834 rettv->v_type = VAR_FLOAT;
5835 if (get_float_arg(argvars, &fx) == OK
5836 && get_float_arg(&argvars[1], &fy) == OK)
5837 rettv->vval.v_float = pow(fx, fy);
5838 else
5839 rettv->vval.v_float = 0.0;
5840}
5841#endif
5842
5843/*
5844 * "prevnonblank()" function
5845 */
5846 static void
5847f_prevnonblank(typval_T *argvars, typval_T *rettv)
5848{
5849 linenr_T lnum;
5850
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005851 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005852 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5853 lnum = 0;
5854 else
5855 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5856 --lnum;
5857 rettv->vval.v_number = lnum;
5858}
5859
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005860// This dummy va_list is here because:
5861// - passing a NULL pointer doesn't work when va_list isn't a pointer
5862// - locally in the function results in a "used before set" warning
5863// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005864static va_list ap;
5865
5866/*
5867 * "printf()" function
5868 */
5869 static void
5870f_printf(typval_T *argvars, typval_T *rettv)
5871{
5872 char_u buf[NUMBUFLEN];
5873 int len;
5874 char_u *s;
5875 int saved_did_emsg = did_emsg;
5876 char *fmt;
5877
5878 rettv->v_type = VAR_STRING;
5879 rettv->vval.v_string = NULL;
5880
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005881 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005882 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005883 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005884 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 if (!did_emsg)
5886 {
5887 s = alloc(len + 1);
5888 if (s != NULL)
5889 {
5890 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005891 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5892 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005893 }
5894 }
5895 did_emsg |= saved_did_emsg;
5896}
5897
5898/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005899 * "pum_getpos()" function
5900 */
5901 static void
5902f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5903{
5904 if (rettv_dict_alloc(rettv) != OK)
5905 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005906 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005907}
5908
5909/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005910 * "pumvisible()" function
5911 */
5912 static void
5913f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5914{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005915 if (pum_visible())
5916 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005917}
5918
5919#ifdef FEAT_PYTHON3
5920/*
5921 * "py3eval()" function
5922 */
5923 static void
5924f_py3eval(typval_T *argvars, typval_T *rettv)
5925{
5926 char_u *str;
5927 char_u buf[NUMBUFLEN];
5928
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005929 if (check_restricted() || check_secure())
5930 return;
5931
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005932 if (p_pyx == 0)
5933 p_pyx = 3;
5934
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005935 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005936 do_py3eval(str, rettv);
5937}
5938#endif
5939
5940#ifdef FEAT_PYTHON
5941/*
5942 * "pyeval()" function
5943 */
5944 static void
5945f_pyeval(typval_T *argvars, typval_T *rettv)
5946{
5947 char_u *str;
5948 char_u buf[NUMBUFLEN];
5949
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005950 if (check_restricted() || check_secure())
5951 return;
5952
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005953 if (p_pyx == 0)
5954 p_pyx = 2;
5955
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005956 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005957 do_pyeval(str, rettv);
5958}
5959#endif
5960
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005961#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5962/*
5963 * "pyxeval()" function
5964 */
5965 static void
5966f_pyxeval(typval_T *argvars, typval_T *rettv)
5967{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005968 if (check_restricted() || check_secure())
5969 return;
5970
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005971# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5972 init_pyxversion();
5973 if (p_pyx == 2)
5974 f_pyeval(argvars, rettv);
5975 else
5976 f_py3eval(argvars, rettv);
5977# elif defined(FEAT_PYTHON)
5978 f_pyeval(argvars, rettv);
5979# elif defined(FEAT_PYTHON3)
5980 f_py3eval(argvars, rettv);
5981# endif
5982}
5983#endif
5984
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005985static UINT32_T srand_seed_for_testing = 0;
5986static int srand_seed_for_testing_is_used = FALSE;
5987
5988 static void
5989f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5990{
5991 if (argvars[0].v_type == VAR_UNKNOWN)
5992 srand_seed_for_testing_is_used = FALSE;
5993 else
5994 {
5995 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5996 srand_seed_for_testing_is_used = TRUE;
5997 }
5998}
5999
6000 static void
6001init_srand(UINT32_T *x)
6002{
6003#ifndef MSWIN
6004 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6005#endif
6006
6007 if (srand_seed_for_testing_is_used)
6008 {
6009 *x = srand_seed_for_testing;
6010 return;
6011 }
6012#ifndef MSWIN
6013 if (dev_urandom_state != FAIL)
6014 {
6015 int fd = open("/dev/urandom", O_RDONLY);
6016 struct {
6017 union {
6018 UINT32_T number;
6019 char bytes[sizeof(UINT32_T)];
6020 } contents;
6021 } buf;
6022
6023 // Attempt reading /dev/urandom.
6024 if (fd == -1)
6025 dev_urandom_state = FAIL;
6026 else
6027 {
6028 buf.contents.number = 0;
6029 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6030 != sizeof(UINT32_T))
6031 dev_urandom_state = FAIL;
6032 else
6033 {
6034 dev_urandom_state = OK;
6035 *x = buf.contents.number;
6036 }
6037 close(fd);
6038 }
6039 }
6040 if (dev_urandom_state != OK)
6041 // Reading /dev/urandom doesn't work, fall back to time().
6042#endif
6043 *x = vim_time();
6044}
6045
6046#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6047#define SPLITMIX32(x, z) ( \
6048 z = (x += 0x9e3779b9), \
6049 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6050 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6051 z ^ (z >> 16) \
6052 )
6053#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6054 result = ROTL(y * 5, 7) * 9; \
6055 t = y << 9; \
6056 z ^= x; \
6057 w ^= y; \
6058 y ^= z, x ^= w; \
6059 z ^= t; \
6060 w = ROTL(w, 11);
6061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006062/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006063 * "rand()" function
6064 */
6065 static void
6066f_rand(typval_T *argvars, typval_T *rettv)
6067{
6068 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006069 static UINT32_T gx, gy, gz, gw;
6070 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006071 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006072 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006073
6074 if (argvars[0].v_type == VAR_UNKNOWN)
6075 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006076 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006077 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006078 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006079 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006080 init_srand(&x);
6081
6082 gx = SPLITMIX32(x, z);
6083 gy = SPLITMIX32(x, z);
6084 gz = SPLITMIX32(x, z);
6085 gw = SPLITMIX32(x, z);
6086 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006087 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006088
6089 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006090 }
6091 else if (argvars[0].v_type == VAR_LIST)
6092 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006093 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006094 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006095 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006096
6097 lx = list_find(l, 0L);
6098 ly = list_find(l, 1L);
6099 lz = list_find(l, 2L);
6100 lw = list_find(l, 3L);
6101 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6102 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6103 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6104 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6105 x = (UINT32_T)lx->li_tv.vval.v_number;
6106 y = (UINT32_T)ly->li_tv.vval.v_number;
6107 z = (UINT32_T)lz->li_tv.vval.v_number;
6108 w = (UINT32_T)lw->li_tv.vval.v_number;
6109
6110 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6111
6112 lx->li_tv.vval.v_number = (varnumber_T)x;
6113 ly->li_tv.vval.v_number = (varnumber_T)y;
6114 lz->li_tv.vval.v_number = (varnumber_T)z;
6115 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006116 }
6117 else
6118 goto theend;
6119
6120 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006121 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006122 return;
6123
6124theend:
6125 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006126 rettv->v_type = VAR_NUMBER;
6127 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006128}
6129
6130/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006131 * "srand()" function
6132 */
6133 static void
6134f_srand(typval_T *argvars, typval_T *rettv)
6135{
6136 UINT32_T x = 0, z;
6137
6138 if (rettv_list_alloc(rettv) == FAIL)
6139 return;
6140 if (argvars[0].v_type == VAR_UNKNOWN)
6141 {
6142 init_srand(&x);
6143 }
6144 else
6145 {
6146 int error = FALSE;
6147
6148 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6149 if (error)
6150 return;
6151 }
6152
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 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6156 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6157}
6158
6159#undef ROTL
6160#undef SPLITMIX32
6161#undef SHUFFLE_XOSHIRO128STARSTAR
6162
6163/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006164 * "range()" function
6165 */
6166 static void
6167f_range(typval_T *argvars, typval_T *rettv)
6168{
6169 varnumber_T start;
6170 varnumber_T end;
6171 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006172 int error = FALSE;
6173
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006174 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175 if (argvars[1].v_type == VAR_UNKNOWN)
6176 {
6177 end = start - 1;
6178 start = 0;
6179 }
6180 else
6181 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006182 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006184 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 }
6186
6187 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006188 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006189 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006190 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006191 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006192 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006193 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006195 list_T *list = rettv->vval.v_list;
6196
6197 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006198 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006199 // be called.
6200 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006201 list->lv_u.nonmat.lv_start = start;
6202 list->lv_u.nonmat.lv_end = end;
6203 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006204 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006205 }
6206}
6207
6208/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006209 * Materialize "list".
6210 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006211 */
6212 void
6213range_list_materialize(list_T *list)
6214{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006215 varnumber_T start = list->lv_u.nonmat.lv_start;
6216 varnumber_T end = list->lv_u.nonmat.lv_end;
6217 int stride = list->lv_u.nonmat.lv_stride;
6218 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006219
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006220 list->lv_first = NULL;
6221 list->lv_u.mat.lv_last = NULL;
6222 list->lv_len = 0;
6223 list->lv_u.mat.lv_idx_item = NULL;
6224 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6225 if (list_append_number(list, (varnumber_T)i) == FAIL)
6226 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006227}
6228
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006229 static void
6230return_register(int regname, typval_T *rettv)
6231{
6232 char_u buf[2] = {0, 0};
6233
6234 buf[0] = (char_u)regname;
6235 rettv->v_type = VAR_STRING;
6236 rettv->vval.v_string = vim_strsave(buf);
6237}
6238
6239/*
6240 * "reg_executing()" function
6241 */
6242 static void
6243f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6244{
6245 return_register(reg_executing, rettv);
6246}
6247
6248/*
6249 * "reg_recording()" function
6250 */
6251 static void
6252f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6253{
6254 return_register(reg_recording, rettv);
6255}
6256
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006257/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006258 * "rename({from}, {to})" function
6259 */
6260 static void
6261f_rename(typval_T *argvars, typval_T *rettv)
6262{
6263 char_u buf[NUMBUFLEN];
6264
6265 if (check_restricted() || check_secure())
6266 rettv->vval.v_number = -1;
6267 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006268 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6269 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270}
6271
6272/*
6273 * "repeat()" function
6274 */
6275 static void
6276f_repeat(typval_T *argvars, typval_T *rettv)
6277{
6278 char_u *p;
6279 int n;
6280 int slen;
6281 int len;
6282 char_u *r;
6283 int i;
6284
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006285 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006286 if (argvars[0].v_type == VAR_LIST)
6287 {
6288 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6289 while (n-- > 0)
6290 if (list_extend(rettv->vval.v_list,
6291 argvars[0].vval.v_list, NULL) == FAIL)
6292 break;
6293 }
6294 else
6295 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006296 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 rettv->v_type = VAR_STRING;
6298 rettv->vval.v_string = NULL;
6299
6300 slen = (int)STRLEN(p);
6301 len = slen * n;
6302 if (len <= 0)
6303 return;
6304
6305 r = alloc(len + 1);
6306 if (r != NULL)
6307 {
6308 for (i = 0; i < n; i++)
6309 mch_memmove(r + i * slen, p, (size_t)slen);
6310 r[len] = NUL;
6311 }
6312
6313 rettv->vval.v_string = r;
6314 }
6315}
6316
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006317#define SP_NOMOVE 0x01 // don't move cursor
6318#define SP_REPEAT 0x02 // repeat to find outer pair
6319#define SP_RETCOUNT 0x04 // return matchcount
6320#define SP_SETPCMARK 0x08 // set previous context mark
6321#define SP_START 0x10 // accept match at start position
6322#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6323#define SP_END 0x40 // leave cursor at end of match
6324#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006326/*
6327 * Get flags for a search function.
6328 * Possibly sets "p_ws".
6329 * Returns BACKWARD, FORWARD or zero (for an error).
6330 */
6331 static int
6332get_search_arg(typval_T *varp, int *flagsp)
6333{
6334 int dir = FORWARD;
6335 char_u *flags;
6336 char_u nbuf[NUMBUFLEN];
6337 int mask;
6338
6339 if (varp->v_type != VAR_UNKNOWN)
6340 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006341 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006342 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006343 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006344 while (*flags != NUL)
6345 {
6346 switch (*flags)
6347 {
6348 case 'b': dir = BACKWARD; break;
6349 case 'w': p_ws = TRUE; break;
6350 case 'W': p_ws = FALSE; break;
6351 default: mask = 0;
6352 if (flagsp != NULL)
6353 switch (*flags)
6354 {
6355 case 'c': mask = SP_START; break;
6356 case 'e': mask = SP_END; break;
6357 case 'm': mask = SP_RETCOUNT; break;
6358 case 'n': mask = SP_NOMOVE; break;
6359 case 'p': mask = SP_SUBPAT; break;
6360 case 'r': mask = SP_REPEAT; break;
6361 case 's': mask = SP_SETPCMARK; break;
6362 case 'z': mask = SP_COLUMN; break;
6363 }
6364 if (mask == 0)
6365 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006366 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006367 dir = 0;
6368 }
6369 else
6370 *flagsp |= mask;
6371 }
6372 if (dir == 0)
6373 break;
6374 ++flags;
6375 }
6376 }
6377 return dir;
6378}
6379
6380/*
6381 * Shared by search() and searchpos() functions.
6382 */
6383 static int
6384search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6385{
6386 int flags;
6387 char_u *pat;
6388 pos_T pos;
6389 pos_T save_cursor;
6390 int save_p_ws = p_ws;
6391 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006392 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006395 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396 long time_limit = 0;
6397#endif
6398 int options = SEARCH_KEEP;
6399 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006400 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006401
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006402 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006403 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006404 if (dir == 0)
6405 goto theend;
6406 flags = *flagsp;
6407 if (flags & SP_START)
6408 options |= SEARCH_START;
6409 if (flags & SP_END)
6410 options |= SEARCH_END;
6411 if (flags & SP_COLUMN)
6412 options |= SEARCH_COL;
6413
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006414 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6416 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006417 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006418 if (lnum_stop < 0)
6419 goto theend;
6420#ifdef FEAT_RELTIME
6421 if (argvars[3].v_type != VAR_UNKNOWN)
6422 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006423 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006424 if (time_limit < 0)
6425 goto theend;
6426 }
6427#endif
6428 }
6429
6430#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006431 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006432 profile_setlimit(time_limit, &tm);
6433#endif
6434
6435 /*
6436 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6437 * Check to make sure only those flags are set.
6438 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6439 * flags cannot be set. Check for that condition also.
6440 */
6441 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6442 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6443 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006444 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445 goto theend;
6446 }
6447
6448 pos = save_cursor = curwin->w_cursor;
Bram Moolenaara80faa82020-04-12 19:37:17 +02006449 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006450 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6451#ifdef FEAT_RELTIME
6452 sia.sa_tm = &tm;
6453#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006454 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006455 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006456 if (subpatnum != FAIL)
6457 {
6458 if (flags & SP_SUBPAT)
6459 retval = subpatnum;
6460 else
6461 retval = pos.lnum;
6462 if (flags & SP_SETPCMARK)
6463 setpcmark();
6464 curwin->w_cursor = pos;
6465 if (match_pos != NULL)
6466 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006467 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006468 match_pos->lnum = pos.lnum;
6469 match_pos->col = pos.col + 1;
6470 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006471 // "/$" will put the cursor after the end of the line, may need to
6472 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473 check_cursor();
6474 }
6475
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006476 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006477 if (flags & SP_NOMOVE)
6478 curwin->w_cursor = save_cursor;
6479 else
6480 curwin->w_set_curswant = TRUE;
6481theend:
6482 p_ws = save_p_ws;
6483
6484 return retval;
6485}
6486
6487#ifdef FEAT_FLOAT
6488
6489/*
6490 * round() is not in C90, use ceil() or floor() instead.
6491 */
6492 float_T
6493vim_round(float_T f)
6494{
6495 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6496}
6497
6498/*
6499 * "round({float})" function
6500 */
6501 static void
6502f_round(typval_T *argvars, typval_T *rettv)
6503{
6504 float_T f = 0.0;
6505
6506 rettv->v_type = VAR_FLOAT;
6507 if (get_float_arg(argvars, &f) == OK)
6508 rettv->vval.v_float = vim_round(f);
6509 else
6510 rettv->vval.v_float = 0.0;
6511}
6512#endif
6513
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006514#ifdef FEAT_RUBY
6515/*
6516 * "rubyeval()" function
6517 */
6518 static void
6519f_rubyeval(typval_T *argvars, typval_T *rettv)
6520{
6521 char_u *str;
6522 char_u buf[NUMBUFLEN];
6523
6524 str = tv_get_string_buf(&argvars[0], buf);
6525 do_rubyeval(str, rettv);
6526}
6527#endif
6528
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006529/*
6530 * "screenattr()" function
6531 */
6532 static void
6533f_screenattr(typval_T *argvars, typval_T *rettv)
6534{
6535 int row;
6536 int col;
6537 int c;
6538
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006539 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6540 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541 if (row < 0 || row >= screen_Rows
6542 || col < 0 || col >= screen_Columns)
6543 c = -1;
6544 else
6545 c = ScreenAttrs[LineOffset[row] + col];
6546 rettv->vval.v_number = c;
6547}
6548
6549/*
6550 * "screenchar()" function
6551 */
6552 static void
6553f_screenchar(typval_T *argvars, typval_T *rettv)
6554{
6555 int row;
6556 int col;
6557 int off;
6558 int c;
6559
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006560 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6561 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006562 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006563 c = -1;
6564 else
6565 {
6566 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006567 if (enc_utf8 && ScreenLinesUC[off] != 0)
6568 c = ScreenLinesUC[off];
6569 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 c = ScreenLines[off];
6571 }
6572 rettv->vval.v_number = c;
6573}
6574
6575/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006576 * "screenchars()" function
6577 */
6578 static void
6579f_screenchars(typval_T *argvars, typval_T *rettv)
6580{
6581 int row;
6582 int col;
6583 int off;
6584 int c;
6585 int i;
6586
6587 if (rettv_list_alloc(rettv) == FAIL)
6588 return;
6589 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6590 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6591 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6592 return;
6593
6594 off = LineOffset[row] + col;
6595 if (enc_utf8 && ScreenLinesUC[off] != 0)
6596 c = ScreenLinesUC[off];
6597 else
6598 c = ScreenLines[off];
6599 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6600
6601 if (enc_utf8)
6602
6603 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6604 list_append_number(rettv->vval.v_list,
6605 (varnumber_T)ScreenLinesC[i][off]);
6606}
6607
6608/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006609 * "screencol()" function
6610 *
6611 * First column is 1 to be consistent with virtcol().
6612 */
6613 static void
6614f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6615{
6616 rettv->vval.v_number = screen_screencol() + 1;
6617}
6618
6619/*
6620 * "screenrow()" function
6621 */
6622 static void
6623f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6624{
6625 rettv->vval.v_number = screen_screenrow() + 1;
6626}
6627
6628/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006629 * "screenstring()" function
6630 */
6631 static void
6632f_screenstring(typval_T *argvars, typval_T *rettv)
6633{
6634 int row;
6635 int col;
6636 int off;
6637 int c;
6638 int i;
6639 char_u buf[MB_MAXBYTES + 1];
6640 int buflen = 0;
6641
6642 rettv->vval.v_string = NULL;
6643 rettv->v_type = VAR_STRING;
6644
6645 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6646 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6647 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6648 return;
6649
6650 off = LineOffset[row] + col;
6651 if (enc_utf8 && ScreenLinesUC[off] != 0)
6652 c = ScreenLinesUC[off];
6653 else
6654 c = ScreenLines[off];
6655 buflen += mb_char2bytes(c, buf);
6656
6657 if (enc_utf8)
6658 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6659 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6660
6661 buf[buflen] = NUL;
6662 rettv->vval.v_string = vim_strsave(buf);
6663}
6664
6665/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006666 * "search()" function
6667 */
6668 static void
6669f_search(typval_T *argvars, typval_T *rettv)
6670{
6671 int flags = 0;
6672
6673 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6674}
6675
6676/*
6677 * "searchdecl()" function
6678 */
6679 static void
6680f_searchdecl(typval_T *argvars, typval_T *rettv)
6681{
6682 int locally = 1;
6683 int thisblock = 0;
6684 int error = FALSE;
6685 char_u *name;
6686
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006687 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006689 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690 if (argvars[1].v_type != VAR_UNKNOWN)
6691 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006692 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006694 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006695 }
6696 if (!error && name != NULL)
6697 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6698 locally, thisblock, SEARCH_KEEP) == FAIL;
6699}
6700
6701/*
6702 * Used by searchpair() and searchpairpos()
6703 */
6704 static int
6705searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6706{
6707 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006708 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006709 int save_p_ws = p_ws;
6710 int dir;
6711 int flags = 0;
6712 char_u nbuf1[NUMBUFLEN];
6713 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006714 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006715 long lnum_stop = 0;
6716 long time_limit = 0;
6717
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006718 // Get the three pattern arguments: start, middle, end. Will result in an
6719 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006720 spat = tv_get_string_chk(&argvars[0]);
6721 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6722 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006723 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006724 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006725
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006726 // Handle the optional fourth argument: flags
6727 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006728 if (dir == 0)
6729 goto theend;
6730
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006731 // Don't accept SP_END or SP_SUBPAT.
6732 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006733 if ((flags & (SP_END | SP_SUBPAT)) != 0
6734 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6735 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006736 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 goto theend;
6738 }
6739
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006740 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741 if (flags & SP_REPEAT)
6742 p_ws = FALSE;
6743
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006744 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006745 if (argvars[3].v_type == VAR_UNKNOWN
6746 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006747 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006748 else
6749 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006750 skip = &argvars[4];
6751 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6752 && skip->v_type != VAR_STRING)
6753 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006754 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006755 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006756 goto theend;
6757 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758 if (argvars[5].v_type != VAR_UNKNOWN)
6759 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006760 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006761 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006762 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006763 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006764 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006765 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006766#ifdef FEAT_RELTIME
6767 if (argvars[6].v_type != VAR_UNKNOWN)
6768 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006769 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006771 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006772 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006774 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006775 }
6776#endif
6777 }
6778 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779
6780 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6781 match_pos, lnum_stop, time_limit);
6782
6783theend:
6784 p_ws = save_p_ws;
6785
6786 return retval;
6787}
6788
6789/*
6790 * "searchpair()" function
6791 */
6792 static void
6793f_searchpair(typval_T *argvars, typval_T *rettv)
6794{
6795 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6796}
6797
6798/*
6799 * "searchpairpos()" function
6800 */
6801 static void
6802f_searchpairpos(typval_T *argvars, typval_T *rettv)
6803{
6804 pos_T match_pos;
6805 int lnum = 0;
6806 int col = 0;
6807
6808 if (rettv_list_alloc(rettv) == FAIL)
6809 return;
6810
6811 if (searchpair_cmn(argvars, &match_pos) > 0)
6812 {
6813 lnum = match_pos.lnum;
6814 col = match_pos.col;
6815 }
6816
6817 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6818 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6819}
6820
6821/*
6822 * Search for a start/middle/end thing.
6823 * Used by searchpair(), see its documentation for the details.
6824 * Returns 0 or -1 for no match,
6825 */
6826 long
6827do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006828 char_u *spat, // start pattern
6829 char_u *mpat, // middle pattern
6830 char_u *epat, // end pattern
6831 int dir, // BACKWARD or FORWARD
6832 typval_T *skip, // skip expression
6833 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006835 linenr_T lnum_stop, // stop at this line if not zero
6836 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006837{
6838 char_u *save_cpo;
6839 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6840 long retval = 0;
6841 pos_T pos;
6842 pos_T firstpos;
6843 pos_T foundpos;
6844 pos_T save_cursor;
6845 pos_T save_pos;
6846 int n;
6847 int r;
6848 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006849 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850 int err;
6851 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006852#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006853 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006854#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006855
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006856 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006857 save_cpo = p_cpo;
6858 p_cpo = empty_option;
6859
6860#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006861 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 profile_setlimit(time_limit, &tm);
6863#endif
6864
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006865 // Make two search patterns: start/end (pat2, for in nested pairs) and
6866 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006867 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6868 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869 if (pat2 == NULL || pat3 == NULL)
6870 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006871 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006872 if (*mpat == NUL)
6873 STRCPY(pat3, pat2);
6874 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006875 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006876 spat, epat, mpat);
6877 if (flags & SP_START)
6878 options |= SEARCH_START;
6879
Bram Moolenaar48570482017-10-30 21:48:41 +01006880 if (skip != NULL)
6881 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006882 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006883 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6884 use_skip = skip->vval.v_string != NULL
6885 && *skip->vval.v_string != NUL;
6886 }
6887
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006888 save_cursor = curwin->w_cursor;
6889 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006890 CLEAR_POS(&firstpos);
6891 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892 pat = pat3;
6893 for (;;)
6894 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006895 searchit_arg_T sia;
6896
Bram Moolenaara80faa82020-04-12 19:37:17 +02006897 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006898 sia.sa_stop_lnum = lnum_stop;
6899#ifdef FEAT_RELTIME
6900 sia.sa_tm = &tm;
6901#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006902 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006903 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006904 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006905 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 break;
6907
6908 if (firstpos.lnum == 0)
6909 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006910 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006911 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006912 // Found the same position again. Can happen with a pattern that
6913 // has "\zs" at the end and searching backwards. Advance one
6914 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006915 if (dir == BACKWARD)
6916 decl(&pos);
6917 else
6918 incl(&pos);
6919 }
6920 foundpos = pos;
6921
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006922 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006923 options &= ~SEARCH_START;
6924
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006925 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006926 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006927 {
6928 save_pos = curwin->w_cursor;
6929 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006930 err = FALSE;
6931 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006932 curwin->w_cursor = save_pos;
6933 if (err)
6934 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006935 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 curwin->w_cursor = save_cursor;
6937 retval = -1;
6938 break;
6939 }
6940 if (r)
6941 continue;
6942 }
6943
6944 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6945 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006946 // Found end when searching backwards or start when searching
6947 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006949 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950 }
6951 else
6952 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006953 // Found end when searching forward or start when searching
6954 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006955 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006956 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006957 }
6958
6959 if (nest == 0)
6960 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006961 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006962 if (flags & SP_RETCOUNT)
6963 ++retval;
6964 else
6965 retval = pos.lnum;
6966 if (flags & SP_SETPCMARK)
6967 setpcmark();
6968 curwin->w_cursor = pos;
6969 if (!(flags & SP_REPEAT))
6970 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006971 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006972 }
6973 }
6974
6975 if (match_pos != NULL)
6976 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006977 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006978 match_pos->lnum = curwin->w_cursor.lnum;
6979 match_pos->col = curwin->w_cursor.col + 1;
6980 }
6981
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006982 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006983 if ((flags & SP_NOMOVE) || retval == 0)
6984 curwin->w_cursor = save_cursor;
6985
6986theend:
6987 vim_free(pat2);
6988 vim_free(pat3);
6989 if (p_cpo == empty_option)
6990 p_cpo = save_cpo;
6991 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006992 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006993 free_string_option(save_cpo);
6994
6995 return retval;
6996}
6997
6998/*
6999 * "searchpos()" function
7000 */
7001 static void
7002f_searchpos(typval_T *argvars, typval_T *rettv)
7003{
7004 pos_T match_pos;
7005 int lnum = 0;
7006 int col = 0;
7007 int n;
7008 int flags = 0;
7009
7010 if (rettv_list_alloc(rettv) == FAIL)
7011 return;
7012
7013 n = search_cmn(argvars, &match_pos, &flags);
7014 if (n > 0)
7015 {
7016 lnum = match_pos.lnum;
7017 col = match_pos.col;
7018 }
7019
7020 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7021 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7022 if (flags & SP_SUBPAT)
7023 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7024}
7025
7026 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007027f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7028{
7029 dict_T *d;
7030 dictitem_T *di;
7031 char_u *csearch;
7032
7033 if (argvars[0].v_type != VAR_DICT)
7034 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007035 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 return;
7037 }
7038
7039 if ((d = argvars[0].vval.v_dict) != NULL)
7040 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007041 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007042 if (csearch != NULL)
7043 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007044 if (enc_utf8)
7045 {
7046 int pcc[MAX_MCO];
7047 int c = utfc_ptr2char(csearch, pcc);
7048
7049 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7050 }
7051 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007052 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007053 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007054 }
7055
7056 di = dict_find(d, (char_u *)"forward", -1);
7057 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007058 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007059 ? FORWARD : BACKWARD);
7060
7061 di = dict_find(d, (char_u *)"until", -1);
7062 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007063 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007064 }
7065}
7066
7067/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007068 * "setenv()" function
7069 */
7070 static void
7071f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7072{
7073 char_u namebuf[NUMBUFLEN];
7074 char_u valbuf[NUMBUFLEN];
7075 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7076
7077 if (argvars[1].v_type == VAR_SPECIAL
7078 && argvars[1].vval.v_number == VVAL_NULL)
7079 vim_unsetenv(name);
7080 else
7081 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7082}
7083
7084/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007085 * "setfperm({fname}, {mode})" function
7086 */
7087 static void
7088f_setfperm(typval_T *argvars, typval_T *rettv)
7089{
7090 char_u *fname;
7091 char_u modebuf[NUMBUFLEN];
7092 char_u *mode_str;
7093 int i;
7094 int mask;
7095 int mode = 0;
7096
7097 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007098 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007099 if (fname == NULL)
7100 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007101 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007102 if (mode_str == NULL)
7103 return;
7104 if (STRLEN(mode_str) != 9)
7105 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007106 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007107 return;
7108 }
7109
7110 mask = 1;
7111 for (i = 8; i >= 0; --i)
7112 {
7113 if (mode_str[i] != '-')
7114 mode |= mask;
7115 mask = mask << 1;
7116 }
7117 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7118}
7119
7120/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007121 * "setpos()" function
7122 */
7123 static void
7124f_setpos(typval_T *argvars, typval_T *rettv)
7125{
7126 pos_T pos;
7127 int fnum;
7128 char_u *name;
7129 colnr_T curswant = -1;
7130
7131 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007132 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007133 if (name != NULL)
7134 {
7135 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7136 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007137 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007138 pos.col = 0;
7139 if (name[0] == '.' && name[1] == NUL)
7140 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007141 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007142 curwin->w_cursor = pos;
7143 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007144 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007145 curwin->w_curswant = curswant - 1;
7146 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007147 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007148 check_cursor();
7149 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150 }
7151 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7152 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007153 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007154 if (setmark_pos(name[1], &pos, fnum) == OK)
7155 rettv->vval.v_number = 0;
7156 }
7157 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007158 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007159 }
7160 }
7161}
7162
7163/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 * "setreg()" function
7165 */
7166 static void
7167f_setreg(typval_T *argvars, typval_T *rettv)
7168{
7169 int regname;
7170 char_u *strregname;
7171 char_u *stropt;
7172 char_u *strval;
7173 int append;
7174 char_u yank_type;
7175 long block_len;
7176
7177 block_len = -1;
7178 yank_type = MAUTO;
7179 append = FALSE;
7180
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007181 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007182 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007183
7184 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007185 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007186 regname = *strregname;
7187 if (regname == 0 || regname == '@')
7188 regname = '"';
7189
7190 if (argvars[2].v_type != VAR_UNKNOWN)
7191 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007192 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007193 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007194 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007195 for (; *stropt != NUL; ++stropt)
7196 switch (*stropt)
7197 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007198 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007199 append = TRUE;
7200 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007201 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007202 yank_type = MCHAR;
7203 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007204 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007205 yank_type = MLINE;
7206 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007207 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208 yank_type = MBLOCK;
7209 if (VIM_ISDIGIT(stropt[1]))
7210 {
7211 ++stropt;
7212 block_len = getdigits(&stropt) - 1;
7213 --stropt;
7214 }
7215 break;
7216 }
7217 }
7218
7219 if (argvars[1].v_type == VAR_LIST)
7220 {
7221 char_u **lstval;
7222 char_u **allocval;
7223 char_u buf[NUMBUFLEN];
7224 char_u **curval;
7225 char_u **curallocval;
7226 list_T *ll = argvars[1].vval.v_list;
7227 listitem_T *li;
7228 int len;
7229
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007230 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007231 len = ll == NULL ? 0 : ll->lv_len;
7232
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007233 // First half: use for pointers to result lines; second half: use for
7234 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007235 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 if (lstval == NULL)
7237 return;
7238 curval = lstval;
7239 allocval = lstval + len + 2;
7240 curallocval = allocval;
7241
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007242 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007243 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007244 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007245 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007246 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007247 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007248 if (strval == NULL)
7249 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007250 if (strval == buf)
7251 {
7252 // Need to make a copy, next tv_get_string_buf_chk() will
7253 // overwrite the string.
7254 strval = vim_strsave(buf);
7255 if (strval == NULL)
7256 goto free_lstval;
7257 *curallocval++ = strval;
7258 }
7259 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007260 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007261 }
7262 *curval++ = NULL;
7263
7264 write_reg_contents_lst(regname, lstval, -1,
7265 append, yank_type, block_len);
7266free_lstval:
7267 while (curallocval > allocval)
7268 vim_free(*--curallocval);
7269 vim_free(lstval);
7270 }
7271 else
7272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007273 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274 if (strval == NULL)
7275 return;
7276 write_reg_contents_ex(regname, strval, -1,
7277 append, yank_type, block_len);
7278 }
7279 rettv->vval.v_number = 0;
7280}
7281
7282/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007283 * "settagstack()" function
7284 */
7285 static void
7286f_settagstack(typval_T *argvars, typval_T *rettv)
7287{
7288 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7289 win_T *wp;
7290 dict_T *d;
7291 int action = 'r';
7292
7293 rettv->vval.v_number = -1;
7294
7295 // first argument: window number or id
7296 wp = find_win_by_nr_or_id(&argvars[0]);
7297 if (wp == NULL)
7298 return;
7299
7300 // second argument: dict with items to set in the tag stack
7301 if (argvars[1].v_type != VAR_DICT)
7302 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007303 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007304 return;
7305 }
7306 d = argvars[1].vval.v_dict;
7307 if (d == NULL)
7308 return;
7309
7310 // third argument: action - 'a' for append and 'r' for replace.
7311 // default is to replace the stack.
7312 if (argvars[2].v_type == VAR_UNKNOWN)
7313 action = 'r';
7314 else if (argvars[2].v_type == VAR_STRING)
7315 {
7316 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007317 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007318 if (actstr == NULL)
7319 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007320 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7321 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007322 action = *actstr;
7323 else
7324 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007325 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007326 return;
7327 }
7328 }
7329 else
7330 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007331 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007332 return;
7333 }
7334
7335 if (set_tagstack(wp, d, action) == OK)
7336 rettv->vval.v_number = 0;
7337}
7338
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007339#ifdef FEAT_CRYPT
7340/*
7341 * "sha256({string})" function
7342 */
7343 static void
7344f_sha256(typval_T *argvars, typval_T *rettv)
7345{
7346 char_u *p;
7347
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007348 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007349 rettv->vval.v_string = vim_strsave(
7350 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7351 rettv->v_type = VAR_STRING;
7352}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007353#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007354
7355/*
7356 * "shellescape({string})" function
7357 */
7358 static void
7359f_shellescape(typval_T *argvars, typval_T *rettv)
7360{
Bram Moolenaar20615522017-06-05 18:46:26 +02007361 int do_special = non_zero_arg(&argvars[1]);
7362
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007363 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007364 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365 rettv->v_type = VAR_STRING;
7366}
7367
7368/*
7369 * shiftwidth() function
7370 */
7371 static void
7372f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7373{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007374 rettv->vval.v_number = 0;
7375
7376 if (argvars[0].v_type != VAR_UNKNOWN)
7377 {
7378 long col;
7379
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007380 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007381 if (col < 0)
7382 return; // type error; errmsg already given
7383#ifdef FEAT_VARTABS
7384 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7385 return;
7386#endif
7387 }
7388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389 rettv->vval.v_number = get_sw_value(curbuf);
7390}
7391
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392#ifdef FEAT_FLOAT
7393/*
7394 * "sin()" function
7395 */
7396 static void
7397f_sin(typval_T *argvars, typval_T *rettv)
7398{
7399 float_T f = 0.0;
7400
7401 rettv->v_type = VAR_FLOAT;
7402 if (get_float_arg(argvars, &f) == OK)
7403 rettv->vval.v_float = sin(f);
7404 else
7405 rettv->vval.v_float = 0.0;
7406}
7407
7408/*
7409 * "sinh()" function
7410 */
7411 static void
7412f_sinh(typval_T *argvars, typval_T *rettv)
7413{
7414 float_T f = 0.0;
7415
7416 rettv->v_type = VAR_FLOAT;
7417 if (get_float_arg(argvars, &f) == OK)
7418 rettv->vval.v_float = sinh(f);
7419 else
7420 rettv->vval.v_float = 0.0;
7421}
7422#endif
7423
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424/*
7425 * "soundfold({word})" function
7426 */
7427 static void
7428f_soundfold(typval_T *argvars, typval_T *rettv)
7429{
7430 char_u *s;
7431
7432 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007433 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434#ifdef FEAT_SPELL
7435 rettv->vval.v_string = eval_soundfold(s);
7436#else
7437 rettv->vval.v_string = vim_strsave(s);
7438#endif
7439}
7440
7441/*
7442 * "spellbadword()" function
7443 */
7444 static void
7445f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7446{
7447 char_u *word = (char_u *)"";
7448 hlf_T attr = HLF_COUNT;
7449 int len = 0;
7450
7451 if (rettv_list_alloc(rettv) == FAIL)
7452 return;
7453
7454#ifdef FEAT_SPELL
7455 if (argvars[0].v_type == VAR_UNKNOWN)
7456 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007457 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7459 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007460 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007461 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007462 curwin->w_set_curswant = TRUE;
7463 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464 }
7465 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7466 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007467 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007468 int capcol = -1;
7469
7470 if (str != NULL)
7471 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007472 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007473 while (*str != NUL)
7474 {
7475 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7476 if (attr != HLF_COUNT)
7477 {
7478 word = str;
7479 break;
7480 }
7481 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007482 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007483 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007484 }
7485 }
7486 }
7487#endif
7488
7489 list_append_string(rettv->vval.v_list, word, len);
7490 list_append_string(rettv->vval.v_list, (char_u *)(
7491 attr == HLF_SPB ? "bad" :
7492 attr == HLF_SPR ? "rare" :
7493 attr == HLF_SPL ? "local" :
7494 attr == HLF_SPC ? "caps" :
7495 ""), -1);
7496}
7497
7498/*
7499 * "spellsuggest()" function
7500 */
7501 static void
7502f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7503{
7504#ifdef FEAT_SPELL
7505 char_u *str;
7506 int typeerr = FALSE;
7507 int maxcount;
7508 garray_T ga;
7509 int i;
7510 listitem_T *li;
7511 int need_capital = FALSE;
7512#endif
7513
7514 if (rettv_list_alloc(rettv) == FAIL)
7515 return;
7516
7517#ifdef FEAT_SPELL
7518 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7519 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007520 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 if (argvars[1].v_type != VAR_UNKNOWN)
7522 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007523 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524 if (maxcount <= 0)
7525 return;
7526 if (argvars[2].v_type != VAR_UNKNOWN)
7527 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007528 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 if (typeerr)
7530 return;
7531 }
7532 }
7533 else
7534 maxcount = 25;
7535
7536 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7537
7538 for (i = 0; i < ga.ga_len; ++i)
7539 {
7540 str = ((char_u **)ga.ga_data)[i];
7541
7542 li = listitem_alloc();
7543 if (li == NULL)
7544 vim_free(str);
7545 else
7546 {
7547 li->li_tv.v_type = VAR_STRING;
7548 li->li_tv.v_lock = 0;
7549 li->li_tv.vval.v_string = str;
7550 list_append(rettv->vval.v_list, li);
7551 }
7552 }
7553 ga_clear(&ga);
7554 }
7555#endif
7556}
7557
7558 static void
7559f_split(typval_T *argvars, typval_T *rettv)
7560{
7561 char_u *str;
7562 char_u *end;
7563 char_u *pat = NULL;
7564 regmatch_T regmatch;
7565 char_u patbuf[NUMBUFLEN];
7566 char_u *save_cpo;
7567 int match;
7568 colnr_T col = 0;
7569 int keepempty = FALSE;
7570 int typeerr = FALSE;
7571
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007572 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007573 save_cpo = p_cpo;
7574 p_cpo = (char_u *)"";
7575
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 if (argvars[1].v_type != VAR_UNKNOWN)
7578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007579 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007580 if (pat == NULL)
7581 typeerr = TRUE;
7582 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007583 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007584 }
7585 if (pat == NULL || *pat == NUL)
7586 pat = (char_u *)"[\\x01- ]\\+";
7587
7588 if (rettv_list_alloc(rettv) == FAIL)
7589 return;
7590 if (typeerr)
7591 return;
7592
7593 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7594 if (regmatch.regprog != NULL)
7595 {
7596 regmatch.rm_ic = FALSE;
7597 while (*str != NUL || keepempty)
7598 {
7599 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007600 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007601 else
7602 match = vim_regexec_nl(&regmatch, str, col);
7603 if (match)
7604 end = regmatch.startp[0];
7605 else
7606 end = str + STRLEN(str);
7607 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7608 && *str != NUL && match && end < regmatch.endp[0]))
7609 {
7610 if (list_append_string(rettv->vval.v_list, str,
7611 (int)(end - str)) == FAIL)
7612 break;
7613 }
7614 if (!match)
7615 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007616 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617 if (regmatch.endp[0] > str)
7618 col = 0;
7619 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007620 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007621 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007622 str = regmatch.endp[0];
7623 }
7624
7625 vim_regfree(regmatch.regprog);
7626 }
7627
7628 p_cpo = save_cpo;
7629}
7630
7631#ifdef FEAT_FLOAT
7632/*
7633 * "sqrt()" function
7634 */
7635 static void
7636f_sqrt(typval_T *argvars, typval_T *rettv)
7637{
7638 float_T f = 0.0;
7639
7640 rettv->v_type = VAR_FLOAT;
7641 if (get_float_arg(argvars, &f) == OK)
7642 rettv->vval.v_float = sqrt(f);
7643 else
7644 rettv->vval.v_float = 0.0;
7645}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007646#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007648#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007649/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650 * "str2float()" function
7651 */
7652 static void
7653f_str2float(typval_T *argvars, typval_T *rettv)
7654{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007655 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007656 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657
Bram Moolenaar08243d22017-01-10 16:12:29 +01007658 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659 p = skipwhite(p + 1);
7660 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007661 if (isneg)
7662 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007663 rettv->v_type = VAR_FLOAT;
7664}
7665#endif
7666
7667/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007668 * "str2list()" function
7669 */
7670 static void
7671f_str2list(typval_T *argvars, typval_T *rettv)
7672{
7673 char_u *p;
7674 int utf8 = FALSE;
7675
7676 if (rettv_list_alloc(rettv) == FAIL)
7677 return;
7678
7679 if (argvars[1].v_type != VAR_UNKNOWN)
7680 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7681
7682 p = tv_get_string(&argvars[0]);
7683
7684 if (has_mbyte || utf8)
7685 {
7686 int (*ptr2len)(char_u *);
7687 int (*ptr2char)(char_u *);
7688
7689 if (utf8 || enc_utf8)
7690 {
7691 ptr2len = utf_ptr2len;
7692 ptr2char = utf_ptr2char;
7693 }
7694 else
7695 {
7696 ptr2len = mb_ptr2len;
7697 ptr2char = mb_ptr2char;
7698 }
7699
7700 for ( ; *p != NUL; p += (*ptr2len)(p))
7701 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7702 }
7703 else
7704 for ( ; *p != NUL; ++p)
7705 list_append_number(rettv->vval.v_list, *p);
7706}
7707
7708/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007709 * "str2nr()" function
7710 */
7711 static void
7712f_str2nr(typval_T *argvars, typval_T *rettv)
7713{
7714 int base = 10;
7715 char_u *p;
7716 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007717 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007718 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007719
7720 if (argvars[1].v_type != VAR_UNKNOWN)
7721 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007722 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007723 if (base != 2 && base != 8 && base != 10 && base != 16)
7724 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007725 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726 return;
7727 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007728 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7729 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007730 }
7731
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007732 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007733 isneg = (*p == '-');
7734 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007735 p = skipwhite(p + 1);
7736 switch (base)
7737 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007738 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7739 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7740 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007741 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007742 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7743 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007744 if (isneg)
7745 rettv->vval.v_number = -n;
7746 else
7747 rettv->vval.v_number = n;
7748
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749}
7750
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007751/*
7752 * "strgetchar()" function
7753 */
7754 static void
7755f_strgetchar(typval_T *argvars, typval_T *rettv)
7756{
7757 char_u *str;
7758 int len;
7759 int error = FALSE;
7760 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007761 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007762
7763 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007764 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765 if (str == NULL)
7766 return;
7767 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007768 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007769 if (error)
7770 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007771
Bram Moolenaar13505972019-01-24 15:04:48 +01007772 while (charidx >= 0 && byteidx < len)
7773 {
7774 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007775 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007776 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7777 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007778 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007779 --charidx;
7780 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007781 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007782}
7783
7784/*
7785 * "stridx()" function
7786 */
7787 static void
7788f_stridx(typval_T *argvars, typval_T *rettv)
7789{
7790 char_u buf[NUMBUFLEN];
7791 char_u *needle;
7792 char_u *haystack;
7793 char_u *save_haystack;
7794 char_u *pos;
7795 int start_idx;
7796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007797 needle = tv_get_string_chk(&argvars[1]);
7798 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799 rettv->vval.v_number = -1;
7800 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007801 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007802
7803 if (argvars[2].v_type != VAR_UNKNOWN)
7804 {
7805 int error = FALSE;
7806
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007807 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007808 if (error || start_idx >= (int)STRLEN(haystack))
7809 return;
7810 if (start_idx >= 0)
7811 haystack += start_idx;
7812 }
7813
7814 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7815 if (pos != NULL)
7816 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7817}
7818
7819/*
7820 * "string()" function
7821 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007822 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007823f_string(typval_T *argvars, typval_T *rettv)
7824{
7825 char_u *tofree;
7826 char_u numbuf[NUMBUFLEN];
7827
7828 rettv->v_type = VAR_STRING;
7829 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7830 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007831 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 if (rettv->vval.v_string != NULL && tofree == NULL)
7833 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7834}
7835
7836/*
7837 * "strlen()" function
7838 */
7839 static void
7840f_strlen(typval_T *argvars, typval_T *rettv)
7841{
7842 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007843 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007844}
7845
7846/*
7847 * "strchars()" function
7848 */
7849 static void
7850f_strchars(typval_T *argvars, typval_T *rettv)
7851{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007852 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 varnumber_T len = 0;
7855 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856
7857 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007858 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007860 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 else
7862 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007863 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7864 while (*s != NUL)
7865 {
7866 func_mb_ptr2char_adv(&s);
7867 ++len;
7868 }
7869 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007870 }
7871}
7872
7873/*
7874 * "strdisplaywidth()" function
7875 */
7876 static void
7877f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7878{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007879 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 int col = 0;
7881
7882 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007883 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007884
7885 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7886}
7887
7888/*
7889 * "strwidth()" function
7890 */
7891 static void
7892f_strwidth(typval_T *argvars, typval_T *rettv)
7893{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007894 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007895
Bram Moolenaar13505972019-01-24 15:04:48 +01007896 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897}
7898
7899/*
7900 * "strcharpart()" function
7901 */
7902 static void
7903f_strcharpart(typval_T *argvars, typval_T *rettv)
7904{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007905 char_u *p;
7906 int nchar;
7907 int nbyte = 0;
7908 int charlen;
7909 int len = 0;
7910 int slen;
7911 int error = FALSE;
7912
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007913 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914 slen = (int)STRLEN(p);
7915
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007916 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007917 if (!error)
7918 {
7919 if (nchar > 0)
7920 while (nchar > 0 && nbyte < slen)
7921 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007922 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007923 --nchar;
7924 }
7925 else
7926 nbyte = nchar;
7927 if (argvars[2].v_type != VAR_UNKNOWN)
7928 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007929 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007930 while (charlen > 0 && nbyte + len < slen)
7931 {
7932 int off = nbyte + len;
7933
7934 if (off < 0)
7935 len += 1;
7936 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007937 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007938 --charlen;
7939 }
7940 }
7941 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007942 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007943 }
7944
7945 /*
7946 * Only return the overlap between the specified part and the actual
7947 * string.
7948 */
7949 if (nbyte < 0)
7950 {
7951 len += nbyte;
7952 nbyte = 0;
7953 }
7954 else if (nbyte > slen)
7955 nbyte = slen;
7956 if (len < 0)
7957 len = 0;
7958 else if (nbyte + len > slen)
7959 len = slen - nbyte;
7960
7961 rettv->v_type = VAR_STRING;
7962 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963}
7964
7965/*
7966 * "strpart()" function
7967 */
7968 static void
7969f_strpart(typval_T *argvars, typval_T *rettv)
7970{
7971 char_u *p;
7972 int n;
7973 int len;
7974 int slen;
7975 int error = FALSE;
7976
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007977 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007978 slen = (int)STRLEN(p);
7979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007980 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007981 if (error)
7982 len = 0;
7983 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007984 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007985 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007986 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987
7988 /*
7989 * Only return the overlap between the specified part and the actual
7990 * string.
7991 */
7992 if (n < 0)
7993 {
7994 len += n;
7995 n = 0;
7996 }
7997 else if (n > slen)
7998 n = slen;
7999 if (len < 0)
8000 len = 0;
8001 else if (n + len > slen)
8002 len = slen - n;
8003
8004 rettv->v_type = VAR_STRING;
8005 rettv->vval.v_string = vim_strnsave(p + n, len);
8006}
8007
8008/*
8009 * "strridx()" function
8010 */
8011 static void
8012f_strridx(typval_T *argvars, typval_T *rettv)
8013{
8014 char_u buf[NUMBUFLEN];
8015 char_u *needle;
8016 char_u *haystack;
8017 char_u *rest;
8018 char_u *lastmatch = NULL;
8019 int haystack_len, end_idx;
8020
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008021 needle = tv_get_string_chk(&argvars[1]);
8022 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023
8024 rettv->vval.v_number = -1;
8025 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008026 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008027
8028 haystack_len = (int)STRLEN(haystack);
8029 if (argvars[2].v_type != VAR_UNKNOWN)
8030 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008031 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008032 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008034 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008035 }
8036 else
8037 end_idx = haystack_len;
8038
8039 if (*needle == NUL)
8040 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008041 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 lastmatch = haystack + end_idx;
8043 }
8044 else
8045 {
8046 for (rest = haystack; *rest != '\0'; ++rest)
8047 {
8048 rest = (char_u *)strstr((char *)rest, (char *)needle);
8049 if (rest == NULL || rest > haystack + end_idx)
8050 break;
8051 lastmatch = rest;
8052 }
8053 }
8054
8055 if (lastmatch == NULL)
8056 rettv->vval.v_number = -1;
8057 else
8058 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8059}
8060
8061/*
8062 * "strtrans()" function
8063 */
8064 static void
8065f_strtrans(typval_T *argvars, typval_T *rettv)
8066{
8067 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008068 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069}
8070
8071/*
8072 * "submatch()" function
8073 */
8074 static void
8075f_submatch(typval_T *argvars, typval_T *rettv)
8076{
8077 int error = FALSE;
8078 int no;
8079 int retList = 0;
8080
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008081 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 if (error)
8083 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008084 if (no < 0 || no >= NSUBEXP)
8085 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008086 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008087 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008088 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008089 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008090 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008091 if (error)
8092 return;
8093
8094 if (retList == 0)
8095 {
8096 rettv->v_type = VAR_STRING;
8097 rettv->vval.v_string = reg_submatch(no);
8098 }
8099 else
8100 {
8101 rettv->v_type = VAR_LIST;
8102 rettv->vval.v_list = reg_submatch_list(no);
8103 }
8104}
8105
8106/*
8107 * "substitute()" function
8108 */
8109 static void
8110f_substitute(typval_T *argvars, typval_T *rettv)
8111{
8112 char_u patbuf[NUMBUFLEN];
8113 char_u subbuf[NUMBUFLEN];
8114 char_u flagsbuf[NUMBUFLEN];
8115
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008116 char_u *str = tv_get_string_chk(&argvars[0]);
8117 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008118 char_u *sub = NULL;
8119 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008120 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008121
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008122 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8123 expr = &argvars[2];
8124 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008125 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008126
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008127 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008128 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8129 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 rettv->vval.v_string = NULL;
8131 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008132 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133}
8134
8135/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008136 * "swapinfo(swap_filename)" function
8137 */
8138 static void
8139f_swapinfo(typval_T *argvars, typval_T *rettv)
8140{
8141 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008142 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008143}
8144
8145/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008146 * "swapname(expr)" function
8147 */
8148 static void
8149f_swapname(typval_T *argvars, typval_T *rettv)
8150{
8151 buf_T *buf;
8152
8153 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008154 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008155 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8156 || buf->b_ml.ml_mfp->mf_fname == NULL)
8157 rettv->vval.v_string = NULL;
8158 else
8159 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8160}
8161
8162/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 * "synID(lnum, col, trans)" function
8164 */
8165 static void
8166f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8167{
8168 int id = 0;
8169#ifdef FEAT_SYN_HL
8170 linenr_T lnum;
8171 colnr_T col;
8172 int trans;
8173 int transerr = FALSE;
8174
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008175 lnum = tv_get_lnum(argvars); // -1 on type error
8176 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008177 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008178
8179 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8180 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8181 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8182#endif
8183
8184 rettv->vval.v_number = id;
8185}
8186
8187/*
8188 * "synIDattr(id, what [, mode])" function
8189 */
8190 static void
8191f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8192{
8193 char_u *p = NULL;
8194#ifdef FEAT_SYN_HL
8195 int id;
8196 char_u *what;
8197 char_u *mode;
8198 char_u modebuf[NUMBUFLEN];
8199 int modec;
8200
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008201 id = (int)tv_get_number(&argvars[0]);
8202 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008203 if (argvars[2].v_type != VAR_UNKNOWN)
8204 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008205 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008206 modec = TOLOWER_ASC(mode[0]);
8207 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008208 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209 }
8210 else
8211 {
8212#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8213 if (USE_24BIT)
8214 modec = 'g';
8215 else
8216#endif
8217 if (t_colors > 1)
8218 modec = 'c';
8219 else
8220 modec = 't';
8221 }
8222
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223 switch (TOLOWER_ASC(what[0]))
8224 {
8225 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008226 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008227 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008228 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008229 p = highlight_has_attr(id, HL_BOLD, modec);
8230 break;
8231
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008232 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008233 p = highlight_color(id, what, modec);
8234 break;
8235
8236 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008237 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008239 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008240 p = highlight_has_attr(id, HL_ITALIC, modec);
8241 break;
8242
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008243 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008244 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008245 break;
8246
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008247 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008248 p = highlight_has_attr(id, HL_INVERSE, modec);
8249 break;
8250
8251 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008252 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008253 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008254 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008255 else if (TOLOWER_ASC(what[1]) == 't' &&
8256 TOLOWER_ASC(what[2]) == 'r')
8257 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008258 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 p = highlight_has_attr(id, HL_STANDOUT, modec);
8260 break;
8261
8262 case 'u':
8263 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008264 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8266 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008267 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008268 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8269 break;
8270 }
8271
8272 if (p != NULL)
8273 p = vim_strsave(p);
8274#endif
8275 rettv->v_type = VAR_STRING;
8276 rettv->vval.v_string = p;
8277}
8278
8279/*
8280 * "synIDtrans(id)" function
8281 */
8282 static void
8283f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8284{
8285 int id;
8286
8287#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008288 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008289
8290 if (id > 0)
8291 id = syn_get_final_id(id);
8292 else
8293#endif
8294 id = 0;
8295
8296 rettv->vval.v_number = id;
8297}
8298
8299/*
8300 * "synconcealed(lnum, col)" function
8301 */
8302 static void
8303f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8304{
8305#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8306 linenr_T lnum;
8307 colnr_T col;
8308 int syntax_flags = 0;
8309 int cchar;
8310 int matchid = 0;
8311 char_u str[NUMBUFLEN];
8312#endif
8313
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008314 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008315
8316#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008317 lnum = tv_get_lnum(argvars); // -1 on type error
8318 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319
Bram Moolenaara80faa82020-04-12 19:37:17 +02008320 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008321
8322 if (rettv_list_alloc(rettv) != FAIL)
8323 {
8324 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8325 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8326 && curwin->w_p_cole > 0)
8327 {
8328 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8329 syntax_flags = get_syntax_info(&matchid);
8330
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008331 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008332 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8333 {
8334 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008335 if (cchar == NUL && curwin->w_p_cole == 1)
8336 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008337 if (cchar != NUL)
8338 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339 if (has_mbyte)
8340 (*mb_char2bytes)(cchar, str);
8341 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 str[0] = cchar;
8343 }
8344 }
8345 }
8346
8347 list_append_number(rettv->vval.v_list,
8348 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008349 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008350 list_append_string(rettv->vval.v_list, str, -1);
8351 list_append_number(rettv->vval.v_list, matchid);
8352 }
8353#endif
8354}
8355
8356/*
8357 * "synstack(lnum, col)" function
8358 */
8359 static void
8360f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8361{
8362#ifdef FEAT_SYN_HL
8363 linenr_T lnum;
8364 colnr_T col;
8365 int i;
8366 int id;
8367#endif
8368
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008369 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008370
8371#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008372 lnum = tv_get_lnum(argvars); // -1 on type error
8373 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374
8375 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8376 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8377 && rettv_list_alloc(rettv) != FAIL)
8378 {
8379 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8380 for (i = 0; ; ++i)
8381 {
8382 id = syn_get_stack_item(i);
8383 if (id < 0)
8384 break;
8385 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8386 break;
8387 }
8388 }
8389#endif
8390}
8391
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008392/*
8393 * "tabpagebuflist()" function
8394 */
8395 static void
8396f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8397{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398 tabpage_T *tp;
8399 win_T *wp = NULL;
8400
8401 if (argvars[0].v_type == VAR_UNKNOWN)
8402 wp = firstwin;
8403 else
8404 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008405 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008406 if (tp != NULL)
8407 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8408 }
8409 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8410 {
8411 for (; wp != NULL; wp = wp->w_next)
8412 if (list_append_number(rettv->vval.v_list,
8413 wp->w_buffer->b_fnum) == FAIL)
8414 break;
8415 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008416}
8417
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008418/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008419 * "tagfiles()" function
8420 */
8421 static void
8422f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8423{
8424 char_u *fname;
8425 tagname_T tn;
8426 int first;
8427
8428 if (rettv_list_alloc(rettv) == FAIL)
8429 return;
8430 fname = alloc(MAXPATHL);
8431 if (fname == NULL)
8432 return;
8433
8434 for (first = TRUE; ; first = FALSE)
8435 if (get_tagfname(&tn, first, fname) == FAIL
8436 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8437 break;
8438 tagname_free(&tn);
8439 vim_free(fname);
8440}
8441
8442/*
8443 * "taglist()" function
8444 */
8445 static void
8446f_taglist(typval_T *argvars, typval_T *rettv)
8447{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008448 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008449 char_u *tag_pattern;
8450
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008451 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008452
8453 rettv->vval.v_number = FALSE;
8454 if (*tag_pattern == NUL)
8455 return;
8456
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008457 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008458 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008460 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008461}
8462
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463#ifdef FEAT_FLOAT
8464/*
8465 * "tan()" function
8466 */
8467 static void
8468f_tan(typval_T *argvars, typval_T *rettv)
8469{
8470 float_T f = 0.0;
8471
8472 rettv->v_type = VAR_FLOAT;
8473 if (get_float_arg(argvars, &f) == OK)
8474 rettv->vval.v_float = tan(f);
8475 else
8476 rettv->vval.v_float = 0.0;
8477}
8478
8479/*
8480 * "tanh()" function
8481 */
8482 static void
8483f_tanh(typval_T *argvars, typval_T *rettv)
8484{
8485 float_T f = 0.0;
8486
8487 rettv->v_type = VAR_FLOAT;
8488 if (get_float_arg(argvars, &f) == OK)
8489 rettv->vval.v_float = tanh(f);
8490 else
8491 rettv->vval.v_float = 0.0;
8492}
8493#endif
8494
8495/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008496 * "tolower(string)" function
8497 */
8498 static void
8499f_tolower(typval_T *argvars, typval_T *rettv)
8500{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008501 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008502 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008503}
8504
8505/*
8506 * "toupper(string)" function
8507 */
8508 static void
8509f_toupper(typval_T *argvars, typval_T *rettv)
8510{
8511 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008512 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008513}
8514
8515/*
8516 * "tr(string, fromstr, tostr)" function
8517 */
8518 static void
8519f_tr(typval_T *argvars, typval_T *rettv)
8520{
8521 char_u *in_str;
8522 char_u *fromstr;
8523 char_u *tostr;
8524 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008525 int inlen;
8526 int fromlen;
8527 int tolen;
8528 int idx;
8529 char_u *cpstr;
8530 int cplen;
8531 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008532 char_u buf[NUMBUFLEN];
8533 char_u buf2[NUMBUFLEN];
8534 garray_T ga;
8535
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008536 in_str = tv_get_string(&argvars[0]);
8537 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8538 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008539
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008540 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008541 rettv->v_type = VAR_STRING;
8542 rettv->vval.v_string = NULL;
8543 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008544 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008545 ga_init2(&ga, (int)sizeof(char), 80);
8546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008548 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008549 if (STRLEN(fromstr) != STRLEN(tostr))
8550 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008551error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008552 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008553 ga_clear(&ga);
8554 return;
8555 }
8556
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008557 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 while (*in_str != NUL)
8559 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008560 if (has_mbyte)
8561 {
8562 inlen = (*mb_ptr2len)(in_str);
8563 cpstr = in_str;
8564 cplen = inlen;
8565 idx = 0;
8566 for (p = fromstr; *p != NUL; p += fromlen)
8567 {
8568 fromlen = (*mb_ptr2len)(p);
8569 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8570 {
8571 for (p = tostr; *p != NUL; p += tolen)
8572 {
8573 tolen = (*mb_ptr2len)(p);
8574 if (idx-- == 0)
8575 {
8576 cplen = tolen;
8577 cpstr = p;
8578 break;
8579 }
8580 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008581 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008582 goto error;
8583 break;
8584 }
8585 ++idx;
8586 }
8587
8588 if (first && cpstr == in_str)
8589 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008590 // Check that fromstr and tostr have the same number of
8591 // (multi-byte) characters. Done only once when a character
8592 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008593 first = FALSE;
8594 for (p = tostr; *p != NUL; p += tolen)
8595 {
8596 tolen = (*mb_ptr2len)(p);
8597 --idx;
8598 }
8599 if (idx != 0)
8600 goto error;
8601 }
8602
8603 (void)ga_grow(&ga, cplen);
8604 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8605 ga.ga_len += cplen;
8606
8607 in_str += inlen;
8608 }
8609 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008610 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008611 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008612 p = vim_strchr(fromstr, *in_str);
8613 if (p != NULL)
8614 ga_append(&ga, tostr[p - fromstr]);
8615 else
8616 ga_append(&ga, *in_str);
8617 ++in_str;
8618 }
8619 }
8620
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008621 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008622 (void)ga_grow(&ga, 1);
8623 ga_append(&ga, NUL);
8624
8625 rettv->vval.v_string = ga.ga_data;
8626}
8627
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008628/*
8629 * "trim({expr})" function
8630 */
8631 static void
8632f_trim(typval_T *argvars, typval_T *rettv)
8633{
8634 char_u buf1[NUMBUFLEN];
8635 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008636 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008637 char_u *mask = NULL;
8638 char_u *tail;
8639 char_u *prev;
8640 char_u *p;
8641 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008642 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008643
8644 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008645 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008646 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008647 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008648
8649 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008650 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008651 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008652
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008653 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008654 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008655 int error = 0;
8656
8657 // leading or trailing characters to trim
8658 dir = (int)tv_get_number_chk(&argvars[2], &error);
8659 if (error)
8660 return;
8661 if (dir < 0 || dir > 2)
8662 {
8663 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8664 return;
8665 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008666 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008667 }
8668
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008669 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008670 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008671 // Trim leading characters
8672 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008673 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008674 c1 = PTR2CHAR(head);
8675 if (mask == NULL)
8676 {
8677 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008678 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008679 }
8680 else
8681 {
8682 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8683 if (c1 == PTR2CHAR(p))
8684 break;
8685 if (*p == NUL)
8686 break;
8687 }
8688 MB_PTR_ADV(head);
8689 }
8690 }
8691
8692 tail = head + STRLEN(head);
8693 if (dir == 0 || dir == 2)
8694 {
8695 // Trim trailing characters
8696 for (; tail > head; tail = prev)
8697 {
8698 prev = tail;
8699 MB_PTR_BACK(head, prev);
8700 c1 = PTR2CHAR(prev);
8701 if (mask == NULL)
8702 {
8703 if (c1 > ' ' && c1 != 0xa0)
8704 break;
8705 }
8706 else
8707 {
8708 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8709 if (c1 == PTR2CHAR(p))
8710 break;
8711 if (*p == NUL)
8712 break;
8713 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008714 }
8715 }
8716 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8717}
8718
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008719#ifdef FEAT_FLOAT
8720/*
8721 * "trunc({float})" function
8722 */
8723 static void
8724f_trunc(typval_T *argvars, typval_T *rettv)
8725{
8726 float_T f = 0.0;
8727
8728 rettv->v_type = VAR_FLOAT;
8729 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008730 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008731 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8732 else
8733 rettv->vval.v_float = 0.0;
8734}
8735#endif
8736
8737/*
8738 * "type(expr)" function
8739 */
8740 static void
8741f_type(typval_T *argvars, typval_T *rettv)
8742{
8743 int n = -1;
8744
8745 switch (argvars[0].v_type)
8746 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008747 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8748 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008749 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008750 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8751 case VAR_LIST: n = VAR_TYPE_LIST; break;
8752 case VAR_DICT: n = VAR_TYPE_DICT; break;
8753 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8754 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8755 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008756 case VAR_JOB: n = VAR_TYPE_JOB; break;
8757 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008758 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008759 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02008760 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008761 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008762 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008763 n = -1;
8764 break;
8765 }
8766 rettv->vval.v_number = n;
8767}
8768
8769/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008770 * "virtcol(string)" function
8771 */
8772 static void
8773f_virtcol(typval_T *argvars, typval_T *rettv)
8774{
8775 colnr_T vcol = 0;
8776 pos_T *fp;
8777 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008778 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008779
8780 fp = var2fpos(&argvars[0], FALSE, &fnum);
8781 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8782 && fnum == curbuf->b_fnum)
8783 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008784 // Limit the column to a valid value, getvvcol() doesn't check.
8785 if (fp->col < 0)
8786 fp->col = 0;
8787 else
8788 {
8789 len = (int)STRLEN(ml_get(fp->lnum));
8790 if (fp->col > len)
8791 fp->col = len;
8792 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008793 getvvcol(curwin, fp, NULL, NULL, &vcol);
8794 ++vcol;
8795 }
8796
8797 rettv->vval.v_number = vcol;
8798}
8799
8800/*
8801 * "visualmode()" function
8802 */
8803 static void
8804f_visualmode(typval_T *argvars, typval_T *rettv)
8805{
8806 char_u str[2];
8807
8808 rettv->v_type = VAR_STRING;
8809 str[0] = curbuf->b_visual_mode_eval;
8810 str[1] = NUL;
8811 rettv->vval.v_string = vim_strsave(str);
8812
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008813 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008814 if (non_zero_arg(&argvars[0]))
8815 curbuf->b_visual_mode_eval = NUL;
8816}
8817
8818/*
8819 * "wildmenumode()" function
8820 */
8821 static void
8822f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8823{
8824#ifdef FEAT_WILDMENU
8825 if (wild_menu_showing)
8826 rettv->vval.v_number = 1;
8827#endif
8828}
8829
8830/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008831 * "windowsversion()" function
8832 */
8833 static void
8834f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8835{
8836 rettv->v_type = VAR_STRING;
8837 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8838}
8839
8840/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008841 * "wordcount()" function
8842 */
8843 static void
8844f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8845{
8846 if (rettv_dict_alloc(rettv) == FAIL)
8847 return;
8848 cursor_pos_info(rettv->vval.v_dict);
8849}
8850
8851/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008852 * "xor(expr, expr)" function
8853 */
8854 static void
8855f_xor(typval_T *argvars, typval_T *rettv)
8856{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008857 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8858 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008859}
8860
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008861#endif // FEAT_EVAL