blob: 570aef85f723ee7de91b100493eee44f264a9552 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020023#ifdef FEAT_FLOAT
24static void f_abs(typval_T *argvars, typval_T *rettv);
25static void f_acos(typval_T *argvars, typval_T *rettv);
26#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028#ifdef FEAT_FLOAT
29static void f_asin(typval_T *argvars, typval_T *rettv);
30static void f_atan(typval_T *argvars, typval_T *rettv);
31static void f_atan2(typval_T *argvars, typval_T *rettv);
32#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010033#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020034static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010035static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010036# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010037static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010038# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020040static void f_byte2line(typval_T *argvars, typval_T *rettv);
41static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
42static void f_byteidx(typval_T *argvars, typval_T *rettv);
43static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
44static void f_call(typval_T *argvars, typval_T *rettv);
45#ifdef FEAT_FLOAT
46static void f_ceil(typval_T *argvars, typval_T *rettv);
47#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_changenr(typval_T *argvars, typval_T *rettv);
49static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_confirm(typval_T *argvars, typval_T *rettv);
52static void f_copy(typval_T *argvars, typval_T *rettv);
53#ifdef FEAT_FLOAT
54static void f_cos(typval_T *argvars, typval_T *rettv);
55static void f_cosh(typval_T *argvars, typval_T *rettv);
56#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010058#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020059static void f_debugbreak(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010063static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020065static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_escape(typval_T *argvars, typval_T *rettv);
67static void f_eval(typval_T *argvars, typval_T *rettv);
68static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_exists(typval_T *argvars, typval_T *rettv);
71#ifdef FEAT_FLOAT
72static void f_exp(typval_T *argvars, typval_T *rettv);
73#endif
74static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020075static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077#ifdef FEAT_FLOAT
78static void f_float2nr(typval_T *argvars, typval_T *rettv);
79static void f_floor(typval_T *argvars, typval_T *rettv);
80static void f_fmod(typval_T *argvars, typval_T *rettv);
81#endif
82static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020084static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_function(typval_T *argvars, typval_T *rettv);
86static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
87static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010088static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020090static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010092static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getpid(typval_T *argvars, typval_T *rettv);
94static void f_getcurpos(typval_T *argvars, typval_T *rettv);
95static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarbb861e22020-06-07 18:16:36 +020097static void f_getreginfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020098static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010099static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +0200100static void f_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
102static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_hlID(typval_T *argvars, typval_T *rettv);
104static void f_hlexists(typval_T *argvars, typval_T *rettv);
105static void f_hostname(typval_T *argvars, typval_T *rettv);
106static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_index(typval_T *argvars, typval_T *rettv);
108static void f_input(typval_T *argvars, typval_T *rettv);
109static void f_inputdialog(typval_T *argvars, typval_T *rettv);
110static void f_inputlist(typval_T *argvars, typval_T *rettv);
111static void f_inputrestore(typval_T *argvars, typval_T *rettv);
112static void f_inputsave(typval_T *argvars, typval_T *rettv);
113static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100114static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200115static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200116static void f_islocked(typval_T *argvars, typval_T *rettv);
117#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200118static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_isnan(typval_T *argvars, typval_T *rettv);
120#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
122static void f_len(typval_T *argvars, typval_T *rettv);
123static void f_libcall(typval_T *argvars, typval_T *rettv);
124static void f_libcallnr(typval_T *argvars, typval_T *rettv);
125static void f_line(typval_T *argvars, typval_T *rettv);
126static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127#ifdef FEAT_FLOAT
128static void f_log(typval_T *argvars, typval_T *rettv);
129static void f_log10(typval_T *argvars, typval_T *rettv);
130#endif
131#ifdef FEAT_LUA
132static void f_luaeval(typval_T *argvars, typval_T *rettv);
133#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200134static void f_maparg(typval_T *argvars, typval_T *rettv);
135static void f_mapcheck(typval_T *argvars, typval_T *rettv);
136static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_matchend(typval_T *argvars, typval_T *rettv);
138static void f_matchlist(typval_T *argvars, typval_T *rettv);
139static void f_matchstr(typval_T *argvars, typval_T *rettv);
140static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
141static void f_max(typval_T *argvars, typval_T *rettv);
142static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200143#ifdef FEAT_MZSCHEME
144static void f_mzeval(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
147static void f_nr2char(typval_T *argvars, typval_T *rettv);
148static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200149#ifdef FEAT_PERL
150static void f_perleval(typval_T *argvars, typval_T *rettv);
151#endif
152#ifdef FEAT_FLOAT
153static void f_pow(typval_T *argvars, typval_T *rettv);
154#endif
155static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
156static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200157static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200158static void f_pumvisible(typval_T *argvars, typval_T *rettv);
159#ifdef FEAT_PYTHON3
160static void f_py3eval(typval_T *argvars, typval_T *rettv);
161#endif
162#ifdef FEAT_PYTHON
163static void f_pyeval(typval_T *argvars, typval_T *rettv);
164#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100165#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
166static void f_pyxeval(typval_T *argvars, typval_T *rettv);
167#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100168static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100169static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200171static void f_reg_executing(typval_T *argvars, typval_T *rettv);
172static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_rename(typval_T *argvars, typval_T *rettv);
174static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175#ifdef FEAT_FLOAT
176static void f_round(typval_T *argvars, typval_T *rettv);
177#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100178#ifdef FEAT_RUBY
179static void f_rubyeval(typval_T *argvars, typval_T *rettv);
180#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200181static void f_screenattr(typval_T *argvars, typval_T *rettv);
182static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100183static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200184static void f_screencol(typval_T *argvars, typval_T *rettv);
185static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100186static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_search(typval_T *argvars, typval_T *rettv);
188static void f_searchdecl(typval_T *argvars, typval_T *rettv);
189static void f_searchpair(typval_T *argvars, typval_T *rettv);
190static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
191static void f_searchpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200193static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100197static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198#ifdef FEAT_CRYPT
199static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200200#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_shellescape(typval_T *argvars, typval_T *rettv);
202static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200203#ifdef FEAT_FLOAT
204static void f_sin(typval_T *argvars, typval_T *rettv);
205static void f_sinh(typval_T *argvars, typval_T *rettv);
206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_soundfold(typval_T *argvars, typval_T *rettv);
208static void f_spellbadword(typval_T *argvars, typval_T *rettv);
209static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
210static void f_split(typval_T *argvars, typval_T *rettv);
211#ifdef FEAT_FLOAT
212static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100213#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100214static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100215#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200216static void f_str2float(typval_T *argvars, typval_T *rettv);
217#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200218static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219static void f_str2nr(typval_T *argvars, typval_T *rettv);
220static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_strgetchar(typval_T *argvars, typval_T *rettv);
222static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200223static void f_strlen(typval_T *argvars, typval_T *rettv);
224static void f_strcharpart(typval_T *argvars, typval_T *rettv);
225static void f_strpart(typval_T *argvars, typval_T *rettv);
226static void f_strridx(typval_T *argvars, typval_T *rettv);
227static void f_strtrans(typval_T *argvars, typval_T *rettv);
228static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
229static void f_strwidth(typval_T *argvars, typval_T *rettv);
230static void f_submatch(typval_T *argvars, typval_T *rettv);
231static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200232static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200233static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_synID(typval_T *argvars, typval_T *rettv);
235static void f_synIDattr(typval_T *argvars, typval_T *rettv);
236static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
237static void f_synstack(typval_T *argvars, typval_T *rettv);
238static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200239static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_taglist(typval_T *argvars, typval_T *rettv);
241static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200242#ifdef FEAT_FLOAT
243static void f_tan(typval_T *argvars, typval_T *rettv);
244static void f_tanh(typval_T *argvars, typval_T *rettv);
245#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_tolower(typval_T *argvars, typval_T *rettv);
247static void f_toupper(typval_T *argvars, typval_T *rettv);
248static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100249static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200250#ifdef FEAT_FLOAT
251static void f_trunc(typval_T *argvars, typval_T *rettv);
252#endif
253static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200254static void f_virtcol(typval_T *argvars, typval_T *rettv);
255static void f_visualmode(typval_T *argvars, typval_T *rettv);
256static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100257static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200258static void f_wordcount(typval_T *argvars, typval_T *rettv);
259static void f_xor(typval_T *argvars, typval_T *rettv);
260
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100261
262 static type_T *
263ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
264{
265 return &t_void;
266}
267 static type_T *
268ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
269{
270 return &t_any;
271}
272 static type_T *
273ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
274{
275 return &t_number;
276}
277 static type_T *
278ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
279{
280 return &t_float;
281}
282 static type_T *
283ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
284{
285 return &t_string;
286}
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200287 static type_T *
288ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100289{
290 return &t_list_any;
291}
292 static type_T *
293ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
294{
295 return &t_list_number;
296}
297 static type_T *
298ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
299{
300 return &t_list_string;
301}
302 static type_T *
303ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
304{
305 return &t_list_dict_any;
306}
307 static type_T *
308ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
309{
310 return &t_dict_any;
311}
312 static type_T *
313ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
314{
315 return &t_dict_number;
316}
317 static type_T *
318ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
319{
320 return &t_dict_string;
321}
322 static type_T *
323ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
324{
325 return &t_blob;
326}
327 static type_T *
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200328ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100329{
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200330 return &t_func_any;
331}
332 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100333ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
334{
335 return &t_channel;
336}
337 static type_T *
338ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
339{
340 return &t_job;
341}
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100342
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200343 static type_T *
344ret_first_arg(int argcount, type_T **argtypes)
345{
346 if (argcount > 0)
347 return argtypes[0];
348 return &t_void;
349}
350
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200351/*
352 * Used for getqflist(): returns list if there is no argument, dict if there is
353 * one.
354 */
355 static type_T *
356ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
357{
358 if (argcount > 0)
359 return &t_dict_any;
360 return &t_list_dict_any;
361}
362
363/*
364 * Used for getloclist(): returns list if there is one argument, dict if there
365 * are two.
366 */
367 static type_T *
368ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
369{
370 if (argcount > 1)
371 return &t_dict_any;
372 return &t_list_dict_any;
373}
374
Bram Moolenaar846178a2020-07-05 17:04:13 +0200375 static type_T *
376ret_argv(int argcount, type_T **argtypes UNUSED)
377{
378 // argv() returns list of strings
379 if (argcount == 0)
380 return &t_list_string;
381
382 // argv(0) returns a string, but argv(-1] returns a list
383 return &t_any;
384}
385
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200386 static type_T *
387ret_remove(int argcount UNUSED, type_T **argtypes)
388{
Bram Moolenaar5e654232020-09-16 15:22:00 +0200389 if (argtypes != NULL)
390 {
391 if (argtypes[0]->tt_type == VAR_LIST
392 || argtypes[0]->tt_type == VAR_DICT)
393 return argtypes[0]->tt_member;
394 if (argtypes[0]->tt_type == VAR_BLOB)
395 return &t_number;
396 }
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200397 return &t_any;
398}
399
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200400 static type_T *
401ret_getreg(int argcount, type_T **argtypes UNUSED)
402{
403 // Assume that if the third argument is passed it's non-zero
404 if (argcount == 3)
405 return &t_list_string;
406 return &t_string;
407}
408
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200409 static type_T *
410ret_maparg(int argcount, type_T **argtypes UNUSED)
411{
412 // Assume that if the fourth argument is passed it's non-zero
413 if (argcount == 4)
414 return &t_dict_any;
415 return &t_string;
416}
417
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100418static type_T *ret_f_function(int argcount, type_T **argtypes);
419
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200420/*
421 * Array with names and number of arguments of all internal functions
422 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
423 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200424typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200425{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200426 char *f_name; // function name
427 char f_min_argc; // minimal number of arguments
428 char f_max_argc; // maximal number of arguments
429 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100430 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
431 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200432 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200433 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200434} funcentry_T;
435
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200436// values for f_argtype; zero means it cannot be used as a method
437#define FEARG_1 1 // base is the first argument
438#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200439#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200440#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200441#define FEARG_LAST 9 // base is the last argument
442
Bram Moolenaar15c47602020-03-26 22:16:48 +0100443#ifdef FEAT_FLOAT
444# define FLOAT_FUNC(name) name
445#else
446# define FLOAT_FUNC(name) NULL
447#endif
448#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
449# define MATH_FUNC(name) name
450#else
451# define MATH_FUNC(name) NULL
452#endif
453#ifdef FEAT_TIMERS
454# define TIMER_FUNC(name) name
455#else
456# define TIMER_FUNC(name) NULL
457#endif
458#ifdef FEAT_JOB_CHANNEL
459# define JOB_FUNC(name) name
460#else
461# define JOB_FUNC(name) NULL
462#endif
463#ifdef FEAT_PROP_POPUP
464# define PROP_FUNC(name) name
465#else
466# define PROP_FUNC(name) NULL
467#endif
468#ifdef FEAT_SIGNS
469# define SIGN_FUNC(name) name
470#else
471# define SIGN_FUNC(name) NULL
472#endif
473#ifdef FEAT_SOUND
474# define SOUND_FUNC(name) name
475#else
476# define SOUND_FUNC(name) NULL
477#endif
478#ifdef FEAT_TERMINAL
479# define TERM_FUNC(name) name
480#else
481# define TERM_FUNC(name) NULL
482#endif
483
Bram Moolenaarac92e252019-08-03 21:58:38 +0200484static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200485{
Bram Moolenaar15c47602020-03-26 22:16:48 +0100486 {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)},
487 {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfce82b32020-07-05 16:07:21 +0200488 {"add", 2, 2, FEARG_1, ret_first_arg, f_add},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100489 {"and", 2, 2, FEARG_1, ret_number, f_and},
Bram Moolenaar389df252020-07-09 21:20:47 +0200490 {"append", 2, 2, FEARG_2, ret_number, f_append},
Bram Moolenaar92053ce2020-07-09 22:53:30 +0200491 {"appendbufline", 3, 3, FEARG_3, ret_number, f_appendbufline},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100492 {"argc", 0, 1, 0, ret_number, f_argc},
493 {"argidx", 0, 0, 0, ret_number, f_argidx},
494 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
Bram Moolenaar846178a2020-07-05 17:04:13 +0200495 {"argv", 0, 2, 0, ret_argv, f_argv},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100496 {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
498 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
Bram Moolenaarfb517ba2020-06-03 19:55:35 +0200499 {"assert_equalfile", 2, 3, FEARG_1, ret_number, f_assert_equalfile},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100500 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200501 {"assert_fails", 1, 5, FEARG_1, ret_number, f_assert_fails},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100502 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
503 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
504 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
505 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
506 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
507 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
508 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100509 {"atan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_atan)},
510 {"atan2", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_atan2)},
511 {"balloon_gettext", 0, 0, 0, ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100512#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100513 f_balloon_gettext
514#else
515 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100516#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100517 },
518 {"balloon_show", 1, 1, FEARG_1, ret_void,
519#ifdef FEAT_BEVAL
520 f_balloon_show
521#else
522 NULL
523#endif
524 },
525 {"balloon_split", 1, 1, FEARG_1, ret_list_string,
526#if defined(FEAT_BEVAL_TERM)
527 f_balloon_split
528#else
529 NULL
530#endif
531 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100532 {"browse", 4, 4, 0, ret_string, f_browse},
533 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
534 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
535 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
536 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
537 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
538 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
539 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
540 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
541 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
542 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
543 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
544 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
545 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
546 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
547 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
548 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
549 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100550 {"ceil", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_ceil)},
551 {"ch_canread", 1, 1, FEARG_1, ret_number, JOB_FUNC(f_ch_canread)},
552 {"ch_close", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close)},
553 {"ch_close_in", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close_in)},
554 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalexpr)},
555 {"ch_evalraw", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalraw)},
556 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, JOB_FUNC(f_ch_getbufnr)},
557 {"ch_getjob", 1, 1, FEARG_1, ret_job, JOB_FUNC(f_ch_getjob)},
558 {"ch_info", 1, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_ch_info)},
559 {"ch_log", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_log)},
560 {"ch_logfile", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_logfile)},
561 {"ch_open", 1, 2, FEARG_1, ret_channel, JOB_FUNC(f_ch_open)},
562 {"ch_read", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_read)},
563 {"ch_readblob", 1, 2, FEARG_1, ret_blob, JOB_FUNC(f_ch_readblob)},
564 {"ch_readraw", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_readraw)},
565 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendexpr)},
566 {"ch_sendraw", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendraw)},
567 {"ch_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_setoptions)},
568 {"ch_status", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_status)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100569 {"changenr", 0, 0, 0, ret_number, f_changenr},
570 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
Bram Moolenaar4e4473c2020-08-28 22:24:57 +0200571 {"charclass", 1, 1, FEARG_1, ret_number, f_charclass},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100572 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
573 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
574 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
575 {"col", 1, 1, FEARG_1, ret_number, f_col},
576 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
577 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
578 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
579 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
580 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
Bram Moolenaara66ba012020-07-05 18:41:08 +0200581 {"copy", 1, 1, FEARG_1, ret_first_arg, f_copy},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100582 {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)},
583 {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100584 {"count", 2, 4, FEARG_1, ret_number, f_count},
585 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
586 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100587 {"debugbreak", 1, 1, FEARG_1, ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100588#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100589 f_debugbreak
590#else
591 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200592#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100593 },
Bram Moolenaara66ba012020-07-05 18:41:08 +0200594 {"deepcopy", 1, 2, FEARG_1, ret_first_arg, f_deepcopy},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100595 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
596 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
597 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
598 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
599 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
600 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
601 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
602 {"environ", 0, 0, 0, ret_dict_string, f_environ},
603 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
604 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
605 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
606 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
607 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
608 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
609 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100610 {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100611 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
612 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
Bram Moolenaarb3c019c2020-07-05 20:08:39 +0200613 {"extend", 2, 3, FEARG_1, ret_first_arg, f_extend},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100614 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
615 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
616 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
617 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
Bram Moolenaar0d94ad62020-07-05 20:16:41 +0200618 {"filter", 2, 2, FEARG_1, ret_first_arg, f_filter},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100619 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
620 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar077a1e62020-06-08 20:50:43 +0200621 {"flatten", 1, 2, FEARG_1, ret_list_any, f_flatten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100622 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)},
623 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)},
624 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100625 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
626 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
627 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
628 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
629 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
630 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
631 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
632 {"foreground", 0, 0, 0, ret_void, f_foreground},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200633 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
635 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
636 {"get", 2, 3, FEARG_1, ret_any, f_get},
Bram Moolenaar6434fc52020-07-18 22:24:22 +0200637 {"getbufinfo", 0, 1, FEARG_1, ret_list_dict_any, f_getbufinfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100638 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
639 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
640 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
641 {"getchar", 0, 1, 0, ret_number, f_getchar},
642 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
643 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
644 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
645 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
646 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
647 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
648 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
Bram Moolenaar99ca9c42020-09-22 21:55:41 +0200649 {"getcurpos", 0, 1, FEARG_1, ret_list_number, f_getcurpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100650 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
651 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
652 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
653 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
654 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
655 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
656 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
657 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
658 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
659 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200660 {"getloclist", 1, 2, 0, ret_list_or_dict_1, f_getloclist},
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +0200661 {"getmarklist", 0, 1, FEARG_1, ret_list_dict_any, f_getmarklist},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100662 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
663 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
664 {"getpid", 0, 0, 0, ret_number, f_getpid},
665 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200666 {"getqflist", 0, 1, 0, ret_list_or_dict_0, f_getqflist},
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200667 {"getreg", 0, 3, FEARG_1, ret_getreg, f_getreg},
Bram Moolenaarbb861e22020-06-07 18:16:36 +0200668 {"getreginfo", 0, 1, FEARG_1, ret_dict_any, f_getreginfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100669 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
670 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
671 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
672 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
673 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +0200674 {"gettext", 1, 1, FEARG_1, ret_string, f_gettext},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100675 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
676 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
677 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
678 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
679 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
680 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
681 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
682 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100683 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100684 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
685 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
686 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
687 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
688 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
689 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
690 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
691 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
692 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
693 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
694 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
695 {"hostname", 0, 0, 0, ret_string, f_hostname},
696 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
697 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
698 {"index", 2, 4, FEARG_1, ret_number, f_index},
699 {"input", 1, 3, FEARG_1, ret_string, f_input},
700 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
701 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
702 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
703 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
704 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
Bram Moolenaar252e88a2020-07-05 20:47:18 +0200705 {"insert", 2, 3, FEARG_1, ret_first_arg, f_insert},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100706 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
707 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
708 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100709 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100710 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100711 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100712 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100713 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
714 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
715 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
716 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
717 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
718 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100719 {"join", 1, 2, FEARG_1, ret_string, f_join},
720 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
721 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
722 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
723 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
Bram Moolenaar32f335f2020-08-14 18:56:45 +0200724 {"keys", 1, 1, FEARG_1, ret_list_string, f_keys},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100725 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
726 {"len", 1, 1, FEARG_1, ret_number, f_len},
727 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
728 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
729 {"line", 1, 2, FEARG_1, ret_number, f_line},
730 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
731 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
732 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
733 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
734 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
735 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
736 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100737 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
738 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
739 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200740#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100741 f_luaeval
742#else
743 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100745 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100746 {"map", 2, 2, FEARG_1, ret_any, f_map},
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200747 {"maparg", 1, 4, FEARG_1, ret_maparg, f_maparg},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100748 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200749 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100750 {"match", 2, 4, FEARG_1, ret_any, f_match},
751 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
752 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
753 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
754 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
755 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
Bram Moolenaar4f73b8e2020-09-22 20:33:50 +0200756 {"matchfuzzy", 2, 3, FEARG_1, ret_list_string, f_matchfuzzy},
757 {"matchfuzzypos", 2, 3, FEARG_1, ret_list_any, f_matchfuzzypos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100758 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
759 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
760 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
761 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100762 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100763#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100764 f_menu_info
765#else
766 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100767#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100768 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100769 {"min", 1, 1, FEARG_1, ret_any, f_min},
770 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
771 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100772 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200773#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100774 f_mzeval
775#else
776 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100778 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100779 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
780 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
781 {"or", 2, 2, FEARG_1, ret_number, f_or},
782 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100783 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200784#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100785 f_perleval
786#else
787 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200788#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100789 },
790 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
791 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200792 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100793 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
794 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
795 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
796 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)},
797 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)},
798 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
799 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
800 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
801 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
802 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200803 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100804 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
805 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
806 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
807 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
808 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
809 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
810 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
811 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100812 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
813 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar077cc7a2020-09-04 16:35:35 +0200814 {"prompt_getprompt", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_prompt_getprompt)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100815 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
816 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
817 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
818 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
819 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
820 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
821 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
822 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
823 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
824 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
825 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
826 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
827 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100828 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
829 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100830 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200831#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100832 f_py3eval
833#else
834 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200835#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100836 },
837 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200838#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100839 f_pyeval
840#else
841 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200842#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100843 },
844 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100845#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100846 f_pyxeval
847#else
848 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100849#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100850 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100851 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
852 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +0200853 {"readdir", 1, 3, FEARG_1, ret_list_string, f_readdir},
854 {"readdirex", 1, 3, FEARG_1, ret_list_dict_any, f_readdirex},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100855 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
Bram Moolenaar85629982020-06-01 18:39:20 +0200856 {"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100857 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
858 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
859 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100860 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100861 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
862 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
863 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
864 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
865 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
866 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
Bram Moolenaar9978d472020-07-05 16:01:56 +0200867 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200868 {"remove", 2, 3, FEARG_1, ret_remove, f_remove},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100869 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
Bram Moolenaar9978d472020-07-05 16:01:56 +0200870 {"repeat", 2, 2, FEARG_1, ret_first_arg, f_repeat},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100871 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
Bram Moolenaar67627352020-07-05 21:10:24 +0200872 {"reverse", 1, 1, FEARG_1, ret_first_arg, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100873 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
874 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100875#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100876 f_rubyeval
877#else
878 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100879#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100880 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100881 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
882 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
883 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
884 {"screencol", 0, 0, 0, ret_number, f_screencol},
885 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
886 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
887 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200888 {"search", 1, 5, FEARG_1, ret_number, f_search},
Bram Moolenaare8f5ec02020-06-01 17:28:35 +0200889 {"searchcount", 0, 1, FEARG_1, ret_dict_any, f_searchcount},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100890 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
891 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
892 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200893 {"searchpos", 1, 5, FEARG_1, ret_list_number, f_searchpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100894 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
895 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
896 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
897 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
Bram Moolenaar08aac3c2020-08-28 21:04:24 +0200898 {"setcellwidths", 1, 1, FEARG_1, ret_void, f_setcellwidths},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100899 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
900 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
901 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
902 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
903 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
904 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
905 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
906 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
907 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
908 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
909 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
910 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
911 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
912 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100913 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200914#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100915 f_sha256
916#else
917 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100919 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100920 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
921 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100922 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
923 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
924 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
925 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
926 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
927 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
928 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
929 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
930 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200931 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100932 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
933 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200934 {"sort", 1, 3, FEARG_1, ret_first_arg, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100935 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
936 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
937 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
938 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100939 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
940 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
941 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
942 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100943 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100944 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
945 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100946 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100947 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
948 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
949 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
950 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
951 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100952 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200953#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100954 f_strftime
955#else
956 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200957#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100958 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100959 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
960 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
961 {"string", 1, 1, FEARG_1, ret_string, f_string},
962 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
Bram Moolenaar6c53fca2020-08-23 17:34:46 +0200963 {"strpart", 2, 4, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100964 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100965#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100966 f_strptime
967#else
968 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100969#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100970 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100971 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
972 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
973 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
974 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
975 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
976 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
977 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
978 {"synID", 3, 3, 0, ret_number, f_synID},
979 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
980 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
981 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
982 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
983 {"system", 1, 2, FEARG_1, ret_string, f_system},
984 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
985 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
986 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
987 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
988 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
989 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100990 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
991 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100992 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100993 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
994 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
995 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
996 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
997 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100998#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100999 f_term_getansicolors
1000#else
1001 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001002#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001003 },
1004 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
1005 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
1006 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
1007 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
1008 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
1009 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
1010 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
1011 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
1012 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
1013 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
1014 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
1015 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
1016 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001017#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001018 f_term_setansicolors
1019#else
1020 NULL
1021#endif
1022 },
1023 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
1024 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
1025 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
1026 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
1027 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
1028 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaar0c0eddd2020-06-13 15:47:25 +02001029 {"terminalprops", 0, 0, 0, ret_dict_string, f_terminalprops},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001030 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
1031 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
1032 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
1033 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
1034 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
1035 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
1036 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
1037 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001038 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001039 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +02001040 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001041 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001042 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +02001043 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001044 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
1045 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
1046 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
1047 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001048 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +02001049#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +01001050 f_test_scrollbar
1051#else
1052 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +02001053#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001054 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001055 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
1056 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
1057 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
1058 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
Bram Moolenaar418f1df2020-08-12 21:34:49 +02001059 {"test_void", 0, 0, 0, ret_void, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001060 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
1061 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
1062 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
1063 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
1064 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001065 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
1066 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
1067 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +02001068 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001069 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001070 {"type", 1, 1, FEARG_1, ret_number, f_type},
1071 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
1072 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
1073 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
1074 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
1075 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
1076 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
1077 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
1078 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
1079 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
1080 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
1081 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
1082 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
1083 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
1084 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
1085 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
1086 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
1087 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
1088 {"wincol", 0, 0, 0, ret_number, f_wincol},
1089 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1090 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1091 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1092 {"winline", 0, 0, 0, ret_number, f_winline},
1093 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1094 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1095 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1096 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1097 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1098 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1099 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1100 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001101};
1102
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001103/*
1104 * Function given to ExpandGeneric() to obtain the list of internal
1105 * or user defined function names.
1106 */
1107 char_u *
1108get_function_name(expand_T *xp, int idx)
1109{
1110 static int intidx = -1;
1111 char_u *name;
1112
1113 if (idx == 0)
1114 intidx = -1;
1115 if (intidx < 0)
1116 {
1117 name = get_user_func_name(xp, idx);
1118 if (name != NULL)
1119 return name;
1120 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001121 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001122 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001123 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001124 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001125 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001126 STRCAT(IObuff, ")");
1127 return IObuff;
1128 }
1129
1130 return NULL;
1131}
1132
1133/*
1134 * Function given to ExpandGeneric() to obtain the list of internal or
1135 * user defined variable or function names.
1136 */
1137 char_u *
1138get_expr_name(expand_T *xp, int idx)
1139{
1140 static int intidx = -1;
1141 char_u *name;
1142
1143 if (idx == 0)
1144 intidx = -1;
1145 if (intidx < 0)
1146 {
1147 name = get_function_name(xp, idx);
1148 if (name != NULL)
1149 return name;
1150 }
1151 return get_user_var_name(xp, ++intidx);
1152}
1153
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001154/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001155 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001156 * Return index, or -1 if not found or "implemented" is TRUE and the function
1157 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001158 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001159 static int
1160find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001161{
1162 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001163 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001164 int cmp;
1165 int x;
1166
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001167 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001168
1169 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001170 while (first <= last)
1171 {
1172 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001173 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001174 if (cmp < 0)
1175 last = x - 1;
1176 else if (cmp > 0)
1177 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001178 else if (implemented && global_functions[x].f_func == NULL)
1179 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001180 else
1181 return x;
1182 }
1183 return -1;
1184}
1185
Bram Moolenaar15c47602020-03-26 22:16:48 +01001186/*
1187 * Find internal function "name" in table "global_functions".
1188 * Return index, or -1 if not found or the function is not implemented.
1189 */
1190 int
1191find_internal_func(char_u *name)
1192{
1193 return find_internal_func_opt(name, TRUE);
1194}
1195
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001196 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001197has_internal_func(char_u *name)
1198{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001199 return find_internal_func_opt(name, TRUE) >= 0;
1200}
1201
1202 static int
1203has_internal_func_name(char_u *name)
1204{
1205 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001206}
1207
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001208 char *
1209internal_func_name(int idx)
1210{
1211 return global_functions[idx].f_name;
1212}
1213
1214 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001215internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001216{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001217 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001218}
1219
1220/*
1221 * Check the argument count to use for internal function "idx".
Bram Moolenaar389df252020-07-09 21:20:47 +02001222 * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
1223 * first argument, 2 if method base is second argument, etc. 9 if method base
1224 * is last argument.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001225 */
1226 int
1227check_internal_func(int idx, int argcount)
1228{
1229 int res;
1230 char *name;
1231
1232 if (argcount < global_functions[idx].f_min_argc)
1233 res = FCERR_TOOFEW;
1234 else if (argcount > global_functions[idx].f_max_argc)
1235 res = FCERR_TOOMANY;
1236 else
Bram Moolenaar389df252020-07-09 21:20:47 +02001237 return global_functions[idx].f_argtype;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001238
1239 name = internal_func_name(idx);
1240 if (res == FCERR_TOOMANY)
1241 semsg(_(e_toomanyarg), name);
1242 else
1243 semsg(_(e_toofewarg), name);
Bram Moolenaar389df252020-07-09 21:20:47 +02001244 return -1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001245}
1246
Bram Moolenaarac92e252019-08-03 21:58:38 +02001247 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001248call_internal_func(
1249 char_u *name,
1250 int argcount,
1251 typval_T *argvars,
1252 typval_T *rettv)
1253{
1254 int i;
1255
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001256 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001257 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001258 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001259 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001260 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001261 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001262 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001263 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001264 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001265 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001266}
1267
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001268 void
1269call_internal_func_by_idx(
1270 int idx,
1271 typval_T *argvars,
1272 typval_T *rettv)
1273{
1274 global_functions[idx].f_func(argvars, rettv);
1275}
1276
Bram Moolenaarac92e252019-08-03 21:58:38 +02001277/*
1278 * Invoke a method for base->method().
1279 */
1280 int
1281call_internal_method(
1282 char_u *name,
1283 int argcount,
1284 typval_T *argvars,
1285 typval_T *rettv,
1286 typval_T *basetv)
1287{
1288 int i;
1289 int fi;
1290 typval_T argv[MAX_FUNC_ARGS + 1];
1291
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001292 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001293 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001294 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001295 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001296 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001297 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001298 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001299 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001300 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001301
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001302 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001303 {
1304 // base value goes last
1305 for (i = 0; i < argcount; ++i)
1306 argv[i] = argvars[i];
1307 argv[argcount] = *basetv;
1308 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001309 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001310 {
1311 // base value goes second
1312 argv[0] = argvars[0];
1313 argv[1] = *basetv;
1314 for (i = 1; i < argcount; ++i)
1315 argv[i + 1] = argvars[i];
1316 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001317 else if (global_functions[fi].f_argtype == FEARG_3)
1318 {
1319 // base value goes third
1320 argv[0] = argvars[0];
1321 argv[1] = argvars[1];
1322 argv[2] = *basetv;
1323 for (i = 2; i < argcount; ++i)
1324 argv[i + 1] = argvars[i];
1325 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001326 else if (global_functions[fi].f_argtype == FEARG_4)
1327 {
1328 // base value goes fourth
1329 argv[0] = argvars[0];
1330 argv[1] = argvars[1];
1331 argv[2] = argvars[2];
1332 argv[3] = *basetv;
1333 for (i = 3; i < argcount; ++i)
1334 argv[i + 1] = argvars[i];
1335 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001336 else
1337 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001338 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001339 argv[0] = *basetv;
1340 for (i = 0; i < argcount; ++i)
1341 argv[i + 1] = argvars[i];
1342 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001343 argv[argcount + 1].v_type = VAR_UNKNOWN;
1344
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001345 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001346 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347}
1348
1349/*
1350 * Return TRUE for a non-zero Number and a non-empty String.
1351 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001352 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353non_zero_arg(typval_T *argvars)
1354{
1355 return ((argvars[0].v_type == VAR_NUMBER
1356 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001357 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 && argvars[0].vval.v_number == VVAL_TRUE)
1359 || (argvars[0].v_type == VAR_STRING
1360 && argvars[0].vval.v_string != NULL
1361 && *argvars[0].vval.v_string != NUL));
1362}
1363
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001365/*
1366 * Get the float value of "argvars[0]" into "f".
1367 * Returns FAIL when the argument is not a Number or Float.
1368 */
1369 static int
1370get_float_arg(typval_T *argvars, float_T *f)
1371{
1372 if (argvars[0].v_type == VAR_FLOAT)
1373 {
1374 *f = argvars[0].vval.v_float;
1375 return OK;
1376 }
1377 if (argvars[0].v_type == VAR_NUMBER)
1378 {
1379 *f = (float_T)argvars[0].vval.v_number;
1380 return OK;
1381 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001382 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001383 return FAIL;
1384}
1385
1386/*
1387 * "abs(expr)" function
1388 */
1389 static void
1390f_abs(typval_T *argvars, typval_T *rettv)
1391{
1392 if (argvars[0].v_type == VAR_FLOAT)
1393 {
1394 rettv->v_type = VAR_FLOAT;
1395 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1396 }
1397 else
1398 {
1399 varnumber_T n;
1400 int error = FALSE;
1401
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001402 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001403 if (error)
1404 rettv->vval.v_number = -1;
1405 else if (n > 0)
1406 rettv->vval.v_number = n;
1407 else
1408 rettv->vval.v_number = -n;
1409 }
1410}
1411
1412/*
1413 * "acos()" function
1414 */
1415 static void
1416f_acos(typval_T *argvars, typval_T *rettv)
1417{
1418 float_T f = 0.0;
1419
1420 rettv->v_type = VAR_FLOAT;
1421 if (get_float_arg(argvars, &f) == OK)
1422 rettv->vval.v_float = acos(f);
1423 else
1424 rettv->vval.v_float = 0.0;
1425}
1426#endif
1427
1428/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001429 * "and(expr, expr)" function
1430 */
1431 static void
1432f_and(typval_T *argvars, typval_T *rettv)
1433{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001434 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1435 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001436}
1437
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001438#ifdef FEAT_FLOAT
1439/*
1440 * "asin()" function
1441 */
1442 static void
1443f_asin(typval_T *argvars, typval_T *rettv)
1444{
1445 float_T f = 0.0;
1446
1447 rettv->v_type = VAR_FLOAT;
1448 if (get_float_arg(argvars, &f) == OK)
1449 rettv->vval.v_float = asin(f);
1450 else
1451 rettv->vval.v_float = 0.0;
1452}
1453
1454/*
1455 * "atan()" function
1456 */
1457 static void
1458f_atan(typval_T *argvars, typval_T *rettv)
1459{
1460 float_T f = 0.0;
1461
1462 rettv->v_type = VAR_FLOAT;
1463 if (get_float_arg(argvars, &f) == OK)
1464 rettv->vval.v_float = atan(f);
1465 else
1466 rettv->vval.v_float = 0.0;
1467}
1468
1469/*
1470 * "atan2()" function
1471 */
1472 static void
1473f_atan2(typval_T *argvars, typval_T *rettv)
1474{
1475 float_T fx = 0.0, fy = 0.0;
1476
1477 rettv->v_type = VAR_FLOAT;
1478 if (get_float_arg(argvars, &fx) == OK
1479 && get_float_arg(&argvars[1], &fy) == OK)
1480 rettv->vval.v_float = atan2(fx, fy);
1481 else
1482 rettv->vval.v_float = 0.0;
1483}
1484#endif
1485
1486/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001487 * "balloon_show()" function
1488 */
1489#ifdef FEAT_BEVAL
1490 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001491f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1492{
1493 rettv->v_type = VAR_STRING;
1494 if (balloonEval != NULL)
1495 {
1496 if (balloonEval->msg == NULL)
1497 rettv->vval.v_string = NULL;
1498 else
1499 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1500 }
1501}
1502
1503 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001504f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1505{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001506 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001507 {
1508 if (argvars[0].v_type == VAR_LIST
1509# ifdef FEAT_GUI
1510 && !gui.in_use
1511# endif
1512 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001513 {
1514 list_T *l = argvars[0].vval.v_list;
1515
1516 // empty list removes the balloon
1517 post_balloon(balloonEval, NULL,
1518 l == NULL || l->lv_len == 0 ? NULL : l);
1519 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001520 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001521 {
1522 char_u *mesg = tv_get_string_chk(&argvars[0]);
1523
1524 if (mesg != NULL)
1525 // empty string removes the balloon
1526 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1527 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001528 }
1529}
1530
Bram Moolenaar669a8282017-11-19 20:13:05 +01001531# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001532 static void
1533f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1534{
1535 if (rettv_list_alloc(rettv) == OK)
1536 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001537 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001538
1539 if (msg != NULL)
1540 {
1541 pumitem_T *array;
1542 int size = split_message(msg, &array);
1543 int i;
1544
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001545 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001546 for (i = 1; i < size - 1; ++i)
1547 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001548 while (size > 0)
1549 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001550 vim_free(array);
1551 }
1552 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001553}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001554# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001555#endif
1556
1557/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001558 * Get the buffer from "arg" and give an error and return NULL if it is not
1559 * valid.
1560 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001561 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001562get_buf_arg(typval_T *arg)
1563{
1564 buf_T *buf;
1565
1566 ++emsg_off;
1567 buf = tv_get_buf(arg, FALSE);
1568 --emsg_off;
1569 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001570 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001571 return buf;
1572}
1573
1574/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575 * "byte2line(byte)" function
1576 */
1577 static void
1578f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1579{
1580#ifndef FEAT_BYTEOFF
1581 rettv->vval.v_number = -1;
1582#else
1583 long boff = 0;
1584
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001585 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001586 if (boff < 0)
1587 rettv->vval.v_number = -1;
1588 else
1589 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1590 (linenr_T)0, &boff);
1591#endif
1592}
1593
1594 static void
1595byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1596{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598 char_u *str;
1599 varnumber_T idx;
1600
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001601 str = tv_get_string_chk(&argvars[0]);
1602 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603 rettv->vval.v_number = -1;
1604 if (str == NULL || idx < 0)
1605 return;
1606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607 t = str;
1608 for ( ; idx > 0; idx--)
1609 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001610 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001611 return;
1612 if (enc_utf8 && comp)
1613 t += utf_ptr2len(t);
1614 else
1615 t += (*mb_ptr2len)(t);
1616 }
1617 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001618}
1619
1620/*
1621 * "byteidx()" function
1622 */
1623 static void
1624f_byteidx(typval_T *argvars, typval_T *rettv)
1625{
1626 byteidx(argvars, rettv, FALSE);
1627}
1628
1629/*
1630 * "byteidxcomp()" function
1631 */
1632 static void
1633f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1634{
1635 byteidx(argvars, rettv, TRUE);
1636}
1637
1638/*
1639 * "call(func, arglist [, dict])" function
1640 */
1641 static void
1642f_call(typval_T *argvars, typval_T *rettv)
1643{
1644 char_u *func;
1645 partial_T *partial = NULL;
1646 dict_T *selfdict = NULL;
1647
1648 if (argvars[1].v_type != VAR_LIST)
1649 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001650 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651 return;
1652 }
1653 if (argvars[1].vval.v_list == NULL)
1654 return;
1655
1656 if (argvars[0].v_type == VAR_FUNC)
1657 func = argvars[0].vval.v_string;
1658 else if (argvars[0].v_type == VAR_PARTIAL)
1659 {
1660 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001661 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001662 }
1663 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001664 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001665 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001666 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667
1668 if (argvars[2].v_type != VAR_UNKNOWN)
1669 {
1670 if (argvars[2].v_type != VAR_DICT)
1671 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001672 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673 return;
1674 }
1675 selfdict = argvars[2].vval.v_dict;
1676 }
1677
1678 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1679}
1680
1681#ifdef FEAT_FLOAT
1682/*
1683 * "ceil({float})" function
1684 */
1685 static void
1686f_ceil(typval_T *argvars, typval_T *rettv)
1687{
1688 float_T f = 0.0;
1689
1690 rettv->v_type = VAR_FLOAT;
1691 if (get_float_arg(argvars, &f) == OK)
1692 rettv->vval.v_float = ceil(f);
1693 else
1694 rettv->vval.v_float = 0.0;
1695}
1696#endif
1697
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001698/*
1699 * "changenr()" function
1700 */
1701 static void
1702f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1703{
1704 rettv->vval.v_number = curbuf->b_u_seq_cur;
1705}
1706
1707/*
1708 * "char2nr(string)" function
1709 */
1710 static void
1711f_char2nr(typval_T *argvars, typval_T *rettv)
1712{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001713 if (has_mbyte)
1714 {
1715 int utf8 = 0;
1716
1717 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar24f77502020-09-04 19:50:57 +02001718 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001719
1720 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001721 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001723 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001724 }
1725 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001726 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727}
1728
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001729 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001730get_optional_window(typval_T *argvars, int idx)
1731{
1732 win_T *win = curwin;
1733
1734 if (argvars[idx].v_type != VAR_UNKNOWN)
1735 {
1736 win = find_win_by_nr_or_id(&argvars[idx]);
1737 if (win == NULL)
1738 {
1739 emsg(_(e_invalwindow));
1740 return NULL;
1741 }
1742 }
1743 return win;
1744}
1745
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001746/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001747 * "col(string)" function
1748 */
1749 static void
1750f_col(typval_T *argvars, typval_T *rettv)
1751{
1752 colnr_T col = 0;
1753 pos_T *fp;
1754 int fnum = curbuf->b_fnum;
1755
1756 fp = var2fpos(&argvars[0], FALSE, &fnum);
1757 if (fp != NULL && fnum == curbuf->b_fnum)
1758 {
1759 if (fp->col == MAXCOL)
1760 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001761 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001762 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1763 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1764 else
1765 col = MAXCOL;
1766 }
1767 else
1768 {
1769 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001770 // col(".") when the cursor is on the NUL at the end of the line
1771 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001772 if (virtual_active() && fp == &curwin->w_cursor)
1773 {
1774 char_u *p = ml_get_cursor();
1775
1776 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1777 curwin->w_virtcol - curwin->w_cursor.coladd))
1778 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001779 int l;
1780
1781 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1782 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001783 }
1784 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001785 }
1786 }
1787 rettv->vval.v_number = col;
1788}
1789
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790/*
1791 * "confirm(message, buttons[, default [, type]])" function
1792 */
1793 static void
1794f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1795{
1796#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1797 char_u *message;
1798 char_u *buttons = NULL;
1799 char_u buf[NUMBUFLEN];
1800 char_u buf2[NUMBUFLEN];
1801 int def = 1;
1802 int type = VIM_GENERIC;
1803 char_u *typestr;
1804 int error = FALSE;
1805
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001806 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001807 if (message == NULL)
1808 error = TRUE;
1809 if (argvars[1].v_type != VAR_UNKNOWN)
1810 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001811 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001812 if (buttons == NULL)
1813 error = TRUE;
1814 if (argvars[2].v_type != VAR_UNKNOWN)
1815 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001816 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001817 if (argvars[3].v_type != VAR_UNKNOWN)
1818 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001819 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001820 if (typestr == NULL)
1821 error = TRUE;
1822 else
1823 {
1824 switch (TOUPPER_ASC(*typestr))
1825 {
1826 case 'E': type = VIM_ERROR; break;
1827 case 'Q': type = VIM_QUESTION; break;
1828 case 'I': type = VIM_INFO; break;
1829 case 'W': type = VIM_WARNING; break;
1830 case 'G': type = VIM_GENERIC; break;
1831 }
1832 }
1833 }
1834 }
1835 }
1836
1837 if (buttons == NULL || *buttons == NUL)
1838 buttons = (char_u *)_("&Ok");
1839
1840 if (!error)
1841 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1842 def, NULL, FALSE);
1843#endif
1844}
1845
1846/*
1847 * "copy()" function
1848 */
1849 static void
1850f_copy(typval_T *argvars, typval_T *rettv)
1851{
1852 item_copy(&argvars[0], rettv, FALSE, 0);
1853}
1854
1855#ifdef FEAT_FLOAT
1856/*
1857 * "cos()" function
1858 */
1859 static void
1860f_cos(typval_T *argvars, typval_T *rettv)
1861{
1862 float_T f = 0.0;
1863
1864 rettv->v_type = VAR_FLOAT;
1865 if (get_float_arg(argvars, &f) == OK)
1866 rettv->vval.v_float = cos(f);
1867 else
1868 rettv->vval.v_float = 0.0;
1869}
1870
1871/*
1872 * "cosh()" function
1873 */
1874 static void
1875f_cosh(typval_T *argvars, typval_T *rettv)
1876{
1877 float_T f = 0.0;
1878
1879 rettv->v_type = VAR_FLOAT;
1880 if (get_float_arg(argvars, &f) == OK)
1881 rettv->vval.v_float = cosh(f);
1882 else
1883 rettv->vval.v_float = 0.0;
1884}
1885#endif
1886
1887/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001888 * "cursor(lnum, col)" function, or
1889 * "cursor(list)"
1890 *
1891 * Moves the cursor to the specified line and column.
1892 * Returns 0 when the position could be set, -1 otherwise.
1893 */
1894 static void
1895f_cursor(typval_T *argvars, typval_T *rettv)
1896{
1897 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001898 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001899 int set_curswant = TRUE;
1900
1901 rettv->vval.v_number = -1;
1902 if (argvars[1].v_type == VAR_UNKNOWN)
1903 {
1904 pos_T pos;
1905 colnr_T curswant = -1;
1906
1907 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1908 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001909 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001910 return;
1911 }
1912 line = pos.lnum;
1913 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001914 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001915 if (curswant >= 0)
1916 {
1917 curwin->w_curswant = curswant - 1;
1918 set_curswant = FALSE;
1919 }
1920 }
1921 else
1922 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001923 line = tv_get_lnum(argvars);
1924 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001925 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001926 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001928 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001929 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001930 if (line > 0)
1931 curwin->w_cursor.lnum = line;
1932 if (col > 0)
1933 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001934 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001936 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001937 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001938 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001939 if (has_mbyte)
1940 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001941
1942 curwin->w_set_curswant = set_curswant;
1943 rettv->vval.v_number = 0;
1944}
1945
Bram Moolenaar4f974752019-02-17 17:44:42 +01001946#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001947/*
1948 * "debugbreak()" function
1949 */
1950 static void
1951f_debugbreak(typval_T *argvars, typval_T *rettv)
1952{
1953 int pid;
1954
1955 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001956 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001957 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001958 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001959 else
1960 {
1961 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1962
1963 if (hProcess != NULL)
1964 {
1965 DebugBreakProcess(hProcess);
1966 CloseHandle(hProcess);
1967 rettv->vval.v_number = OK;
1968 }
1969 }
1970}
1971#endif
1972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001973/*
1974 * "deepcopy()" function
1975 */
1976 static void
1977f_deepcopy(typval_T *argvars, typval_T *rettv)
1978{
1979 int noref = 0;
1980 int copyID;
1981
1982 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar44b4a242020-09-05 17:18:28 +02001983 noref = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001984 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001985 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986 else
1987 {
1988 copyID = get_copyID();
1989 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1990 }
1991}
1992
1993/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001994 * "did_filetype()" function
1995 */
1996 static void
1997f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1998{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001999 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002000}
2001
2002/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01002003 * "echoraw({expr})" function
2004 */
2005 static void
2006f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
2007{
2008 char_u *str = tv_get_string_chk(&argvars[0]);
2009
2010 if (str != NULL && *str != NUL)
2011 {
2012 out_str(str);
2013 out_flush();
2014 }
2015}
2016
2017/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002018 * "empty({expr})" function
2019 */
2020 static void
2021f_empty(typval_T *argvars, typval_T *rettv)
2022{
2023 int n = FALSE;
2024
2025 switch (argvars[0].v_type)
2026 {
2027 case VAR_STRING:
2028 case VAR_FUNC:
2029 n = argvars[0].vval.v_string == NULL
2030 || *argvars[0].vval.v_string == NUL;
2031 break;
2032 case VAR_PARTIAL:
2033 n = FALSE;
2034 break;
2035 case VAR_NUMBER:
2036 n = argvars[0].vval.v_number == 0;
2037 break;
2038 case VAR_FLOAT:
2039#ifdef FEAT_FLOAT
2040 n = argvars[0].vval.v_float == 0.0;
2041 break;
2042#endif
2043 case VAR_LIST:
2044 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002045 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002046 break;
2047 case VAR_DICT:
2048 n = argvars[0].vval.v_dict == NULL
2049 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2050 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01002051 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052 case VAR_SPECIAL:
2053 n = argvars[0].vval.v_number != VVAL_TRUE;
2054 break;
2055
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002056 case VAR_BLOB:
2057 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002058 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2059 break;
2060
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 case VAR_JOB:
2062#ifdef FEAT_JOB_CHANNEL
2063 n = argvars[0].vval.v_job == NULL
2064 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2065 break;
2066#endif
2067 case VAR_CHANNEL:
2068#ifdef FEAT_JOB_CHANNEL
2069 n = argvars[0].vval.v_channel == NULL
2070 || !channel_is_open(argvars[0].vval.v_channel);
2071 break;
2072#endif
2073 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002074 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002075 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01002076 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077 n = TRUE;
2078 break;
2079 }
2080
2081 rettv->vval.v_number = n;
2082}
2083
2084/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002085 * "environ()" function
2086 */
2087 static void
2088f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2089{
2090#if !defined(AMIGA)
2091 int i = 0;
2092 char_u *entry, *value;
2093# ifdef MSWIN
2094 extern wchar_t **_wenviron;
2095# else
2096 extern char **environ;
2097# endif
2098
2099 if (rettv_dict_alloc(rettv) != OK)
2100 return;
2101
2102# ifdef MSWIN
2103 if (*_wenviron == NULL)
2104 return;
2105# else
2106 if (*environ == NULL)
2107 return;
2108# endif
2109
2110 for (i = 0; ; ++i)
2111 {
2112# ifdef MSWIN
2113 short_u *p;
2114
2115 if ((p = (short_u *)_wenviron[i]) == NULL)
2116 return;
2117 entry = utf16_to_enc(p, NULL);
2118# else
2119 if ((entry = (char_u *)environ[i]) == NULL)
2120 return;
2121 entry = vim_strsave(entry);
2122# endif
2123 if (entry == NULL) // out of memory
2124 return;
2125 if ((value = vim_strchr(entry, '=')) == NULL)
2126 {
2127 vim_free(entry);
2128 continue;
2129 }
2130 *value++ = NUL;
2131 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2132 vim_free(entry);
2133 }
2134#endif
2135}
2136
2137/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138 * "escape({string}, {chars})" function
2139 */
2140 static void
2141f_escape(typval_T *argvars, typval_T *rettv)
2142{
2143 char_u buf[NUMBUFLEN];
2144
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002145 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2146 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147 rettv->v_type = VAR_STRING;
2148}
2149
2150/*
2151 * "eval()" function
2152 */
2153 static void
2154f_eval(typval_T *argvars, typval_T *rettv)
2155{
2156 char_u *s, *p;
2157
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002158 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002159 if (s != NULL)
2160 s = skipwhite(s);
2161
2162 p = s;
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02002163 if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 {
2165 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002166 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167 need_clr_eos = FALSE;
2168 rettv->v_type = VAR_NUMBER;
2169 rettv->vval.v_number = 0;
2170 }
2171 else if (*s != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02002172 semsg(_(e_trailing_arg), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173}
2174
2175/*
2176 * "eventhandler()" function
2177 */
2178 static void
2179f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2180{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002181 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182}
2183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002184static garray_T redir_execute_ga;
2185
2186/*
2187 * Append "value[value_len]" to the execute() output.
2188 */
2189 void
2190execute_redir_str(char_u *value, int value_len)
2191{
2192 int len;
2193
2194 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002195 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002196 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002197 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002198 if (ga_grow(&redir_execute_ga, len) == OK)
2199 {
2200 mch_memmove((char *)redir_execute_ga.ga_data
2201 + redir_execute_ga.ga_len, value, len);
2202 redir_execute_ga.ga_len += len;
2203 }
2204}
2205
2206/*
2207 * Get next line from a list.
2208 * Called by do_cmdline() to get the next line.
2209 * Returns allocated string, or NULL for end of function.
2210 */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211 static char_u *
2212get_list_line(
2213 int c UNUSED,
2214 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002215 int indent UNUSED,
Bram Moolenaar66250c92020-08-20 15:02:42 +02002216 getline_opt_T options UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002217{
2218 listitem_T **p = (listitem_T **)cookie;
2219 listitem_T *item = *p;
2220 char_u buf[NUMBUFLEN];
2221 char_u *s;
2222
2223 if (item == NULL)
2224 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002225 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002226 *p = item->li_next;
2227 return s == NULL ? NULL : vim_strsave(s);
2228}
2229
2230/*
2231 * "execute()" function
2232 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002233 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002234execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002235{
2236 char_u *cmd = NULL;
2237 list_T *list = NULL;
2238 int save_msg_silent = msg_silent;
2239 int save_emsg_silent = emsg_silent;
2240 int save_emsg_noredir = emsg_noredir;
2241 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002242 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002243 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002244 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002245 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002246
2247 rettv->vval.v_string = NULL;
2248 rettv->v_type = VAR_STRING;
2249
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002250 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002251 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002252 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002253 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002254 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002255 return;
2256 ++list->lv_refcount;
2257 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002258 else if (argvars[arg_off].v_type == VAR_JOB
2259 || argvars[arg_off].v_type == VAR_CHANNEL)
2260 {
2261 emsg(_(e_inval_string));
2262 return;
2263 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002264 else
2265 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002266 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002267 if (cmd == NULL)
2268 return;
2269 }
2270
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002271 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002272 {
2273 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002274 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275
2276 if (s == NULL)
2277 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002278 if (*s == NUL)
2279 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 if (STRNCMP(s, "silent", 6) == 0)
2281 ++msg_silent;
2282 if (STRCMP(s, "silent!") == 0)
2283 {
2284 emsg_silent = TRUE;
2285 emsg_noredir = TRUE;
2286 }
2287 }
2288 else
2289 ++msg_silent;
2290
2291 if (redir_execute)
2292 save_ga = redir_execute_ga;
2293 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2294 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002295 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002296 if (!echo_output)
2297 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002298
2299 if (cmd != NULL)
2300 do_cmdline_cmd(cmd);
2301 else
2302 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002303 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002304
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002305 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002306 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002307 do_cmdline(NULL, get_list_line, (void *)&item,
2308 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2309 --list->lv_refcount;
2310 }
2311
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002312 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002313 if (ga_grow(&redir_execute_ga, 1) == OK)
2314 {
2315 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2316 rettv->vval.v_string = redir_execute_ga.ga_data;
2317 }
2318 else
2319 {
2320 ga_clear(&redir_execute_ga);
2321 rettv->vval.v_string = NULL;
2322 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002323 msg_silent = save_msg_silent;
2324 emsg_silent = save_emsg_silent;
2325 emsg_noredir = save_emsg_noredir;
2326
2327 redir_execute = save_redir_execute;
2328 if (redir_execute)
2329 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002330 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002331
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002332 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002333 if (echo_output)
2334 // When not working silently: put it in column zero. A following
2335 // "echon" will overwrite the message, unavoidably.
2336 msg_col = 0;
2337 else
2338 // When working silently: Put it back where it was, since nothing
2339 // should have been written.
2340 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002341}
2342
2343/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002344 * "execute()" function
2345 */
2346 static void
2347f_execute(typval_T *argvars, typval_T *rettv)
2348{
2349 execute_common(argvars, rettv, 0);
2350}
2351
2352/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353 * "exists()" function
2354 */
2355 static void
2356f_exists(typval_T *argvars, typval_T *rettv)
2357{
2358 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002361 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002362 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002363 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002364 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365 if (mch_getenv(p + 1) != NULL)
2366 n = TRUE;
2367 else
2368 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002369 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370 p = expand_env_save(p);
2371 if (p != NULL && *p != '$')
2372 n = TRUE;
2373 vim_free(p);
2374 }
2375 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002376 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002377 {
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02002378 n = (eval_option(&p, NULL, TRUE) == OK);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002379 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002380 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002381 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002382 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002383 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002384 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002385 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002386 else if (*p == '?') // internal function only
2387 {
2388 n = has_internal_func_name(p + 1);
2389 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002390 else if (*p == ':')
2391 {
2392 n = cmd_exists(p + 1);
2393 }
2394 else if (*p == '#')
2395 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002396 if (p[1] == '#')
2397 n = autocmd_supported(p + 2);
2398 else
2399 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002400 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002401 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002402 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002403 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002404 }
2405
2406 rettv->vval.v_number = n;
2407}
2408
2409#ifdef FEAT_FLOAT
2410/*
2411 * "exp()" function
2412 */
2413 static void
2414f_exp(typval_T *argvars, typval_T *rettv)
2415{
2416 float_T f = 0.0;
2417
2418 rettv->v_type = VAR_FLOAT;
2419 if (get_float_arg(argvars, &f) == OK)
2420 rettv->vval.v_float = exp(f);
2421 else
2422 rettv->vval.v_float = 0.0;
2423}
2424#endif
2425
2426/*
2427 * "expand()" function
2428 */
2429 static void
2430f_expand(typval_T *argvars, typval_T *rettv)
2431{
2432 char_u *s;
2433 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002434 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002435 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2436 expand_T xpc;
2437 int error = FALSE;
2438 char_u *result;
2439
2440 rettv->v_type = VAR_STRING;
2441 if (argvars[1].v_type != VAR_UNKNOWN
2442 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02002443 && tv_get_bool_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002444 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002445 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002447 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 if (*s == '%' || *s == '#' || *s == '<')
2449 {
2450 ++emsg_off;
2451 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2452 --emsg_off;
2453 if (rettv->v_type == VAR_LIST)
2454 {
2455 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2456 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002457 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458 }
2459 else
2460 rettv->vval.v_string = result;
2461 }
2462 else
2463 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002464 // When the optional second argument is non-zero, don't remove matches
2465 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002466 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02002467 && tv_get_bool_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002468 options |= WILD_KEEP_ALL;
2469 if (!error)
2470 {
2471 ExpandInit(&xpc);
2472 xpc.xp_context = EXPAND_FILES;
2473 if (p_wic)
2474 options += WILD_ICASE;
2475 if (rettv->v_type == VAR_STRING)
2476 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2477 options, WILD_ALL);
2478 else if (rettv_list_alloc(rettv) != FAIL)
2479 {
2480 int i;
2481
2482 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2483 for (i = 0; i < xpc.xp_numfiles; i++)
2484 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2485 ExpandCleanup(&xpc);
2486 }
2487 }
2488 else
2489 rettv->vval.v_string = NULL;
2490 }
2491}
2492
2493/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002494 * "expandcmd()" function
2495 * Expand all the special characters in a command string.
2496 */
2497 static void
2498f_expandcmd(typval_T *argvars, typval_T *rettv)
2499{
2500 exarg_T eap;
2501 char_u *cmdstr;
2502 char *errormsg = NULL;
2503
2504 rettv->v_type = VAR_STRING;
2505 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2506
2507 memset(&eap, 0, sizeof(eap));
2508 eap.cmd = cmdstr;
2509 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002510 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002511 eap.usefilter = FALSE;
2512 eap.nextcmd = NULL;
2513 eap.cmdidx = CMD_USER;
2514
2515 expand_filename(&eap, &cmdstr, &errormsg);
2516 if (errormsg != NULL && *errormsg != NUL)
2517 emsg(errormsg);
2518
2519 rettv->vval.v_string = cmdstr;
2520}
2521
2522/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002523 * "feedkeys()" function
2524 */
2525 static void
2526f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2527{
2528 int remap = TRUE;
2529 int insert = FALSE;
2530 char_u *keys, *flags;
2531 char_u nbuf[NUMBUFLEN];
2532 int typed = FALSE;
2533 int execute = FALSE;
2534 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002535 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002536 char_u *keys_esc;
2537
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002538 // This is not allowed in the sandbox. If the commands would still be
2539 // executed in the sandbox it would be OK, but it probably happens later,
2540 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 if (check_secure())
2542 return;
2543
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002544 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002545
2546 if (argvars[1].v_type != VAR_UNKNOWN)
2547 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002548 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002549 for ( ; *flags != NUL; ++flags)
2550 {
2551 switch (*flags)
2552 {
2553 case 'n': remap = FALSE; break;
2554 case 'm': remap = TRUE; break;
2555 case 't': typed = TRUE; break;
2556 case 'i': insert = TRUE; break;
2557 case 'x': execute = TRUE; break;
2558 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002559 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002560 }
2561 }
2562 }
2563
2564 if (*keys != NUL || execute)
2565 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002566 // Need to escape K_SPECIAL and CSI before putting the string in the
2567 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002568 keys_esc = vim_strsave_escape_csi(keys);
2569 if (keys_esc != NULL)
2570 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002571 if (lowlevel)
2572 {
2573#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002574 int idx;
2575 int len = (int)STRLEN(keys);
2576
2577 for (idx = 0; idx < len; ++idx)
2578 {
2579 // if a CTRL-C was typed, set got_int, similar to what
2580 // happens in fill_input_buf()
2581 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2582 got_int = TRUE;
2583 add_to_input_buf(keys + idx, 1);
2584 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002585#else
2586 emsg(_("E980: lowlevel input not supported"));
2587#endif
2588 }
2589 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002590 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002591 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002593 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002594#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002595 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002596#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002597 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002598 typebuf_was_filled = TRUE;
2599 }
2600 vim_free(keys_esc);
2601
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 if (execute)
2603 {
2604 int save_msg_scroll = msg_scroll;
2605
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002606 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002607 msg_scroll = FALSE;
2608
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002609 if (!dangerous)
2610 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002611 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002612 if (!dangerous)
2613 --ex_normal_busy;
2614
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002615 msg_scroll |= save_msg_scroll;
2616 }
2617 }
2618 }
2619}
2620
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621#ifdef FEAT_FLOAT
2622/*
2623 * "float2nr({float})" function
2624 */
2625 static void
2626f_float2nr(typval_T *argvars, typval_T *rettv)
2627{
2628 float_T f = 0.0;
2629
2630 if (get_float_arg(argvars, &f) == OK)
2631 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002632 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002633 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002634 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002635 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002636 else
2637 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002638 }
2639}
2640
2641/*
2642 * "floor({float})" function
2643 */
2644 static void
2645f_floor(typval_T *argvars, typval_T *rettv)
2646{
2647 float_T f = 0.0;
2648
2649 rettv->v_type = VAR_FLOAT;
2650 if (get_float_arg(argvars, &f) == OK)
2651 rettv->vval.v_float = floor(f);
2652 else
2653 rettv->vval.v_float = 0.0;
2654}
2655
2656/*
2657 * "fmod()" function
2658 */
2659 static void
2660f_fmod(typval_T *argvars, typval_T *rettv)
2661{
2662 float_T fx = 0.0, fy = 0.0;
2663
2664 rettv->v_type = VAR_FLOAT;
2665 if (get_float_arg(argvars, &fx) == OK
2666 && get_float_arg(&argvars[1], &fy) == OK)
2667 rettv->vval.v_float = fmod(fx, fy);
2668 else
2669 rettv->vval.v_float = 0.0;
2670}
2671#endif
2672
2673/*
2674 * "fnameescape({string})" function
2675 */
2676 static void
2677f_fnameescape(typval_T *argvars, typval_T *rettv)
2678{
2679 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002680 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002681 rettv->v_type = VAR_STRING;
2682}
2683
2684/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002685 * "foreground()" function
2686 */
2687 static void
2688f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2689{
2690#ifdef FEAT_GUI
2691 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002692 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002694 return;
2695 }
2696#endif
2697#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002698 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699#endif
2700}
2701
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002702 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002703common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704{
2705 char_u *s;
2706 char_u *name;
2707 int use_string = FALSE;
2708 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002709 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002710 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711
2712 if (argvars[0].v_type == VAR_FUNC)
2713 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002714 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002715 s = argvars[0].vval.v_string;
2716 }
2717 else if (argvars[0].v_type == VAR_PARTIAL
2718 && argvars[0].vval.v_partial != NULL)
2719 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002720 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002721 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002722 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002723 }
2724 else
2725 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002726 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002727 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 use_string = TRUE;
2729 }
2730
Bram Moolenaar843b8842016-08-21 14:36:15 +02002731 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002732 {
2733 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002734 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002735 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2736 if (*name != NUL)
2737 s = NULL;
2738 }
2739
Bram Moolenaar843b8842016-08-21 14:36:15 +02002740 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2741 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002742 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002743 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002744 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002745 ? find_func(trans_name, is_global, NULL) == NULL
2746 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002747 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002748 else
2749 {
2750 int dict_idx = 0;
2751 int arg_idx = 0;
2752 list_T *list = NULL;
2753
2754 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2755 {
2756 char sid_buf[25];
2757 int off = *s == 's' ? 2 : 5;
2758
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002759 // Expand s: and <SID> into <SNR>nr_, so that the function can
2760 // also be called from another script. Using trans_function_name()
2761 // would also work, but some plugins depend on the name being
2762 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002763 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002764 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002765 if (name != NULL)
2766 {
2767 STRCPY(name, sid_buf);
2768 STRCAT(name, s + off);
2769 }
2770 }
2771 else
2772 name = vim_strsave(s);
2773
2774 if (argvars[1].v_type != VAR_UNKNOWN)
2775 {
2776 if (argvars[2].v_type != VAR_UNKNOWN)
2777 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002778 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002779 arg_idx = 1;
2780 dict_idx = 2;
2781 }
2782 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002783 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002784 dict_idx = 1;
2785 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002786 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 arg_idx = 1;
2788 if (dict_idx > 0)
2789 {
2790 if (argvars[dict_idx].v_type != VAR_DICT)
2791 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002792 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002793 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002794 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002795 }
2796 if (argvars[dict_idx].vval.v_dict == NULL)
2797 dict_idx = 0;
2798 }
2799 if (arg_idx > 0)
2800 {
2801 if (argvars[arg_idx].v_type != VAR_LIST)
2802 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002803 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002804 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002805 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002806 }
2807 list = argvars[arg_idx].vval.v_list;
2808 if (list == NULL || list->lv_len == 0)
2809 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002810 else if (list->lv_len > MAX_FUNC_ARGS)
2811 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002812 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002813 vim_free(name);
2814 goto theend;
2815 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002816 }
2817 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002818 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002819 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002820 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002821
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002822 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002823 if (pt == NULL)
2824 vim_free(name);
2825 else
2826 {
2827 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2828 {
2829 listitem_T *li;
2830 int i = 0;
2831 int arg_len = 0;
2832 int lv_len = 0;
2833
2834 if (arg_pt != NULL)
2835 arg_len = arg_pt->pt_argc;
2836 if (list != NULL)
2837 lv_len = list->lv_len;
2838 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002839 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 if (pt->pt_argv == NULL)
2841 {
2842 vim_free(pt);
2843 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002844 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002845 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002846 for (i = 0; i < arg_len; i++)
2847 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2848 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002849 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002850 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002851 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002852 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002853 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002854 }
2855
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002856 // For "function(dict.func, [], dict)" and "func" is a partial
2857 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002858 if (dict_idx > 0)
2859 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002860 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002861 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2862 ++pt->pt_dict->dv_refcount;
2863 }
2864 else if (arg_pt != NULL)
2865 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002866 // If the dict was bound automatically the result is also
2867 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002868 pt->pt_dict = arg_pt->pt_dict;
2869 pt->pt_auto = arg_pt->pt_auto;
2870 if (pt->pt_dict != NULL)
2871 ++pt->pt_dict->dv_refcount;
2872 }
2873
2874 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002875 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2876 {
2877 pt->pt_func = arg_pt->pt_func;
2878 func_ptr_ref(pt->pt_func);
2879 vim_free(name);
2880 }
2881 else if (is_funcref)
2882 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002883 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002884 func_ptr_ref(pt->pt_func);
2885 vim_free(name);
2886 }
2887 else
2888 {
2889 pt->pt_name = name;
2890 func_ref(name);
2891 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002892 }
2893 rettv->v_type = VAR_PARTIAL;
2894 rettv->vval.v_partial = pt;
2895 }
2896 else
2897 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002898 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002899 rettv->v_type = VAR_FUNC;
2900 rettv->vval.v_string = name;
2901 func_ref(name);
2902 }
2903 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002904theend:
2905 vim_free(trans_name);
2906}
2907
2908/*
2909 * "funcref()" function
2910 */
2911 static void
2912f_funcref(typval_T *argvars, typval_T *rettv)
2913{
2914 common_function(argvars, rettv, TRUE);
2915}
2916
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002917 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002918ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002919{
2920 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2921 return &t_func_any;
Bram Moolenaar5e654232020-09-16 15:22:00 +02002922 return &t_func_unknown;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002923}
2924
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002925/*
2926 * "function()" function
2927 */
2928 static void
2929f_function(typval_T *argvars, typval_T *rettv)
2930{
2931 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002932}
2933
2934/*
2935 * "garbagecollect()" function
2936 */
2937 static void
2938f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2939{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002940 // This is postponed until we are back at the toplevel, because we may be
2941 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002942 want_garbage_collect = TRUE;
2943
Bram Moolenaar2df47312020-09-05 17:30:44 +02002944 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002945 garbage_collect_at_exit = TRUE;
2946}
2947
2948/*
2949 * "get()" function
2950 */
2951 static void
2952f_get(typval_T *argvars, typval_T *rettv)
2953{
2954 listitem_T *li;
2955 list_T *l;
2956 dictitem_T *di;
2957 dict_T *d;
2958 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002959 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002960
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002961 if (argvars[0].v_type == VAR_BLOB)
2962 {
2963 int error = FALSE;
2964 int idx = tv_get_number_chk(&argvars[1], &error);
2965
2966 if (!error)
2967 {
2968 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002969 if (idx < 0)
2970 idx = blob_len(argvars[0].vval.v_blob) + idx;
2971 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2972 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002973 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002974 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002975 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002976 tv = rettv;
2977 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002978 }
2979 }
2980 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002981 {
2982 if ((l = argvars[0].vval.v_list) != NULL)
2983 {
2984 int error = FALSE;
2985
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002986 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002987 if (!error && li != NULL)
2988 tv = &li->li_tv;
2989 }
2990 }
2991 else if (argvars[0].v_type == VAR_DICT)
2992 {
2993 if ((d = argvars[0].vval.v_dict) != NULL)
2994 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002995 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002996 if (di != NULL)
2997 tv = &di->di_tv;
2998 }
2999 }
3000 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3001 {
3002 partial_T *pt;
3003 partial_T fref_pt;
3004
3005 if (argvars[0].v_type == VAR_PARTIAL)
3006 pt = argvars[0].vval.v_partial;
3007 else
3008 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02003009 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003010 fref_pt.pt_name = argvars[0].vval.v_string;
3011 pt = &fref_pt;
3012 }
3013
3014 if (pt != NULL)
3015 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003016 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003017 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003018
3019 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3020 {
3021 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003022 n = partial_name(pt);
3023 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003024 rettv->vval.v_string = NULL;
3025 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003026 {
3027 rettv->vval.v_string = vim_strsave(n);
3028 if (rettv->v_type == VAR_FUNC)
3029 func_ref(rettv->vval.v_string);
3030 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003031 }
3032 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003033 {
3034 what_is_dict = TRUE;
3035 if (pt->pt_dict != NULL)
3036 rettv_dict_set(rettv, pt->pt_dict);
3037 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038 else if (STRCMP(what, "args") == 0)
3039 {
3040 rettv->v_type = VAR_LIST;
3041 if (rettv_list_alloc(rettv) == OK)
3042 {
3043 int i;
3044
3045 for (i = 0; i < pt->pt_argc; ++i)
3046 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3047 }
3048 }
3049 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003050 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003051
3052 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3053 // third argument
3054 if (!what_is_dict)
3055 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003056 }
3057 }
3058 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003059 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003060
3061 if (tv == NULL)
3062 {
3063 if (argvars[2].v_type != VAR_UNKNOWN)
3064 copy_tv(&argvars[2], rettv);
3065 }
3066 else
3067 copy_tv(tv, rettv);
3068}
3069
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003070/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003071 * "getchangelist()" function
3072 */
3073 static void
3074f_getchangelist(typval_T *argvars, typval_T *rettv)
3075{
3076#ifdef FEAT_JUMPLIST
3077 buf_T *buf;
3078 int i;
3079 list_T *l;
3080 dict_T *d;
3081#endif
3082
3083 if (rettv_list_alloc(rettv) != OK)
3084 return;
3085
3086#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003087 if (argvars[0].v_type == VAR_UNKNOWN)
3088 buf = curbuf;
3089 else
Bram Moolenaara5d38412020-09-02 21:02:35 +02003090 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003091 if (buf == NULL)
3092 return;
3093
3094 l = list_alloc();
3095 if (l == NULL)
3096 return;
3097
3098 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3099 return;
3100 /*
3101 * The current window change list index tracks only the position in the
3102 * current buffer change list. For other buffers, use the change list
3103 * length as the current index.
3104 */
3105 list_append_number(rettv->vval.v_list,
3106 (varnumber_T)((buf == curwin->w_buffer)
3107 ? curwin->w_changelistidx : buf->b_changelistlen));
3108
3109 for (i = 0; i < buf->b_changelistlen; ++i)
3110 {
3111 if (buf->b_changelist[i].lnum == 0)
3112 continue;
3113 if ((d = dict_alloc()) == NULL)
3114 return;
3115 if (list_append_dict(l, d) == FAIL)
3116 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003117 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3118 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003119 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003120 }
3121#endif
3122}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003123
3124/*
3125 * "getcharsearch()" function
3126 */
3127 static void
3128f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3129{
3130 if (rettv_dict_alloc(rettv) != FAIL)
3131 {
3132 dict_T *dict = rettv->vval.v_dict;
3133
Bram Moolenaare0be1672018-07-08 16:50:37 +02003134 dict_add_string(dict, "char", last_csearch());
3135 dict_add_number(dict, "forward", last_csearch_forward());
3136 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003137 }
3138}
3139
3140/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003141 * "getenv()" function
3142 */
3143 static void
3144f_getenv(typval_T *argvars, typval_T *rettv)
3145{
3146 int mustfree = FALSE;
3147 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3148
3149 if (p == NULL)
3150 {
3151 rettv->v_type = VAR_SPECIAL;
3152 rettv->vval.v_number = VVAL_NULL;
3153 return;
3154 }
3155 if (!mustfree)
3156 p = vim_strsave(p);
3157 rettv->vval.v_string = p;
3158 rettv->v_type = VAR_STRING;
3159}
3160
3161/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003162 * "getfontname()" function
3163 */
3164 static void
3165f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3166{
3167 rettv->v_type = VAR_STRING;
3168 rettv->vval.v_string = NULL;
3169#ifdef FEAT_GUI
3170 if (gui.in_use)
3171 {
3172 GuiFont font;
3173 char_u *name = NULL;
3174
3175 if (argvars[0].v_type == VAR_UNKNOWN)
3176 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003177 // Get the "Normal" font. Either the name saved by
3178 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003179 font = gui.norm_font;
3180 name = hl_get_font_name();
3181 }
3182 else
3183 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003184 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003185 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003186 return;
3187 font = gui_mch_get_font(name, FALSE);
3188 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003189 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003190 }
3191 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3192 if (argvars[0].v_type != VAR_UNKNOWN)
3193 gui_mch_free_font(font);
3194 }
3195#endif
3196}
3197
3198/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003199 * "getjumplist()" function
3200 */
3201 static void
3202f_getjumplist(typval_T *argvars, typval_T *rettv)
3203{
3204#ifdef FEAT_JUMPLIST
3205 win_T *wp;
3206 int i;
3207 list_T *l;
3208 dict_T *d;
3209#endif
3210
3211 if (rettv_list_alloc(rettv) != OK)
3212 return;
3213
3214#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003215 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003216 if (wp == NULL)
3217 return;
3218
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003219 cleanup_jumplist(wp, TRUE);
3220
Bram Moolenaar4f505882018-02-10 21:06:32 +01003221 l = list_alloc();
3222 if (l == NULL)
3223 return;
3224
3225 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3226 return;
3227 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3228
3229 for (i = 0; i < wp->w_jumplistlen; ++i)
3230 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003231 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3232 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003233 if ((d = dict_alloc()) == NULL)
3234 return;
3235 if (list_append_dict(l, d) == FAIL)
3236 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003237 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3238 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003239 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003240 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003241 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003242 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003243 }
3244#endif
3245}
3246
3247/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003248 * "getpid()" function
3249 */
3250 static void
3251f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3252{
3253 rettv->vval.v_number = mch_get_pid();
3254}
3255
3256 static void
3257getpos_both(
3258 typval_T *argvars,
3259 typval_T *rettv,
3260 int getcurpos)
3261{
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003262 pos_T *fp = NULL;
3263 win_T *wp = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003264 list_T *l;
3265 int fnum = -1;
3266
3267 if (rettv_list_alloc(rettv) == OK)
3268 {
3269 l = rettv->vval.v_list;
3270 if (getcurpos)
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003271 {
3272 if (argvars[0].v_type != VAR_UNKNOWN)
3273 {
3274 wp = find_win_by_nr_or_id(&argvars[0]);
3275 if (wp != NULL)
3276 fp = &wp->w_cursor;
3277 }
3278 else
3279 fp = &curwin->w_cursor;
3280 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003281 else
3282 fp = var2fpos(&argvars[0], TRUE, &fnum);
3283 if (fnum != -1)
3284 list_append_number(l, (varnumber_T)fnum);
3285 else
3286 list_append_number(l, (varnumber_T)0);
3287 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3288 : (varnumber_T)0);
3289 list_append_number(l, (fp != NULL)
3290 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3291 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003292 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003293 (varnumber_T)0);
3294 if (getcurpos)
3295 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003296 int save_set_curswant = curwin->w_set_curswant;
3297 colnr_T save_curswant = curwin->w_curswant;
3298 colnr_T save_virtcol = curwin->w_virtcol;
3299
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003300 if (wp == curwin)
3301 update_curswant();
3302 list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
3303 ? (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003304
3305 // Do not change "curswant", as it is unexpected that a get
3306 // function has a side effect.
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003307 if (wp == curwin && save_set_curswant)
Bram Moolenaar19a66852019-03-07 11:25:32 +01003308 {
3309 curwin->w_set_curswant = save_set_curswant;
3310 curwin->w_curswant = save_curswant;
3311 curwin->w_virtcol = save_virtcol;
3312 curwin->w_valid &= ~VALID_VIRTCOL;
3313 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003314 }
3315 }
3316 else
3317 rettv->vval.v_number = FALSE;
3318}
3319
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003320/*
3321 * "getcurpos()" function
3322 */
3323 static void
3324f_getcurpos(typval_T *argvars, typval_T *rettv)
3325{
3326 getpos_both(argvars, rettv, TRUE);
3327}
3328
3329/*
3330 * "getpos(string)" function
3331 */
3332 static void
3333f_getpos(typval_T *argvars, typval_T *rettv)
3334{
3335 getpos_both(argvars, rettv, FALSE);
3336}
3337
3338/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003339 * "getreg()" function
3340 */
3341 static void
3342f_getreg(typval_T *argvars, typval_T *rettv)
3343{
3344 char_u *strregname;
3345 int regname;
3346 int arg2 = FALSE;
3347 int return_list = FALSE;
3348 int error = FALSE;
3349
3350 if (argvars[0].v_type != VAR_UNKNOWN)
3351 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003352 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003353 error = strregname == NULL;
3354 if (argvars[1].v_type != VAR_UNKNOWN)
3355 {
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02003356 arg2 = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003357 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02003358 return_list = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003359 }
3360 }
3361 else
3362 strregname = get_vim_var_str(VV_REG);
3363
3364 if (error)
3365 return;
3366
3367 regname = (strregname == NULL ? '"' : *strregname);
3368 if (regname == 0)
3369 regname = '"';
3370
3371 if (return_list)
3372 {
3373 rettv->v_type = VAR_LIST;
3374 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3375 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3376 if (rettv->vval.v_list == NULL)
3377 (void)rettv_list_alloc(rettv);
3378 else
3379 ++rettv->vval.v_list->lv_refcount;
3380 }
3381 else
3382 {
3383 rettv->v_type = VAR_STRING;
3384 rettv->vval.v_string = get_reg_contents(regname,
3385 arg2 ? GREG_EXPR_SRC : 0);
3386 }
3387}
3388
3389/*
3390 * "getregtype()" function
3391 */
3392 static void
3393f_getregtype(typval_T *argvars, typval_T *rettv)
3394{
3395 char_u *strregname;
3396 int regname;
3397 char_u buf[NUMBUFLEN + 2];
3398 long reglen = 0;
3399
3400 if (argvars[0].v_type != VAR_UNKNOWN)
3401 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003402 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003403 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003404 {
3405 rettv->v_type = VAR_STRING;
3406 rettv->vval.v_string = NULL;
3407 return;
3408 }
3409 }
3410 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003411 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003412 strregname = get_vim_var_str(VV_REG);
3413
3414 regname = (strregname == NULL ? '"' : *strregname);
3415 if (regname == 0)
3416 regname = '"';
3417
3418 buf[0] = NUL;
3419 buf[1] = NUL;
3420 switch (get_reg_type(regname, &reglen))
3421 {
3422 case MLINE: buf[0] = 'V'; break;
3423 case MCHAR: buf[0] = 'v'; break;
3424 case MBLOCK:
3425 buf[0] = Ctrl_V;
3426 sprintf((char *)buf + 1, "%ld", reglen + 1);
3427 break;
3428 }
3429 rettv->v_type = VAR_STRING;
3430 rettv->vval.v_string = vim_strsave(buf);
3431}
3432
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003433/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003434 * "gettagstack()" function
3435 */
3436 static void
3437f_gettagstack(typval_T *argvars, typval_T *rettv)
3438{
3439 win_T *wp = curwin; // default is current window
3440
3441 if (rettv_dict_alloc(rettv) != OK)
3442 return;
3443
3444 if (argvars[0].v_type != VAR_UNKNOWN)
3445 {
3446 wp = find_win_by_nr_or_id(&argvars[0]);
3447 if (wp == NULL)
3448 return;
3449 }
3450
3451 get_tagstack(wp, rettv->vval.v_dict);
3452}
3453
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +02003454/*
3455 * "gettext()" function
3456 */
3457 static void
3458f_gettext(typval_T *argvars, typval_T *rettv)
3459{
3460 if (argvars[0].v_type != VAR_STRING
3461 || argvars[0].vval.v_string == NULL
3462 || *argvars[0].vval.v_string == NUL)
3463 {
3464 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
3465 }
3466 else
3467 {
3468 rettv->v_type = VAR_STRING;
3469 rettv->vval.v_string = vim_strsave(
3470 (char_u *)_(argvars[0].vval.v_string));
3471 }
3472}
3473
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003474// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475#include "version.h"
3476
3477/*
3478 * "has()" function
3479 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003480 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003481f_has(typval_T *argvars, typval_T *rettv)
3482{
3483 int i;
3484 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003485 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003486 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003487 typedef struct {
3488 char *name;
3489 short present;
3490 } has_item_T;
3491 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003493 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003494#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003495 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003496#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003497 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003498#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003499 },
3500 {"arp",
3501#if defined(AMIGA) && defined(FEAT_ARP)
3502 1
3503#else
3504 0
3505#endif
3506 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003507 {"haiku",
3508#ifdef __HAIKU__
3509 1
3510#else
3511 0
3512#endif
3513 },
3514 {"bsd",
3515#if defined(BSD) && !defined(MACOS_X)
3516 1
3517#else
3518 0
3519#endif
3520 },
3521 {"hpux",
3522#ifdef hpux
3523 1
3524#else
3525 0
3526#endif
3527 },
3528 {"linux",
3529#ifdef __linux__
3530 1
3531#else
3532 0
3533#endif
3534 },
3535 {"mac", // Mac OS X (and, once, Mac OS Classic)
3536#ifdef MACOS_X
3537 1
3538#else
3539 0
3540#endif
3541 },
3542 {"osx", // Mac OS X
3543#ifdef MACOS_X
3544 1
3545#else
3546 0
3547#endif
3548 },
3549 {"macunix", // Mac OS X, with the darwin feature
3550#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3551 1
3552#else
3553 0
3554#endif
3555 },
3556 {"osxdarwin", // synonym for macunix
3557#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3558 1
3559#else
3560 0
3561#endif
3562 },
3563 {"qnx",
3564#ifdef __QNX__
3565 1
3566#else
3567 0
3568#endif
3569 },
3570 {"sun",
3571#ifdef SUN_SYSTEM
3572 1
3573#else
3574 0
3575#endif
3576 },
3577 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003579 1
3580#else
3581 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003583 },
3584 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003585#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003586 1
3587#else
3588 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003590 },
3591 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003592#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003593 1
3594#else
3595 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003596#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003597 },
3598 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003599#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003600 1
3601#else
3602 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003604 },
3605 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003606#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003607 1
3608#else
3609 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003610#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003611 },
3612 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003613#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003614 1
3615#else
3616 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003617#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003618 },
3619 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003620#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003621 1
3622#else
3623 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003624#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003625 },
3626 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003627#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003628 1
3629#else
3630 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003631#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003632 },
3633 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003635 1
3636#else
3637 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003639 },
3640 {"autocmd", 1},
3641 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003642#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003643 1
3644#else
3645 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003646#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003647 },
3648 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003649#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003650 1
3651#else
3652 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003653#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003654 },
3655 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003656#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003657 1
3658#else
3659 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003660#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003661 },
3662 {"balloon_multiline",
3663#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3664 // MS-Windows requires runtime check, see below
3665 1
3666#else
3667 0
3668#endif
3669 },
3670 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003671#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003672 1
3673#else
3674 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003675#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003676 },
3677 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003678#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003679 1
3680#else
3681 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003682#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003683 },
3684 {"all_builtin_terms",
3685#if defined(ALL_BUILTIN_TCAPS)
3686 1
3687#else
3688 0
3689#endif
3690 },
3691 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003692#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003693 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003694 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003695 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003696#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003697 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003698#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003699 },
3700 {"byte_offset",
3701#ifdef FEAT_BYTEOFF
3702 1
3703#else
3704 0
3705#endif
3706 },
3707 {"channel",
3708#ifdef FEAT_JOB_CHANNEL
3709 1
3710#else
3711 0
3712#endif
3713 },
3714 {"cindent",
3715#ifdef FEAT_CINDENT
3716 1
3717#else
3718 0
3719#endif
3720 },
3721 {"clientserver",
3722#ifdef FEAT_CLIENTSERVER
3723 1
3724#else
3725 0
3726#endif
3727 },
3728 {"clipboard",
3729#ifdef FEAT_CLIPBOARD
3730 1
3731#else
3732 0
3733#endif
3734 },
3735 {"cmdline_compl", 1},
3736 {"cmdline_hist", 1},
3737 {"comments", 1},
3738 {"conceal",
3739#ifdef FEAT_CONCEAL
3740 1
3741#else
3742 0
3743#endif
3744 },
3745 {"cryptv",
3746#ifdef FEAT_CRYPT
3747 1
3748#else
3749 0
3750#endif
3751 },
3752 {"crypt-blowfish",
3753#ifdef FEAT_CRYPT
3754 1
3755#else
3756 0
3757#endif
3758 },
3759 {"crypt-blowfish2",
3760#ifdef FEAT_CRYPT
3761 1
3762#else
3763 0
3764#endif
3765 },
3766 {"cscope",
3767#ifdef FEAT_CSCOPE
3768 1
3769#else
3770 0
3771#endif
3772 },
3773 {"cursorbind", 1},
3774 {"cursorshape",
3775#ifdef CURSOR_SHAPE
3776 1
3777#else
3778 0
3779#endif
3780 },
3781 {"debug",
3782#ifdef DEBUG
3783 1
3784#else
3785 0
3786#endif
3787 },
3788 {"dialog_con",
3789#ifdef FEAT_CON_DIALOG
3790 1
3791#else
3792 0
3793#endif
3794 },
3795 {"dialog_gui",
3796#ifdef FEAT_GUI_DIALOG
3797 1
3798#else
3799 0
3800#endif
3801 },
3802 {"diff",
3803#ifdef FEAT_DIFF
3804 1
3805#else
3806 0
3807#endif
3808 },
3809 {"digraphs",
3810#ifdef FEAT_DIGRAPHS
3811 1
3812#else
3813 0
3814#endif
3815 },
3816 {"directx",
3817#ifdef FEAT_DIRECTX
3818 1
3819#else
3820 0
3821#endif
3822 },
3823 {"dnd",
3824#ifdef FEAT_DND
3825 1
3826#else
3827 0
3828#endif
3829 },
3830 {"emacs_tags",
3831#ifdef FEAT_EMACS_TAGS
3832 1
3833#else
3834 0
3835#endif
3836 },
3837 {"eval", 1}, // always present, of course!
3838 {"ex_extra", 1}, // graduated feature
3839 {"extra_search",
3840#ifdef FEAT_SEARCH_EXTRA
3841 1
3842#else
3843 0
3844#endif
3845 },
3846 {"file_in_path",
3847#ifdef FEAT_SEARCHPATH
3848 1
3849#else
3850 0
3851#endif
3852 },
3853 {"filterpipe",
3854#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3855 1
3856#else
3857 0
3858#endif
3859 },
3860 {"find_in_path",
3861#ifdef FEAT_FIND_ID
3862 1
3863#else
3864 0
3865#endif
3866 },
3867 {"float",
3868#ifdef FEAT_FLOAT
3869 1
3870#else
3871 0
3872#endif
3873 },
3874 {"folding",
3875#ifdef FEAT_FOLDING
3876 1
3877#else
3878 0
3879#endif
3880 },
3881 {"footer",
3882#ifdef FEAT_FOOTER
3883 1
3884#else
3885 0
3886#endif
3887 },
3888 {"fork",
3889#if !defined(USE_SYSTEM) && defined(UNIX)
3890 1
3891#else
3892 0
3893#endif
3894 },
3895 {"gettext",
3896#ifdef FEAT_GETTEXT
3897 1
3898#else
3899 0
3900#endif
3901 },
3902 {"gui",
3903#ifdef FEAT_GUI
3904 1
3905#else
3906 0
3907#endif
3908 },
3909 {"gui_neXtaw",
3910#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3911 1
3912#else
3913 0
3914#endif
3915 },
3916 {"gui_athena",
3917#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3918 1
3919#else
3920 0
3921#endif
3922 },
3923 {"gui_gtk",
3924#ifdef FEAT_GUI_GTK
3925 1
3926#else
3927 0
3928#endif
3929 },
3930 {"gui_gtk2",
3931#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3932 1
3933#else
3934 0
3935#endif
3936 },
3937 {"gui_gtk3",
3938#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3939 1
3940#else
3941 0
3942#endif
3943 },
3944 {"gui_gnome",
3945#ifdef FEAT_GUI_GNOME
3946 1
3947#else
3948 0
3949#endif
3950 },
3951 {"gui_haiku",
3952#ifdef FEAT_GUI_HAIKU
3953 1
3954#else
3955 0
3956#endif
3957 },
Bram Moolenaar097148e2020-08-11 21:58:20 +02003958 {"gui_mac", 0},
Bram Moolenaar79296512020-03-22 16:17:14 +01003959 {"gui_motif",
3960#ifdef FEAT_GUI_MOTIF
3961 1
3962#else
3963 0
3964#endif
3965 },
3966 {"gui_photon",
3967#ifdef FEAT_GUI_PHOTON
3968 1
3969#else
3970 0
3971#endif
3972 },
3973 {"gui_win32",
3974#ifdef FEAT_GUI_MSWIN
3975 1
3976#else
3977 0
3978#endif
3979 },
3980 {"iconv",
3981#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3982 1
3983#else
3984 0
3985#endif
3986 },
3987 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003988 {"ipv6",
3989#ifdef FEAT_IPV6
3990 1
3991#else
3992 0
3993#endif
3994 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003995 {"job",
3996#ifdef FEAT_JOB_CHANNEL
3997 1
3998#else
3999 0
4000#endif
4001 },
4002 {"jumplist",
4003#ifdef FEAT_JUMPLIST
4004 1
4005#else
4006 0
4007#endif
4008 },
4009 {"keymap",
4010#ifdef FEAT_KEYMAP
4011 1
4012#else
4013 0
4014#endif
4015 },
4016 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
4017 {"langmap",
4018#ifdef FEAT_LANGMAP
4019 1
4020#else
4021 0
4022#endif
4023 },
4024 {"libcall",
4025#ifdef FEAT_LIBCALL
4026 1
4027#else
4028 0
4029#endif
4030 },
4031 {"linebreak",
4032#ifdef FEAT_LINEBREAK
4033 1
4034#else
4035 0
4036#endif
4037 },
4038 {"lispindent",
4039#ifdef FEAT_LISP
4040 1
4041#else
4042 0
4043#endif
4044 },
4045 {"listcmds", 1},
4046 {"localmap", 1},
4047 {"lua",
4048#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
4049 1
4050#else
4051 0
4052#endif
4053 },
4054 {"menu",
4055#ifdef FEAT_MENU
4056 1
4057#else
4058 0
4059#endif
4060 },
4061 {"mksession",
4062#ifdef FEAT_SESSION
4063 1
4064#else
4065 0
4066#endif
4067 },
4068 {"modify_fname", 1},
4069 {"mouse", 1},
4070 {"mouseshape",
4071#ifdef FEAT_MOUSESHAPE
4072 1
4073#else
4074 0
4075#endif
4076 },
4077 {"mouse_dec",
4078#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
4079 1
4080#else
4081 0
4082#endif
4083 },
4084 {"mouse_gpm",
4085#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
4086 1
4087#else
4088 0
4089#endif
4090 },
4091 {"mouse_jsbterm",
4092#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
4093 1
4094#else
4095 0
4096#endif
4097 },
4098 {"mouse_netterm",
4099#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
4100 1
4101#else
4102 0
4103#endif
4104 },
4105 {"mouse_pterm",
4106#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
4107 1
4108#else
4109 0
4110#endif
4111 },
4112 {"mouse_sgr",
4113#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4114 1
4115#else
4116 0
4117#endif
4118 },
4119 {"mouse_sysmouse",
4120#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4121 1
4122#else
4123 0
4124#endif
4125 },
4126 {"mouse_urxvt",
4127#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4128 1
4129#else
4130 0
4131#endif
4132 },
4133 {"mouse_xterm",
4134#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4135 1
4136#else
4137 0
4138#endif
4139 },
4140 {"multi_byte", 1},
4141 {"multi_byte_ime",
4142#ifdef FEAT_MBYTE_IME
4143 1
4144#else
4145 0
4146#endif
4147 },
4148 {"multi_lang",
4149#ifdef FEAT_MULTI_LANG
4150 1
4151#else
4152 0
4153#endif
4154 },
4155 {"mzscheme",
4156#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4157 1
4158#else
4159 0
4160#endif
4161 },
4162 {"num64", 1},
4163 {"ole",
4164#ifdef FEAT_OLE
4165 1
4166#else
4167 0
4168#endif
4169 },
4170 {"packages",
4171#ifdef FEAT_EVAL
4172 1
4173#else
4174 0
4175#endif
4176 },
4177 {"path_extra",
4178#ifdef FEAT_PATH_EXTRA
4179 1
4180#else
4181 0
4182#endif
4183 },
4184 {"perl",
4185#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4186 1
4187#else
4188 0
4189#endif
4190 },
4191 {"persistent_undo",
4192#ifdef FEAT_PERSISTENT_UNDO
4193 1
4194#else
4195 0
4196#endif
4197 },
4198 {"python_compiled",
4199#if defined(FEAT_PYTHON)
4200 1
4201#else
4202 0
4203#endif
4204 },
4205 {"python_dynamic",
4206#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4207 1
4208#else
4209 0
4210#endif
4211 },
4212 {"python",
4213#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4214 1
4215#else
4216 0
4217#endif
4218 },
4219 {"pythonx",
4220#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4221 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4222 1
4223#else
4224 0
4225#endif
4226 },
4227 {"python3_compiled",
4228#if defined(FEAT_PYTHON3)
4229 1
4230#else
4231 0
4232#endif
4233 },
4234 {"python3_dynamic",
4235#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4236 1
4237#else
4238 0
4239#endif
4240 },
4241 {"python3",
4242#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4243 1
4244#else
4245 0
4246#endif
4247 },
4248 {"popupwin",
4249#ifdef FEAT_PROP_POPUP
4250 1
4251#else
4252 0
4253#endif
4254 },
4255 {"postscript",
4256#ifdef FEAT_POSTSCRIPT
4257 1
4258#else
4259 0
4260#endif
4261 },
4262 {"printer",
4263#ifdef FEAT_PRINTER
4264 1
4265#else
4266 0
4267#endif
4268 },
4269 {"profile",
4270#ifdef FEAT_PROFILE
4271 1
4272#else
4273 0
4274#endif
4275 },
4276 {"reltime",
4277#ifdef FEAT_RELTIME
4278 1
4279#else
4280 0
4281#endif
4282 },
4283 {"quickfix",
4284#ifdef FEAT_QUICKFIX
4285 1
4286#else
4287 0
4288#endif
4289 },
4290 {"rightleft",
4291#ifdef FEAT_RIGHTLEFT
4292 1
4293#else
4294 0
4295#endif
4296 },
4297 {"ruby",
4298#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4299 1
4300#else
4301 0
4302#endif
4303 },
4304 {"scrollbind", 1},
4305 {"showcmd",
4306#ifdef FEAT_CMDL_INFO
4307 1
4308#else
4309 0
4310#endif
4311 },
4312 {"cmdline_info",
4313#ifdef FEAT_CMDL_INFO
4314 1
4315#else
4316 0
4317#endif
4318 },
4319 {"signs",
4320#ifdef FEAT_SIGNS
4321 1
4322#else
4323 0
4324#endif
4325 },
4326 {"smartindent",
4327#ifdef FEAT_SMARTINDENT
4328 1
4329#else
4330 0
4331#endif
4332 },
4333 {"startuptime",
4334#ifdef STARTUPTIME
4335 1
4336#else
4337 0
4338#endif
4339 },
4340 {"statusline",
4341#ifdef FEAT_STL_OPT
4342 1
4343#else
4344 0
4345#endif
4346 },
4347 {"netbeans_intg",
4348#ifdef FEAT_NETBEANS_INTG
4349 1
4350#else
4351 0
4352#endif
4353 },
4354 {"sound",
4355#ifdef FEAT_SOUND
4356 1
4357#else
4358 0
4359#endif
4360 },
4361 {"spell",
4362#ifdef FEAT_SPELL
4363 1
4364#else
4365 0
4366#endif
4367 },
4368 {"syntax",
4369#ifdef FEAT_SYN_HL
4370 1
4371#else
4372 0
4373#endif
4374 },
4375 {"system",
4376#if defined(USE_SYSTEM) || !defined(UNIX)
4377 1
4378#else
4379 0
4380#endif
4381 },
4382 {"tag_binary",
4383#ifdef FEAT_TAG_BINS
4384 1
4385#else
4386 0
4387#endif
4388 },
4389 {"tcl",
4390#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4391 1
4392#else
4393 0
4394#endif
4395 },
4396 {"termguicolors",
4397#ifdef FEAT_TERMGUICOLORS
4398 1
4399#else
4400 0
4401#endif
4402 },
4403 {"terminal",
4404#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4405 1
4406#else
4407 0
4408#endif
4409 },
4410 {"terminfo",
4411#ifdef TERMINFO
4412 1
4413#else
4414 0
4415#endif
4416 },
4417 {"termresponse",
4418#ifdef FEAT_TERMRESPONSE
4419 1
4420#else
4421 0
4422#endif
4423 },
4424 {"textobjects",
4425#ifdef FEAT_TEXTOBJ
4426 1
4427#else
4428 0
4429#endif
4430 },
4431 {"textprop",
4432#ifdef FEAT_PROP_POPUP
4433 1
4434#else
4435 0
4436#endif
4437 },
4438 {"tgetent",
4439#ifdef HAVE_TGETENT
4440 1
4441#else
4442 0
4443#endif
4444 },
4445 {"timers",
4446#ifdef FEAT_TIMERS
4447 1
4448#else
4449 0
4450#endif
4451 },
4452 {"title",
4453#ifdef FEAT_TITLE
4454 1
4455#else
4456 0
4457#endif
4458 },
4459 {"toolbar",
4460#ifdef FEAT_TOOLBAR
4461 1
4462#else
4463 0
4464#endif
4465 },
4466 {"unnamedplus",
4467#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4468 1
4469#else
4470 0
4471#endif
4472 },
4473 {"user-commands", 1}, // was accidentally included in 5.4
4474 {"user_commands", 1},
4475 {"vartabs",
4476#ifdef FEAT_VARTABS
4477 1
4478#else
4479 0
4480#endif
4481 },
4482 {"vertsplit", 1},
4483 {"viminfo",
4484#ifdef FEAT_VIMINFO
4485 1
4486#else
4487 0
4488#endif
4489 },
4490 {"vimscript-1", 1},
4491 {"vimscript-2", 1},
4492 {"vimscript-3", 1},
4493 {"vimscript-4", 1},
4494 {"virtualedit", 1},
4495 {"visual", 1},
4496 {"visualextra", 1},
4497 {"vreplace", 1},
4498 {"vtp",
4499#ifdef FEAT_VTP
4500 1
4501#else
4502 0
4503#endif
4504 },
4505 {"wildignore",
4506#ifdef FEAT_WILDIGN
4507 1
4508#else
4509 0
4510#endif
4511 },
4512 {"wildmenu",
4513#ifdef FEAT_WILDMENU
4514 1
4515#else
4516 0
4517#endif
4518 },
4519 {"windows", 1},
4520 {"winaltkeys",
4521#ifdef FEAT_WAK
4522 1
4523#else
4524 0
4525#endif
4526 },
4527 {"writebackup",
4528#ifdef FEAT_WRITEBACKUP
4529 1
4530#else
4531 0
4532#endif
4533 },
4534 {"xim",
4535#ifdef FEAT_XIM
4536 1
4537#else
4538 0
4539#endif
4540 },
4541 {"xfontset",
4542#ifdef FEAT_XFONTSET
4543 1
4544#else
4545 0
4546#endif
4547 },
4548 {"xpm",
4549#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4550 1
4551#else
4552 0
4553#endif
4554 },
4555 {"xpm_w32", // for backward compatibility
4556#ifdef FEAT_XPM_W32
4557 1
4558#else
4559 0
4560#endif
4561 },
4562 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004564 1
4565#else
4566 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004567#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004568 },
4569 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004570#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004571 1
4572#else
4573 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004574#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004575 },
4576 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004577#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004578 1
4579#else
4580 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004581#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004582 },
4583 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004584#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004585 1
4586#else
4587 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004588#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004589 },
4590 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004591#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004592 1
4593#else
4594 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004595#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004596 },
4597 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004598 };
4599
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004600 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004601 for (i = 0; has_list[i].name != NULL; ++i)
4602 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004603 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004604 x = TRUE;
4605 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004606 break;
4607 }
4608
Bram Moolenaar79296512020-03-22 16:17:14 +01004609 // features also in has_list[] but sometimes enabled at runtime
4610 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004612 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004613 {
4614 // intentionally empty
4615 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004616#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004617 else if (STRICMP(name, "balloon_multiline") == 0)
4618 n = multiline_balloon_available();
4619#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004620#ifdef VIMDLL
4621 else if (STRICMP(name, "filterpipe") == 0)
4622 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004623#endif
4624#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4625 else if (STRICMP(name, "iconv") == 0)
4626 n = iconv_enabled(FALSE);
4627#endif
4628#ifdef DYNAMIC_LUA
4629 else if (STRICMP(name, "lua") == 0)
4630 n = lua_enabled(FALSE);
4631#endif
4632#ifdef DYNAMIC_MZSCHEME
4633 else if (STRICMP(name, "mzscheme") == 0)
4634 n = mzscheme_enabled(FALSE);
4635#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004636#ifdef DYNAMIC_PERL
4637 else if (STRICMP(name, "perl") == 0)
4638 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004639#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004640#ifdef DYNAMIC_PYTHON
4641 else if (STRICMP(name, "python") == 0)
4642 n = python_enabled(FALSE);
4643#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004644#ifdef DYNAMIC_PYTHON3
4645 else if (STRICMP(name, "python3") == 0)
4646 n = python3_enabled(FALSE);
4647#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004648#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4649 else if (STRICMP(name, "pythonx") == 0)
4650 {
4651# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4652 if (p_pyx == 0)
4653 n = python3_enabled(FALSE) || python_enabled(FALSE);
4654 else if (p_pyx == 3)
4655 n = python3_enabled(FALSE);
4656 else if (p_pyx == 2)
4657 n = python_enabled(FALSE);
4658# elif defined(DYNAMIC_PYTHON)
4659 n = python_enabled(FALSE);
4660# elif defined(DYNAMIC_PYTHON3)
4661 n = python3_enabled(FALSE);
4662# endif
4663 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004665#ifdef DYNAMIC_RUBY
4666 else if (STRICMP(name, "ruby") == 0)
4667 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004668#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004669#ifdef DYNAMIC_TCL
4670 else if (STRICMP(name, "tcl") == 0)
4671 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004672#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004673#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004674 else if (STRICMP(name, "terminal") == 0)
4675 n = terminal_enabled();
4676#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004677 }
4678
Bram Moolenaar79296512020-03-22 16:17:14 +01004679 // features not in has_list[]
4680 if (x == FALSE)
4681 {
4682 if (STRNICMP(name, "patch", 5) == 0)
4683 {
4684 x = TRUE;
4685 if (name[5] == '-'
4686 && STRLEN(name) >= 11
4687 && vim_isdigit(name[6])
4688 && vim_isdigit(name[8])
4689 && vim_isdigit(name[10]))
4690 {
4691 int major = atoi((char *)name + 6);
4692 int minor = atoi((char *)name + 8);
4693
4694 // Expect "patch-9.9.01234".
4695 n = (major < VIM_VERSION_MAJOR
4696 || (major == VIM_VERSION_MAJOR
4697 && (minor < VIM_VERSION_MINOR
4698 || (minor == VIM_VERSION_MINOR
4699 && has_patch(atoi((char *)name + 10))))));
4700 }
4701 else
4702 n = has_patch(atoi((char *)name + 5));
4703 }
4704 else if (STRICMP(name, "vim_starting") == 0)
4705 {
4706 x = TRUE;
4707 n = (starting != 0);
4708 }
4709 else if (STRICMP(name, "ttyin") == 0)
4710 {
4711 x = TRUE;
4712 n = mch_input_isatty();
4713 }
4714 else if (STRICMP(name, "ttyout") == 0)
4715 {
4716 x = TRUE;
4717 n = stdout_isatty;
4718 }
4719 else if (STRICMP(name, "multi_byte_encoding") == 0)
4720 {
4721 x = TRUE;
4722 n = has_mbyte;
4723 }
4724 else if (STRICMP(name, "gui_running") == 0)
4725 {
4726 x = TRUE;
4727#ifdef FEAT_GUI
4728 n = (gui.in_use || gui.starting);
4729#endif
4730 }
4731 else if (STRICMP(name, "browse") == 0)
4732 {
4733 x = TRUE;
4734#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4735 n = gui.in_use; // gui_mch_browse() works when GUI is running
4736#endif
4737 }
4738 else if (STRICMP(name, "syntax_items") == 0)
4739 {
4740 x = TRUE;
4741#ifdef FEAT_SYN_HL
4742 n = syntax_present(curwin);
4743#endif
4744 }
4745 else if (STRICMP(name, "vcon") == 0)
4746 {
4747 x = TRUE;
4748#ifdef FEAT_VTP
4749 n = is_term_win32() && has_vtp_working();
4750#endif
4751 }
4752 else if (STRICMP(name, "netbeans_enabled") == 0)
4753 {
4754 x = TRUE;
4755#ifdef FEAT_NETBEANS_INTG
4756 n = netbeans_active();
4757#endif
4758 }
4759 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4760 {
4761 x = TRUE;
4762#ifdef FEAT_MOUSE_GPM
4763 n = gpm_enabled();
4764#endif
4765 }
4766 else if (STRICMP(name, "conpty") == 0)
4767 {
4768 x = TRUE;
4769#if defined(FEAT_TERMINAL) && defined(MSWIN)
4770 n = use_conpty();
4771#endif
4772 }
4773 else if (STRICMP(name, "clipboard_working") == 0)
4774 {
4775 x = TRUE;
4776#ifdef FEAT_CLIPBOARD
4777 n = clip_star.available;
4778#endif
4779 }
4780 }
4781
Bram Moolenaar04637e22020-09-05 18:45:29 +02004782 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]))
Bram Moolenaar79296512020-03-22 16:17:14 +01004783 // return whether feature could ever be enabled
4784 rettv->vval.v_number = x;
4785 else
4786 // return whether feature is enabled
4787 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004788}
4789
4790/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004791 * "haslocaldir()" function
4792 */
4793 static void
4794f_haslocaldir(typval_T *argvars, typval_T *rettv)
4795{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004796 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004797 win_T *wp = NULL;
4798
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004799 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4800
4801 // Check for window-local and tab-local directories
4802 if (wp != NULL && wp->w_localdir != NULL)
4803 rettv->vval.v_number = 1;
4804 else if (tp != NULL && tp->tp_localdir != NULL)
4805 rettv->vval.v_number = 2;
4806 else
4807 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004808}
4809
4810/*
4811 * "hasmapto()" function
4812 */
4813 static void
4814f_hasmapto(typval_T *argvars, typval_T *rettv)
4815{
4816 char_u *name;
4817 char_u *mode;
4818 char_u buf[NUMBUFLEN];
4819 int abbr = FALSE;
4820
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004821 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004822 if (argvars[1].v_type == VAR_UNKNOWN)
4823 mode = (char_u *)"nvo";
4824 else
4825 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004826 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004827 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar04d594b2020-09-02 22:25:35 +02004828 abbr = (int)tv_get_bool(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004829 }
4830
4831 if (map_to_exists(name, mode, abbr))
4832 rettv->vval.v_number = TRUE;
4833 else
4834 rettv->vval.v_number = FALSE;
4835}
4836
4837/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004838 * "highlightID(name)" function
4839 */
4840 static void
4841f_hlID(typval_T *argvars, typval_T *rettv)
4842{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004843 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844}
4845
4846/*
4847 * "highlight_exists()" function
4848 */
4849 static void
4850f_hlexists(typval_T *argvars, typval_T *rettv)
4851{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004852 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853}
4854
4855/*
4856 * "hostname()" function
4857 */
4858 static void
4859f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4860{
4861 char_u hostname[256];
4862
4863 mch_get_host_name(hostname, 256);
4864 rettv->v_type = VAR_STRING;
4865 rettv->vval.v_string = vim_strsave(hostname);
4866}
4867
4868/*
4869 * iconv() function
4870 */
4871 static void
4872f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4873{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004874 char_u buf1[NUMBUFLEN];
4875 char_u buf2[NUMBUFLEN];
4876 char_u *from, *to, *str;
4877 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878
4879 rettv->v_type = VAR_STRING;
4880 rettv->vval.v_string = NULL;
4881
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004882 str = tv_get_string(&argvars[0]);
4883 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4884 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004885 vimconv.vc_type = CONV_NONE;
4886 convert_setup(&vimconv, from, to);
4887
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004888 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004889 if (vimconv.vc_type == CONV_NONE)
4890 rettv->vval.v_string = vim_strsave(str);
4891 else
4892 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4893
4894 convert_setup(&vimconv, NULL, NULL);
4895 vim_free(from);
4896 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004897}
4898
4899/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004900 * "index()" function
4901 */
4902 static void
4903f_index(typval_T *argvars, typval_T *rettv)
4904{
4905 list_T *l;
4906 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004907 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908 long idx = 0;
4909 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004910 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911
4912 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004913 if (argvars[0].v_type == VAR_BLOB)
4914 {
4915 typval_T tv;
4916 int start = 0;
4917
4918 if (argvars[2].v_type != VAR_UNKNOWN)
4919 {
4920 start = tv_get_number_chk(&argvars[2], &error);
4921 if (error)
4922 return;
4923 }
4924 b = argvars[0].vval.v_blob;
4925 if (b == NULL)
4926 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004927 if (start < 0)
4928 {
4929 start = blob_len(b) + start;
4930 if (start < 0)
4931 start = 0;
4932 }
4933
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004934 for (idx = start; idx < blob_len(b); ++idx)
4935 {
4936 tv.v_type = VAR_NUMBER;
4937 tv.vval.v_number = blob_get(b, idx);
4938 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4939 {
4940 rettv->vval.v_number = idx;
4941 return;
4942 }
4943 }
4944 return;
4945 }
4946 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004948 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004949 return;
4950 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004951
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004952 l = argvars[0].vval.v_list;
4953 if (l != NULL)
4954 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004955 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004956 item = l->lv_first;
4957 if (argvars[2].v_type != VAR_UNKNOWN)
4958 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004959 // Start at specified item. Use the cached index that list_find()
4960 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004961 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004962 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004963 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaar6c553f92020-09-02 22:10:34 +02004964 ic = (int)tv_get_bool_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965 if (error)
4966 item = NULL;
4967 }
4968
4969 for ( ; item != NULL; item = item->li_next, ++idx)
4970 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4971 {
4972 rettv->vval.v_number = idx;
4973 break;
4974 }
4975 }
4976}
4977
4978static int inputsecret_flag = 0;
4979
4980/*
4981 * "input()" function
4982 * Also handles inputsecret() when inputsecret is set.
4983 */
4984 static void
4985f_input(typval_T *argvars, typval_T *rettv)
4986{
4987 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4988}
4989
4990/*
4991 * "inputdialog()" function
4992 */
4993 static void
4994f_inputdialog(typval_T *argvars, typval_T *rettv)
4995{
4996#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004997 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004998 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4999 {
5000 char_u *message;
5001 char_u buf[NUMBUFLEN];
5002 char_u *defstr = (char_u *)"";
5003
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005004 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005005 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005006 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005007 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5008 else
5009 IObuff[0] = NUL;
5010 if (message != NULL && defstr != NULL
5011 && do_dialog(VIM_QUESTION, NULL, message,
5012 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5013 rettv->vval.v_string = vim_strsave(IObuff);
5014 else
5015 {
5016 if (message != NULL && defstr != NULL
5017 && argvars[1].v_type != VAR_UNKNOWN
5018 && argvars[2].v_type != VAR_UNKNOWN)
5019 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005020 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005021 else
5022 rettv->vval.v_string = NULL;
5023 }
5024 rettv->v_type = VAR_STRING;
5025 }
5026 else
5027#endif
5028 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5029}
5030
5031/*
5032 * "inputlist()" function
5033 */
5034 static void
5035f_inputlist(typval_T *argvars, typval_T *rettv)
5036{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005037 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005038 listitem_T *li;
5039 int selected;
5040 int mouse_used;
5041
5042#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005043 // While starting up, there is no place to enter text. When running tests
5044 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02005045 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005046 return;
5047#endif
5048 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5049 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005050 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005051 return;
5052 }
5053
5054 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005055 msg_row = Rows - 1; // for when 'cmdheight' > 1
5056 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005057 msg_scroll = TRUE;
5058 msg_clr_eos();
5059
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005060 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005061 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02005062 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005063 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005064 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065 msg_putchar('\n');
5066 }
5067
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005068 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005069 selected = prompt_for_number(&mouse_used);
5070 if (mouse_used)
5071 selected -= lines_left;
5072
5073 rettv->vval.v_number = selected;
5074}
5075
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5077
5078/*
5079 * "inputrestore()" function
5080 */
5081 static void
5082f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5083{
5084 if (ga_userinput.ga_len > 0)
5085 {
5086 --ga_userinput.ga_len;
5087 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5088 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005089 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005090 }
5091 else if (p_verbose > 1)
5092 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005093 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005094 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005095 }
5096}
5097
5098/*
5099 * "inputsave()" function
5100 */
5101 static void
5102f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5103{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005104 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 if (ga_grow(&ga_userinput, 1) == OK)
5106 {
5107 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5108 + ga_userinput.ga_len);
5109 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005110 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005111 }
5112 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005113 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114}
5115
5116/*
5117 * "inputsecret()" function
5118 */
5119 static void
5120f_inputsecret(typval_T *argvars, typval_T *rettv)
5121{
5122 ++cmdline_star;
5123 ++inputsecret_flag;
5124 f_input(argvars, rettv);
5125 --cmdline_star;
5126 --inputsecret_flag;
5127}
5128
5129/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005130 * "interrupt()" function
5131 */
5132 static void
5133f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5134{
5135 got_int = TRUE;
5136}
5137
5138/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005139 * "invert(expr)" function
5140 */
5141 static void
5142f_invert(typval_T *argvars, typval_T *rettv)
5143{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005144 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145}
5146
5147/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005148 * "islocked()" function
5149 */
5150 static void
5151f_islocked(typval_T *argvars, typval_T *rettv)
5152{
5153 lval_T lv;
5154 char_u *end;
5155 dictitem_T *di;
5156
5157 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005158 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005159 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005160 if (end != NULL && lv.ll_name != NULL)
5161 {
5162 if (*end != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02005163 semsg(_(e_trailing_arg), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005164 else
5165 {
5166 if (lv.ll_tv == NULL)
5167 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005168 di = find_var(lv.ll_name, NULL, TRUE);
5169 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005170 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005171 // Consider a variable locked when:
5172 // 1. the variable itself is locked
5173 // 2. the value of the variable is locked.
5174 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005175 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5176 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005177 }
5178 }
5179 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005180 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005181 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005182 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005183 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005184 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005185 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5186 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005187 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005188 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5189 }
5190 }
5191
5192 clear_lval(&lv);
5193}
5194
5195#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5196/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005197 * "isinf()" function
5198 */
5199 static void
5200f_isinf(typval_T *argvars, typval_T *rettv)
5201{
5202 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5203 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5204}
5205
5206/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005207 * "isnan()" function
5208 */
5209 static void
5210f_isnan(typval_T *argvars, typval_T *rettv)
5211{
5212 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5213 && isnan(argvars[0].vval.v_float);
5214}
5215#endif
5216
5217/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005218 * "last_buffer_nr()" function.
5219 */
5220 static void
5221f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5222{
5223 int n = 0;
5224 buf_T *buf;
5225
Bram Moolenaar29323592016-07-24 22:04:11 +02005226 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005227 if (n < buf->b_fnum)
5228 n = buf->b_fnum;
5229
5230 rettv->vval.v_number = n;
5231}
5232
5233/*
5234 * "len()" function
5235 */
5236 static void
5237f_len(typval_T *argvars, typval_T *rettv)
5238{
5239 switch (argvars[0].v_type)
5240 {
5241 case VAR_STRING:
5242 case VAR_NUMBER:
5243 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005244 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005245 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005246 case VAR_BLOB:
5247 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5248 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005249 case VAR_LIST:
5250 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5251 break;
5252 case VAR_DICT:
5253 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5254 break;
5255 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005256 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005257 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005258 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005259 case VAR_SPECIAL:
5260 case VAR_FLOAT:
5261 case VAR_FUNC:
5262 case VAR_PARTIAL:
5263 case VAR_JOB:
5264 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005265 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005266 break;
5267 }
5268}
5269
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005270 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005271libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005272{
5273#ifdef FEAT_LIBCALL
5274 char_u *string_in;
5275 char_u **string_result;
5276 int nr_result;
5277#endif
5278
5279 rettv->v_type = type;
5280 if (type != VAR_NUMBER)
5281 rettv->vval.v_string = NULL;
5282
5283 if (check_restricted() || check_secure())
5284 return;
5285
5286#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005287 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5289 {
5290 string_in = NULL;
5291 if (argvars[2].v_type == VAR_STRING)
5292 string_in = argvars[2].vval.v_string;
5293 if (type == VAR_NUMBER)
5294 string_result = NULL;
5295 else
5296 string_result = &rettv->vval.v_string;
5297 if (mch_libcall(argvars[0].vval.v_string,
5298 argvars[1].vval.v_string,
5299 string_in,
5300 argvars[2].vval.v_number,
5301 string_result,
5302 &nr_result) == OK
5303 && type == VAR_NUMBER)
5304 rettv->vval.v_number = nr_result;
5305 }
5306#endif
5307}
5308
5309/*
5310 * "libcall()" function
5311 */
5312 static void
5313f_libcall(typval_T *argvars, typval_T *rettv)
5314{
5315 libcall_common(argvars, rettv, VAR_STRING);
5316}
5317
5318/*
5319 * "libcallnr()" function
5320 */
5321 static void
5322f_libcallnr(typval_T *argvars, typval_T *rettv)
5323{
5324 libcall_common(argvars, rettv, VAR_NUMBER);
5325}
5326
5327/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005328 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005329 */
5330 static void
5331f_line(typval_T *argvars, typval_T *rettv)
5332{
5333 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005334 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005335 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005336 int id;
5337 tabpage_T *tp;
5338 win_T *wp;
5339 win_T *save_curwin;
5340 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005341
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005342 if (argvars[1].v_type != VAR_UNKNOWN)
5343 {
5344 // use window specified in the second argument
5345 id = (int)tv_get_number(&argvars[1]);
5346 wp = win_id2wp_tp(id, &tp);
5347 if (wp != NULL && tp != NULL)
5348 {
5349 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5350 == OK)
5351 {
5352 check_cursor();
5353 fp = var2fpos(&argvars[0], TRUE, &fnum);
5354 }
5355 restore_win_noblock(save_curwin, save_curtab, TRUE);
5356 }
5357 }
5358 else
5359 // use current window
5360 fp = var2fpos(&argvars[0], TRUE, &fnum);
5361
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005362 if (fp != NULL)
5363 lnum = fp->lnum;
5364 rettv->vval.v_number = lnum;
5365}
5366
5367/*
5368 * "line2byte(lnum)" function
5369 */
5370 static void
5371f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5372{
5373#ifndef FEAT_BYTEOFF
5374 rettv->vval.v_number = -1;
5375#else
5376 linenr_T lnum;
5377
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005378 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5380 rettv->vval.v_number = -1;
5381 else
5382 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5383 if (rettv->vval.v_number >= 0)
5384 ++rettv->vval.v_number;
5385#endif
5386}
5387
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005388#ifdef FEAT_FLOAT
5389/*
5390 * "log()" function
5391 */
5392 static void
5393f_log(typval_T *argvars, typval_T *rettv)
5394{
5395 float_T f = 0.0;
5396
5397 rettv->v_type = VAR_FLOAT;
5398 if (get_float_arg(argvars, &f) == OK)
5399 rettv->vval.v_float = log(f);
5400 else
5401 rettv->vval.v_float = 0.0;
5402}
5403
5404/*
5405 * "log10()" function
5406 */
5407 static void
5408f_log10(typval_T *argvars, typval_T *rettv)
5409{
5410 float_T f = 0.0;
5411
5412 rettv->v_type = VAR_FLOAT;
5413 if (get_float_arg(argvars, &f) == OK)
5414 rettv->vval.v_float = log10(f);
5415 else
5416 rettv->vval.v_float = 0.0;
5417}
5418#endif
5419
5420#ifdef FEAT_LUA
5421/*
5422 * "luaeval()" function
5423 */
5424 static void
5425f_luaeval(typval_T *argvars, typval_T *rettv)
5426{
5427 char_u *str;
5428 char_u buf[NUMBUFLEN];
5429
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005430 if (check_restricted() || check_secure())
5431 return;
5432
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005433 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005434 do_luaeval(str, argvars + 1, rettv);
5435}
5436#endif
5437
5438/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005439 * "maparg()" function
5440 */
5441 static void
5442f_maparg(typval_T *argvars, typval_T *rettv)
5443{
5444 get_maparg(argvars, rettv, TRUE);
5445}
5446
5447/*
5448 * "mapcheck()" function
5449 */
5450 static void
5451f_mapcheck(typval_T *argvars, typval_T *rettv)
5452{
5453 get_maparg(argvars, rettv, FALSE);
5454}
5455
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005456typedef enum
5457{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005458 MATCH_END, // matchend()
5459 MATCH_MATCH, // match()
5460 MATCH_STR, // matchstr()
5461 MATCH_LIST, // matchlist()
5462 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005463} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005464
5465 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005466find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005467{
5468 char_u *str = NULL;
5469 long len = 0;
5470 char_u *expr = NULL;
5471 char_u *pat;
5472 regmatch_T regmatch;
5473 char_u patbuf[NUMBUFLEN];
5474 char_u strbuf[NUMBUFLEN];
5475 char_u *save_cpo;
5476 long start = 0;
5477 long nth = 1;
5478 colnr_T startcol = 0;
5479 int match = 0;
5480 list_T *l = NULL;
5481 listitem_T *li = NULL;
5482 long idx = 0;
5483 char_u *tofree = NULL;
5484
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005485 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005486 save_cpo = p_cpo;
5487 p_cpo = (char_u *)"";
5488
5489 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005490 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005492 // type MATCH_LIST: return empty list when there are no matches.
5493 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005494 if (rettv_list_alloc(rettv) == FAIL)
5495 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005496 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005497 && (list_append_string(rettv->vval.v_list,
5498 (char_u *)"", 0) == FAIL
5499 || list_append_number(rettv->vval.v_list,
5500 (varnumber_T)-1) == FAIL
5501 || list_append_number(rettv->vval.v_list,
5502 (varnumber_T)-1) == FAIL
5503 || list_append_number(rettv->vval.v_list,
5504 (varnumber_T)-1) == FAIL))
5505 {
5506 list_free(rettv->vval.v_list);
5507 rettv->vval.v_list = NULL;
5508 goto theend;
5509 }
5510 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005511 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005512 {
5513 rettv->v_type = VAR_STRING;
5514 rettv->vval.v_string = NULL;
5515 }
5516
5517 if (argvars[0].v_type == VAR_LIST)
5518 {
5519 if ((l = argvars[0].vval.v_list) == NULL)
5520 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005521 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005522 li = l->lv_first;
5523 }
5524 else
5525 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005526 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005527 len = (long)STRLEN(str);
5528 }
5529
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005530 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005531 if (pat == NULL)
5532 goto theend;
5533
5534 if (argvars[2].v_type != VAR_UNKNOWN)
5535 {
5536 int error = FALSE;
5537
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005538 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005539 if (error)
5540 goto theend;
5541 if (l != NULL)
5542 {
5543 li = list_find(l, start);
5544 if (li == NULL)
5545 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005546 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005547 }
5548 else
5549 {
5550 if (start < 0)
5551 start = 0;
5552 if (start > len)
5553 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005554 // When "count" argument is there ignore matches before "start",
5555 // otherwise skip part of the string. Differs when pattern is "^"
5556 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005557 if (argvars[3].v_type != VAR_UNKNOWN)
5558 startcol = start;
5559 else
5560 {
5561 str += start;
5562 len -= start;
5563 }
5564 }
5565
5566 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005567 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005568 if (error)
5569 goto theend;
5570 }
5571
5572 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5573 if (regmatch.regprog != NULL)
5574 {
5575 regmatch.rm_ic = p_ic;
5576
5577 for (;;)
5578 {
5579 if (l != NULL)
5580 {
5581 if (li == NULL)
5582 {
5583 match = FALSE;
5584 break;
5585 }
5586 vim_free(tofree);
5587 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5588 if (str == NULL)
5589 break;
5590 }
5591
5592 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5593
5594 if (match && --nth <= 0)
5595 break;
5596 if (l == NULL && !match)
5597 break;
5598
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005599 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005600 if (l != NULL)
5601 {
5602 li = li->li_next;
5603 ++idx;
5604 }
5605 else
5606 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005607 startcol = (colnr_T)(regmatch.startp[0]
5608 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005609 if (startcol > (colnr_T)len
5610 || str + startcol <= regmatch.startp[0])
5611 {
5612 match = FALSE;
5613 break;
5614 }
5615 }
5616 }
5617
5618 if (match)
5619 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005620 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005621 {
5622 listitem_T *li1 = rettv->vval.v_list->lv_first;
5623 listitem_T *li2 = li1->li_next;
5624 listitem_T *li3 = li2->li_next;
5625 listitem_T *li4 = li3->li_next;
5626
5627 vim_free(li1->li_tv.vval.v_string);
5628 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005629 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630 li3->li_tv.vval.v_number =
5631 (varnumber_T)(regmatch.startp[0] - expr);
5632 li4->li_tv.vval.v_number =
5633 (varnumber_T)(regmatch.endp[0] - expr);
5634 if (l != NULL)
5635 li2->li_tv.vval.v_number = (varnumber_T)idx;
5636 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005637 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005638 {
5639 int i;
5640
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005641 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642 for (i = 0; i < NSUBEXP; ++i)
5643 {
5644 if (regmatch.endp[i] == NULL)
5645 {
5646 if (list_append_string(rettv->vval.v_list,
5647 (char_u *)"", 0) == FAIL)
5648 break;
5649 }
5650 else if (list_append_string(rettv->vval.v_list,
5651 regmatch.startp[i],
5652 (int)(regmatch.endp[i] - regmatch.startp[i]))
5653 == FAIL)
5654 break;
5655 }
5656 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005657 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005658 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005659 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005660 if (l != NULL)
5661 copy_tv(&li->li_tv, rettv);
5662 else
5663 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005664 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005665 }
5666 else if (l != NULL)
5667 rettv->vval.v_number = idx;
5668 else
5669 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005670 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671 rettv->vval.v_number =
5672 (varnumber_T)(regmatch.startp[0] - str);
5673 else
5674 rettv->vval.v_number =
5675 (varnumber_T)(regmatch.endp[0] - str);
5676 rettv->vval.v_number += (varnumber_T)(str - expr);
5677 }
5678 }
5679 vim_regfree(regmatch.regprog);
5680 }
5681
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005682theend:
5683 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005684 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685 listitem_remove(rettv->vval.v_list,
5686 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005687 vim_free(tofree);
5688 p_cpo = save_cpo;
5689}
5690
5691/*
5692 * "match()" function
5693 */
5694 static void
5695f_match(typval_T *argvars, typval_T *rettv)
5696{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005697 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005698}
5699
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005700/*
5701 * "matchend()" function
5702 */
5703 static void
5704f_matchend(typval_T *argvars, typval_T *rettv)
5705{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005706 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005707}
5708
5709/*
5710 * "matchlist()" function
5711 */
5712 static void
5713f_matchlist(typval_T *argvars, typval_T *rettv)
5714{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005715 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005716}
5717
5718/*
5719 * "matchstr()" function
5720 */
5721 static void
5722f_matchstr(typval_T *argvars, typval_T *rettv)
5723{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005724 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005725}
5726
5727/*
5728 * "matchstrpos()" function
5729 */
5730 static void
5731f_matchstrpos(typval_T *argvars, typval_T *rettv)
5732{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005733 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734}
5735
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005736 static void
5737max_min(typval_T *argvars, typval_T *rettv, int domax)
5738{
5739 varnumber_T n = 0;
5740 varnumber_T i;
5741 int error = FALSE;
5742
5743 if (argvars[0].v_type == VAR_LIST)
5744 {
5745 list_T *l;
5746 listitem_T *li;
5747
5748 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005749 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005750 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005751 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005752 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005753 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5754 n = l->lv_u.nonmat.lv_start;
5755 else
5756 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5757 * l->lv_u.nonmat.lv_stride;
5758 }
5759 else
5760 {
5761 li = l->lv_first;
5762 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005763 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005764 n = tv_get_number_chk(&li->li_tv, &error);
5765 for (;;)
5766 {
5767 li = li->li_next;
5768 if (li == NULL)
5769 break;
5770 i = tv_get_number_chk(&li->li_tv, &error);
5771 if (domax ? i > n : i < n)
5772 n = i;
5773 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005774 }
5775 }
5776 }
5777 }
5778 else if (argvars[0].v_type == VAR_DICT)
5779 {
5780 dict_T *d;
5781 int first = TRUE;
5782 hashitem_T *hi;
5783 int todo;
5784
5785 d = argvars[0].vval.v_dict;
5786 if (d != NULL)
5787 {
5788 todo = (int)d->dv_hashtab.ht_used;
5789 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5790 {
5791 if (!HASHITEM_EMPTY(hi))
5792 {
5793 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005794 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005795 if (first)
5796 {
5797 n = i;
5798 first = FALSE;
5799 }
5800 else if (domax ? i > n : i < n)
5801 n = i;
5802 }
5803 }
5804 }
5805 }
5806 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005807 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808 rettv->vval.v_number = error ? 0 : n;
5809}
5810
5811/*
5812 * "max()" function
5813 */
5814 static void
5815f_max(typval_T *argvars, typval_T *rettv)
5816{
5817 max_min(argvars, rettv, TRUE);
5818}
5819
5820/*
5821 * "min()" function
5822 */
5823 static void
5824f_min(typval_T *argvars, typval_T *rettv)
5825{
5826 max_min(argvars, rettv, FALSE);
5827}
5828
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829#if defined(FEAT_MZSCHEME) || defined(PROTO)
5830/*
5831 * "mzeval()" function
5832 */
5833 static void
5834f_mzeval(typval_T *argvars, typval_T *rettv)
5835{
5836 char_u *str;
5837 char_u buf[NUMBUFLEN];
5838
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005839 if (check_restricted() || check_secure())
5840 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005841 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005842 do_mzeval(str, rettv);
5843}
5844
5845 void
5846mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5847{
5848 typval_T argvars[3];
5849
5850 argvars[0].v_type = VAR_STRING;
5851 argvars[0].vval.v_string = name;
5852 copy_tv(args, &argvars[1]);
5853 argvars[2].v_type = VAR_UNKNOWN;
5854 f_call(argvars, rettv);
5855 clear_tv(&argvars[1]);
5856}
5857#endif
5858
5859/*
5860 * "nextnonblank()" function
5861 */
5862 static void
5863f_nextnonblank(typval_T *argvars, typval_T *rettv)
5864{
5865 linenr_T lnum;
5866
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005867 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 {
5869 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5870 {
5871 lnum = 0;
5872 break;
5873 }
5874 if (*skipwhite(ml_get(lnum)) != NUL)
5875 break;
5876 }
5877 rettv->vval.v_number = lnum;
5878}
5879
5880/*
5881 * "nr2char()" function
5882 */
5883 static void
5884f_nr2char(typval_T *argvars, typval_T *rettv)
5885{
5886 char_u buf[NUMBUFLEN];
5887
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005888 if (has_mbyte)
5889 {
5890 int utf8 = 0;
5891
5892 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaared6a4302020-09-05 20:29:41 +02005893 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005894 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005895 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005896 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005897 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005898 }
5899 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005901 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005902 buf[1] = NUL;
5903 }
5904 rettv->v_type = VAR_STRING;
5905 rettv->vval.v_string = vim_strsave(buf);
5906}
5907
5908/*
5909 * "or(expr, expr)" function
5910 */
5911 static void
5912f_or(typval_T *argvars, typval_T *rettv)
5913{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005914 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5915 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005916}
5917
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005918#ifdef FEAT_PERL
5919/*
5920 * "perleval()" function
5921 */
5922 static void
5923f_perleval(typval_T *argvars, typval_T *rettv)
5924{
5925 char_u *str;
5926 char_u buf[NUMBUFLEN];
5927
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005928 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005929 do_perleval(str, rettv);
5930}
5931#endif
5932
5933#ifdef FEAT_FLOAT
5934/*
5935 * "pow()" function
5936 */
5937 static void
5938f_pow(typval_T *argvars, typval_T *rettv)
5939{
5940 float_T fx = 0.0, fy = 0.0;
5941
5942 rettv->v_type = VAR_FLOAT;
5943 if (get_float_arg(argvars, &fx) == OK
5944 && get_float_arg(&argvars[1], &fy) == OK)
5945 rettv->vval.v_float = pow(fx, fy);
5946 else
5947 rettv->vval.v_float = 0.0;
5948}
5949#endif
5950
5951/*
5952 * "prevnonblank()" function
5953 */
5954 static void
5955f_prevnonblank(typval_T *argvars, typval_T *rettv)
5956{
5957 linenr_T lnum;
5958
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005959 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005960 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5961 lnum = 0;
5962 else
5963 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5964 --lnum;
5965 rettv->vval.v_number = lnum;
5966}
5967
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005968// This dummy va_list is here because:
5969// - passing a NULL pointer doesn't work when va_list isn't a pointer
5970// - locally in the function results in a "used before set" warning
5971// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972static va_list ap;
5973
5974/*
5975 * "printf()" function
5976 */
5977 static void
5978f_printf(typval_T *argvars, typval_T *rettv)
5979{
5980 char_u buf[NUMBUFLEN];
5981 int len;
5982 char_u *s;
5983 int saved_did_emsg = did_emsg;
5984 char *fmt;
5985
5986 rettv->v_type = VAR_STRING;
5987 rettv->vval.v_string = NULL;
5988
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005989 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005990 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005991 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005992 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005993 if (!did_emsg)
5994 {
5995 s = alloc(len + 1);
5996 if (s != NULL)
5997 {
5998 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005999 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
6000 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006001 }
6002 }
6003 did_emsg |= saved_did_emsg;
6004}
6005
6006/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006007 * "pum_getpos()" function
6008 */
6009 static void
6010f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6011{
6012 if (rettv_dict_alloc(rettv) != OK)
6013 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006014 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006015}
6016
6017/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 * "pumvisible()" function
6019 */
6020 static void
6021f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6022{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 if (pum_visible())
6024 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006025}
6026
6027#ifdef FEAT_PYTHON3
6028/*
6029 * "py3eval()" function
6030 */
6031 static void
6032f_py3eval(typval_T *argvars, typval_T *rettv)
6033{
6034 char_u *str;
6035 char_u buf[NUMBUFLEN];
6036
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006037 if (check_restricted() || check_secure())
6038 return;
6039
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006040 if (p_pyx == 0)
6041 p_pyx = 3;
6042
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006043 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006044 do_py3eval(str, rettv);
6045}
6046#endif
6047
6048#ifdef FEAT_PYTHON
6049/*
6050 * "pyeval()" function
6051 */
6052 static void
6053f_pyeval(typval_T *argvars, typval_T *rettv)
6054{
6055 char_u *str;
6056 char_u buf[NUMBUFLEN];
6057
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006058 if (check_restricted() || check_secure())
6059 return;
6060
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006061 if (p_pyx == 0)
6062 p_pyx = 2;
6063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006064 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065 do_pyeval(str, rettv);
6066}
6067#endif
6068
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006069#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
6070/*
6071 * "pyxeval()" function
6072 */
6073 static void
6074f_pyxeval(typval_T *argvars, typval_T *rettv)
6075{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006076 if (check_restricted() || check_secure())
6077 return;
6078
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006079# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
6080 init_pyxversion();
6081 if (p_pyx == 2)
6082 f_pyeval(argvars, rettv);
6083 else
6084 f_py3eval(argvars, rettv);
6085# elif defined(FEAT_PYTHON)
6086 f_pyeval(argvars, rettv);
6087# elif defined(FEAT_PYTHON3)
6088 f_py3eval(argvars, rettv);
6089# endif
6090}
6091#endif
6092
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006093static UINT32_T srand_seed_for_testing = 0;
6094static int srand_seed_for_testing_is_used = FALSE;
6095
6096 static void
6097f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
6098{
6099 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006100 srand_seed_for_testing_is_used = FALSE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006101 else
6102 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006103 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
6104 srand_seed_for_testing_is_used = TRUE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006105 }
6106}
6107
6108 static void
6109init_srand(UINT32_T *x)
6110{
6111#ifndef MSWIN
6112 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6113#endif
6114
6115 if (srand_seed_for_testing_is_used)
6116 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006117 *x = srand_seed_for_testing;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006118 return;
6119 }
6120#ifndef MSWIN
6121 if (dev_urandom_state != FAIL)
6122 {
6123 int fd = open("/dev/urandom", O_RDONLY);
6124 struct {
6125 union {
6126 UINT32_T number;
6127 char bytes[sizeof(UINT32_T)];
6128 } contents;
6129 } buf;
6130
6131 // Attempt reading /dev/urandom.
6132 if (fd == -1)
6133 dev_urandom_state = FAIL;
6134 else
6135 {
6136 buf.contents.number = 0;
6137 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6138 != sizeof(UINT32_T))
6139 dev_urandom_state = FAIL;
6140 else
6141 {
6142 dev_urandom_state = OK;
6143 *x = buf.contents.number;
6144 }
6145 close(fd);
6146 }
6147 }
6148 if (dev_urandom_state != OK)
6149 // Reading /dev/urandom doesn't work, fall back to time().
6150#endif
6151 *x = vim_time();
6152}
6153
6154#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6155#define SPLITMIX32(x, z) ( \
6156 z = (x += 0x9e3779b9), \
6157 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6158 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6159 z ^ (z >> 16) \
6160 )
6161#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6162 result = ROTL(y * 5, 7) * 9; \
6163 t = y << 9; \
6164 z ^= x; \
6165 w ^= y; \
6166 y ^= z, x ^= w; \
6167 z ^= t; \
6168 w = ROTL(w, 11);
6169
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006170/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006171 * "rand()" function
6172 */
6173 static void
6174f_rand(typval_T *argvars, typval_T *rettv)
6175{
6176 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006177 static UINT32_T gx, gy, gz, gw;
6178 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006179 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006180 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006181
6182 if (argvars[0].v_type == VAR_UNKNOWN)
6183 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006184 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006185 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006186 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006187 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006188 init_srand(&x);
6189
6190 gx = SPLITMIX32(x, z);
6191 gy = SPLITMIX32(x, z);
6192 gz = SPLITMIX32(x, z);
6193 gw = SPLITMIX32(x, z);
6194 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006195 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006196
6197 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006198 }
6199 else if (argvars[0].v_type == VAR_LIST)
6200 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006201 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006202 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006203 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006204
6205 lx = list_find(l, 0L);
6206 ly = list_find(l, 1L);
6207 lz = list_find(l, 2L);
6208 lw = list_find(l, 3L);
6209 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6210 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6211 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6212 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6213 x = (UINT32_T)lx->li_tv.vval.v_number;
6214 y = (UINT32_T)ly->li_tv.vval.v_number;
6215 z = (UINT32_T)lz->li_tv.vval.v_number;
6216 w = (UINT32_T)lw->li_tv.vval.v_number;
6217
6218 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6219
6220 lx->li_tv.vval.v_number = (varnumber_T)x;
6221 ly->li_tv.vval.v_number = (varnumber_T)y;
6222 lz->li_tv.vval.v_number = (varnumber_T)z;
6223 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006224 }
6225 else
6226 goto theend;
6227
6228 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006229 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006230 return;
6231
6232theend:
6233 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006234 rettv->v_type = VAR_NUMBER;
6235 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006236}
6237
6238/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006239 * "srand()" function
6240 */
6241 static void
6242f_srand(typval_T *argvars, typval_T *rettv)
6243{
6244 UINT32_T x = 0, z;
6245
6246 if (rettv_list_alloc(rettv) == FAIL)
6247 return;
6248 if (argvars[0].v_type == VAR_UNKNOWN)
6249 {
6250 init_srand(&x);
6251 }
6252 else
6253 {
6254 int error = FALSE;
6255
6256 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6257 if (error)
6258 return;
6259 }
6260
6261 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6262 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6263 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6264 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6265}
6266
6267#undef ROTL
6268#undef SPLITMIX32
6269#undef SHUFFLE_XOSHIRO128STARSTAR
6270
6271/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 * "range()" function
6273 */
6274 static void
6275f_range(typval_T *argvars, typval_T *rettv)
6276{
6277 varnumber_T start;
6278 varnumber_T end;
6279 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006280 int error = FALSE;
6281
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006282 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283 if (argvars[1].v_type == VAR_UNKNOWN)
6284 {
6285 end = start - 1;
6286 start = 0;
6287 }
6288 else
6289 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006290 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006292 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293 }
6294
6295 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006296 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006298 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006299 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006300 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006301 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006302 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006303 list_T *list = rettv->vval.v_list;
6304
6305 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006306 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006307 // be called.
6308 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006309 list->lv_u.nonmat.lv_start = start;
6310 list->lv_u.nonmat.lv_end = end;
6311 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006312 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006313 }
6314}
6315
6316/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006317 * Materialize "list".
6318 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006319 */
6320 void
6321range_list_materialize(list_T *list)
6322{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006323 varnumber_T start = list->lv_u.nonmat.lv_start;
6324 varnumber_T end = list->lv_u.nonmat.lv_end;
6325 int stride = list->lv_u.nonmat.lv_stride;
6326 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006327
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006328 list->lv_first = NULL;
6329 list->lv_u.mat.lv_last = NULL;
6330 list->lv_len = 0;
6331 list->lv_u.mat.lv_idx_item = NULL;
6332 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6333 if (list_append_number(list, (varnumber_T)i) == FAIL)
6334 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335}
6336
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006337/*
6338 * "getreginfo()" function
6339 */
6340 static void
6341f_getreginfo(typval_T *argvars, typval_T *rettv)
6342{
6343 char_u *strregname;
6344 int regname;
6345 char_u buf[NUMBUFLEN + 2];
6346 long reglen = 0;
6347 dict_T *dict;
6348 list_T *list;
6349
6350 if (argvars[0].v_type != VAR_UNKNOWN)
6351 {
6352 strregname = tv_get_string_chk(&argvars[0]);
6353 if (strregname == NULL)
6354 return;
6355 }
6356 else
6357 strregname = get_vim_var_str(VV_REG);
6358
6359 regname = (strregname == NULL ? '"' : *strregname);
6360 if (regname == 0 || regname == '@')
6361 regname = '"';
6362
6363 if (rettv_dict_alloc(rettv) == FAIL)
6364 return;
6365 dict = rettv->vval.v_dict;
6366
6367 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
6368 if (list == NULL)
6369 return;
Bram Moolenaar91639192020-06-29 19:55:58 +02006370 (void)dict_add_list(dict, "regcontents", list);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006371
6372 buf[0] = NUL;
6373 buf[1] = NUL;
6374 switch (get_reg_type(regname, &reglen))
6375 {
6376 case MLINE: buf[0] = 'V'; break;
6377 case MCHAR: buf[0] = 'v'; break;
6378 case MBLOCK:
6379 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
6380 reglen + 1);
6381 break;
6382 }
Bram Moolenaar91639192020-06-29 19:55:58 +02006383 (void)dict_add_string(dict, (char *)"regtype", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006384
6385 buf[0] = get_register_name(get_unname_register());
6386 buf[1] = NUL;
6387 if (regname == '"')
Bram Moolenaar91639192020-06-29 19:55:58 +02006388 (void)dict_add_string(dict, (char *)"points_to", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006389 else
6390 {
6391 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
6392
6393 if (item != NULL)
6394 {
6395 item->di_tv.v_type = VAR_SPECIAL;
6396 item->di_tv.vval.v_number = regname == buf[0]
6397 ? VVAL_TRUE : VVAL_FALSE;
Bram Moolenaar91639192020-06-29 19:55:58 +02006398 (void)dict_add(dict, item);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006399 }
6400 }
6401}
6402
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006403 static void
6404return_register(int regname, typval_T *rettv)
6405{
6406 char_u buf[2] = {0, 0};
6407
6408 buf[0] = (char_u)regname;
6409 rettv->v_type = VAR_STRING;
6410 rettv->vval.v_string = vim_strsave(buf);
6411}
6412
6413/*
6414 * "reg_executing()" function
6415 */
6416 static void
6417f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6418{
6419 return_register(reg_executing, rettv);
6420}
6421
6422/*
6423 * "reg_recording()" function
6424 */
6425 static void
6426f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6427{
6428 return_register(reg_recording, rettv);
6429}
6430
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006431/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006432 * "rename({from}, {to})" function
6433 */
6434 static void
6435f_rename(typval_T *argvars, typval_T *rettv)
6436{
6437 char_u buf[NUMBUFLEN];
6438
6439 if (check_restricted() || check_secure())
6440 rettv->vval.v_number = -1;
6441 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006442 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6443 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006444}
6445
6446/*
6447 * "repeat()" function
6448 */
6449 static void
6450f_repeat(typval_T *argvars, typval_T *rettv)
6451{
6452 char_u *p;
6453 int n;
6454 int slen;
6455 int len;
6456 char_u *r;
6457 int i;
6458
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006459 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006460 if (argvars[0].v_type == VAR_LIST)
6461 {
6462 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6463 while (n-- > 0)
6464 if (list_extend(rettv->vval.v_list,
6465 argvars[0].vval.v_list, NULL) == FAIL)
6466 break;
6467 }
6468 else
6469 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006470 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006471 rettv->v_type = VAR_STRING;
6472 rettv->vval.v_string = NULL;
6473
6474 slen = (int)STRLEN(p);
6475 len = slen * n;
6476 if (len <= 0)
6477 return;
6478
6479 r = alloc(len + 1);
6480 if (r != NULL)
6481 {
6482 for (i = 0; i < n; i++)
6483 mch_memmove(r + i * slen, p, (size_t)slen);
6484 r[len] = NUL;
6485 }
6486
6487 rettv->vval.v_string = r;
6488 }
6489}
6490
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006491#define SP_NOMOVE 0x01 // don't move cursor
6492#define SP_REPEAT 0x02 // repeat to find outer pair
6493#define SP_RETCOUNT 0x04 // return matchcount
6494#define SP_SETPCMARK 0x08 // set previous context mark
6495#define SP_START 0x10 // accept match at start position
6496#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6497#define SP_END 0x40 // leave cursor at end of match
6498#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500/*
6501 * Get flags for a search function.
6502 * Possibly sets "p_ws".
6503 * Returns BACKWARD, FORWARD or zero (for an error).
6504 */
6505 static int
6506get_search_arg(typval_T *varp, int *flagsp)
6507{
6508 int dir = FORWARD;
6509 char_u *flags;
6510 char_u nbuf[NUMBUFLEN];
6511 int mask;
6512
6513 if (varp->v_type != VAR_UNKNOWN)
6514 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006515 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006516 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006517 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006518 while (*flags != NUL)
6519 {
6520 switch (*flags)
6521 {
6522 case 'b': dir = BACKWARD; break;
6523 case 'w': p_ws = TRUE; break;
6524 case 'W': p_ws = FALSE; break;
6525 default: mask = 0;
6526 if (flagsp != NULL)
6527 switch (*flags)
6528 {
6529 case 'c': mask = SP_START; break;
6530 case 'e': mask = SP_END; break;
6531 case 'm': mask = SP_RETCOUNT; break;
6532 case 'n': mask = SP_NOMOVE; break;
6533 case 'p': mask = SP_SUBPAT; break;
6534 case 'r': mask = SP_REPEAT; break;
6535 case 's': mask = SP_SETPCMARK; break;
6536 case 'z': mask = SP_COLUMN; break;
6537 }
6538 if (mask == 0)
6539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006540 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006541 dir = 0;
6542 }
6543 else
6544 *flagsp |= mask;
6545 }
6546 if (dir == 0)
6547 break;
6548 ++flags;
6549 }
6550 }
6551 return dir;
6552}
6553
6554/*
6555 * Shared by search() and searchpos() functions.
6556 */
6557 static int
6558search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6559{
6560 int flags;
6561 char_u *pat;
6562 pos_T pos;
6563 pos_T save_cursor;
6564 int save_p_ws = p_ws;
6565 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006566 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006567 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006569 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 long time_limit = 0;
6571#endif
6572 int options = SEARCH_KEEP;
6573 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006574 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006575 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006576 pos_T firstpos;
6577
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006578 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006579 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006580 if (dir == 0)
6581 goto theend;
6582 flags = *flagsp;
6583 if (flags & SP_START)
6584 options |= SEARCH_START;
6585 if (flags & SP_END)
6586 options |= SEARCH_END;
6587 if (flags & SP_COLUMN)
6588 options |= SEARCH_COL;
6589
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006590 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006591 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6592 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006593 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594 if (lnum_stop < 0)
6595 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006596 if (argvars[3].v_type != VAR_UNKNOWN)
6597 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006598#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006599 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600 if (time_limit < 0)
6601 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02006603 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006604 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006605 }
6606
6607#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006608 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006609 profile_setlimit(time_limit, &tm);
6610#endif
6611
6612 /*
6613 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6614 * Check to make sure only those flags are set.
6615 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6616 * flags cannot be set. Check for that condition also.
6617 */
6618 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6619 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6620 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006621 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006622 goto theend;
6623 }
6624
6625 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006626 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02006627 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006628 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6629#ifdef FEAT_RELTIME
6630 sia.sa_tm = &tm;
6631#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006632
6633 // Repeat until {skip} returns FALSE.
6634 for (;;)
6635 {
6636 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006637 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006638 // finding the first match again means there is no match where {skip}
6639 // evaluates to zero.
6640 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
6641 subpatnum = FAIL;
6642
Bram Moolenaara9c01042020-06-07 14:50:50 +02006643 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006644 // didn't find it or no skip argument
6645 break;
6646 firstpos = pos;
6647
Bram Moolenaara9c01042020-06-07 14:50:50 +02006648 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006649 {
6650 int do_skip;
6651 int err;
6652 pos_T save_pos = curwin->w_cursor;
6653
6654 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006655 err = FALSE;
6656 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006657 curwin->w_cursor = save_pos;
6658 if (err)
6659 {
6660 // Evaluating {skip} caused an error, break here.
6661 subpatnum = FAIL;
6662 break;
6663 }
6664 if (!do_skip)
6665 break;
6666 }
6667 }
6668
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006669 if (subpatnum != FAIL)
6670 {
6671 if (flags & SP_SUBPAT)
6672 retval = subpatnum;
6673 else
6674 retval = pos.lnum;
6675 if (flags & SP_SETPCMARK)
6676 setpcmark();
6677 curwin->w_cursor = pos;
6678 if (match_pos != NULL)
6679 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006680 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006681 match_pos->lnum = pos.lnum;
6682 match_pos->col = pos.col + 1;
6683 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006684 // "/$" will put the cursor after the end of the line, may need to
6685 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686 check_cursor();
6687 }
6688
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006689 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690 if (flags & SP_NOMOVE)
6691 curwin->w_cursor = save_cursor;
6692 else
6693 curwin->w_set_curswant = TRUE;
6694theend:
6695 p_ws = save_p_ws;
6696
6697 return retval;
6698}
6699
6700#ifdef FEAT_FLOAT
6701
6702/*
6703 * round() is not in C90, use ceil() or floor() instead.
6704 */
6705 float_T
6706vim_round(float_T f)
6707{
6708 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6709}
6710
6711/*
6712 * "round({float})" function
6713 */
6714 static void
6715f_round(typval_T *argvars, typval_T *rettv)
6716{
6717 float_T f = 0.0;
6718
6719 rettv->v_type = VAR_FLOAT;
6720 if (get_float_arg(argvars, &f) == OK)
6721 rettv->vval.v_float = vim_round(f);
6722 else
6723 rettv->vval.v_float = 0.0;
6724}
6725#endif
6726
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006727#ifdef FEAT_RUBY
6728/*
6729 * "rubyeval()" function
6730 */
6731 static void
6732f_rubyeval(typval_T *argvars, typval_T *rettv)
6733{
6734 char_u *str;
6735 char_u buf[NUMBUFLEN];
6736
6737 str = tv_get_string_buf(&argvars[0], buf);
6738 do_rubyeval(str, rettv);
6739}
6740#endif
6741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742/*
6743 * "screenattr()" function
6744 */
6745 static void
6746f_screenattr(typval_T *argvars, typval_T *rettv)
6747{
6748 int row;
6749 int col;
6750 int c;
6751
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006752 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6753 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006754 if (row < 0 || row >= screen_Rows
6755 || col < 0 || col >= screen_Columns)
6756 c = -1;
6757 else
6758 c = ScreenAttrs[LineOffset[row] + col];
6759 rettv->vval.v_number = c;
6760}
6761
6762/*
6763 * "screenchar()" function
6764 */
6765 static void
6766f_screenchar(typval_T *argvars, typval_T *rettv)
6767{
6768 int row;
6769 int col;
6770 int off;
6771 int c;
6772
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006773 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6774 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006775 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776 c = -1;
6777 else
6778 {
6779 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006780 if (enc_utf8 && ScreenLinesUC[off] != 0)
6781 c = ScreenLinesUC[off];
6782 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006783 c = ScreenLines[off];
6784 }
6785 rettv->vval.v_number = c;
6786}
6787
6788/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006789 * "screenchars()" function
6790 */
6791 static void
6792f_screenchars(typval_T *argvars, typval_T *rettv)
6793{
6794 int row;
6795 int col;
6796 int off;
6797 int c;
6798 int i;
6799
6800 if (rettv_list_alloc(rettv) == FAIL)
6801 return;
6802 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6803 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6804 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6805 return;
6806
6807 off = LineOffset[row] + col;
6808 if (enc_utf8 && ScreenLinesUC[off] != 0)
6809 c = ScreenLinesUC[off];
6810 else
6811 c = ScreenLines[off];
6812 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6813
6814 if (enc_utf8)
6815
6816 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6817 list_append_number(rettv->vval.v_list,
6818 (varnumber_T)ScreenLinesC[i][off]);
6819}
6820
6821/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006822 * "screencol()" function
6823 *
6824 * First column is 1 to be consistent with virtcol().
6825 */
6826 static void
6827f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6828{
6829 rettv->vval.v_number = screen_screencol() + 1;
6830}
6831
6832/*
6833 * "screenrow()" function
6834 */
6835 static void
6836f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6837{
6838 rettv->vval.v_number = screen_screenrow() + 1;
6839}
6840
6841/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006842 * "screenstring()" function
6843 */
6844 static void
6845f_screenstring(typval_T *argvars, typval_T *rettv)
6846{
6847 int row;
6848 int col;
6849 int off;
6850 int c;
6851 int i;
6852 char_u buf[MB_MAXBYTES + 1];
6853 int buflen = 0;
6854
6855 rettv->vval.v_string = NULL;
6856 rettv->v_type = VAR_STRING;
6857
6858 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6859 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6860 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6861 return;
6862
6863 off = LineOffset[row] + col;
6864 if (enc_utf8 && ScreenLinesUC[off] != 0)
6865 c = ScreenLinesUC[off];
6866 else
6867 c = ScreenLines[off];
6868 buflen += mb_char2bytes(c, buf);
6869
6870 if (enc_utf8)
6871 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6872 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6873
6874 buf[buflen] = NUL;
6875 rettv->vval.v_string = vim_strsave(buf);
6876}
6877
6878/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879 * "search()" function
6880 */
6881 static void
6882f_search(typval_T *argvars, typval_T *rettv)
6883{
6884 int flags = 0;
6885
6886 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6887}
6888
6889/*
6890 * "searchdecl()" function
6891 */
6892 static void
6893f_searchdecl(typval_T *argvars, typval_T *rettv)
6894{
Bram Moolenaar30788d32020-09-05 21:35:16 +02006895 int locally = TRUE;
6896 int thisblock = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006897 int error = FALSE;
6898 char_u *name;
6899
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006900 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006901
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006902 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006903 if (argvars[1].v_type != VAR_UNKNOWN)
6904 {
Bram Moolenaar30788d32020-09-05 21:35:16 +02006905 locally = !(int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar30788d32020-09-05 21:35:16 +02006907 thisblock = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 }
6909 if (!error && name != NULL)
6910 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6911 locally, thisblock, SEARCH_KEEP) == FAIL;
6912}
6913
6914/*
6915 * Used by searchpair() and searchpairpos()
6916 */
6917 static int
6918searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6919{
6920 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006921 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922 int save_p_ws = p_ws;
6923 int dir;
6924 int flags = 0;
6925 char_u nbuf1[NUMBUFLEN];
6926 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006927 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006928 long lnum_stop = 0;
6929 long time_limit = 0;
6930
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006931 // Get the three pattern arguments: start, middle, end. Will result in an
6932 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006933 spat = tv_get_string_chk(&argvars[0]);
6934 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6935 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006937 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006938
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006939 // Handle the optional fourth argument: flags
6940 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006941 if (dir == 0)
6942 goto theend;
6943
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006944 // Don't accept SP_END or SP_SUBPAT.
6945 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006946 if ((flags & (SP_END | SP_SUBPAT)) != 0
6947 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6948 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006949 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950 goto theend;
6951 }
6952
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006953 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954 if (flags & SP_REPEAT)
6955 p_ws = FALSE;
6956
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006957 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006958 if (argvars[3].v_type == VAR_UNKNOWN
6959 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006960 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961 else
6962 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02006963 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01006964 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02006965
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 if (argvars[5].v_type != VAR_UNKNOWN)
6967 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006968 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006969 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006970 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006971 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006972 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006973 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974#ifdef FEAT_RELTIME
6975 if (argvars[6].v_type != VAR_UNKNOWN)
6976 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006977 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006978 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006979 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006980 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006982 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006983 }
6984#endif
6985 }
6986 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006987
6988 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6989 match_pos, lnum_stop, time_limit);
6990
6991theend:
6992 p_ws = save_p_ws;
6993
6994 return retval;
6995}
6996
6997/*
6998 * "searchpair()" function
6999 */
7000 static void
7001f_searchpair(typval_T *argvars, typval_T *rettv)
7002{
7003 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
7004}
7005
7006/*
7007 * "searchpairpos()" function
7008 */
7009 static void
7010f_searchpairpos(typval_T *argvars, typval_T *rettv)
7011{
7012 pos_T match_pos;
7013 int lnum = 0;
7014 int col = 0;
7015
7016 if (rettv_list_alloc(rettv) == FAIL)
7017 return;
7018
7019 if (searchpair_cmn(argvars, &match_pos) > 0)
7020 {
7021 lnum = match_pos.lnum;
7022 col = match_pos.col;
7023 }
7024
7025 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7026 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7027}
7028
7029/*
7030 * Search for a start/middle/end thing.
7031 * Used by searchpair(), see its documentation for the details.
7032 * Returns 0 or -1 for no match,
7033 */
7034 long
7035do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007036 char_u *spat, // start pattern
7037 char_u *mpat, // middle pattern
7038 char_u *epat, // end pattern
7039 int dir, // BACKWARD or FORWARD
7040 typval_T *skip, // skip expression
7041 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007042 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007043 linenr_T lnum_stop, // stop at this line if not zero
7044 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007045{
7046 char_u *save_cpo;
7047 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7048 long retval = 0;
7049 pos_T pos;
7050 pos_T firstpos;
7051 pos_T foundpos;
7052 pos_T save_cursor;
7053 pos_T save_pos;
7054 int n;
7055 int r;
7056 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007057 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007058 int err;
7059 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007060#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007061 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007062#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007064 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007065 save_cpo = p_cpo;
7066 p_cpo = empty_option;
7067
7068#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007069 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007070 profile_setlimit(time_limit, &tm);
7071#endif
7072
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007073 // Make two search patterns: start/end (pat2, for in nested pairs) and
7074 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02007075 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7076 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007077 if (pat2 == NULL || pat3 == NULL)
7078 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007079 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 if (*mpat == NUL)
7081 STRCPY(pat3, pat2);
7082 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007083 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007084 spat, epat, mpat);
7085 if (flags & SP_START)
7086 options |= SEARCH_START;
7087
Bram Moolenaar48570482017-10-30 21:48:41 +01007088 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02007089 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01007090
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007091 save_cursor = curwin->w_cursor;
7092 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007093 CLEAR_POS(&firstpos);
7094 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007095 pat = pat3;
7096 for (;;)
7097 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007098 searchit_arg_T sia;
7099
Bram Moolenaara80faa82020-04-12 19:37:17 +02007100 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007101 sia.sa_stop_lnum = lnum_stop;
7102#ifdef FEAT_RELTIME
7103 sia.sa_tm = &tm;
7104#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007105 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007106 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007107 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007108 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007109 break;
7110
7111 if (firstpos.lnum == 0)
7112 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007113 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007114 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007115 // Found the same position again. Can happen with a pattern that
7116 // has "\zs" at the end and searching backwards. Advance one
7117 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 if (dir == BACKWARD)
7119 decl(&pos);
7120 else
7121 incl(&pos);
7122 }
7123 foundpos = pos;
7124
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007125 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007126 options &= ~SEARCH_START;
7127
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007128 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007129 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007130 {
7131 save_pos = curwin->w_cursor;
7132 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007133 err = FALSE;
7134 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 curwin->w_cursor = save_pos;
7136 if (err)
7137 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007138 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007139 curwin->w_cursor = save_cursor;
7140 retval = -1;
7141 break;
7142 }
7143 if (r)
7144 continue;
7145 }
7146
7147 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7148 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007149 // Found end when searching backwards or start when searching
7150 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007151 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007152 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007153 }
7154 else
7155 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007156 // Found end when searching forward or start when searching
7157 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007158 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007159 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160 }
7161
7162 if (nest == 0)
7163 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007164 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007165 if (flags & SP_RETCOUNT)
7166 ++retval;
7167 else
7168 retval = pos.lnum;
7169 if (flags & SP_SETPCMARK)
7170 setpcmark();
7171 curwin->w_cursor = pos;
7172 if (!(flags & SP_REPEAT))
7173 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007174 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007175 }
7176 }
7177
7178 if (match_pos != NULL)
7179 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007180 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007181 match_pos->lnum = curwin->w_cursor.lnum;
7182 match_pos->col = curwin->w_cursor.col + 1;
7183 }
7184
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007185 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007186 if ((flags & SP_NOMOVE) || retval == 0)
7187 curwin->w_cursor = save_cursor;
7188
7189theend:
7190 vim_free(pat2);
7191 vim_free(pat3);
7192 if (p_cpo == empty_option)
7193 p_cpo = save_cpo;
7194 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007195 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007196 free_string_option(save_cpo);
7197
7198 return retval;
7199}
7200
7201/*
7202 * "searchpos()" function
7203 */
7204 static void
7205f_searchpos(typval_T *argvars, typval_T *rettv)
7206{
7207 pos_T match_pos;
7208 int lnum = 0;
7209 int col = 0;
7210 int n;
7211 int flags = 0;
7212
7213 if (rettv_list_alloc(rettv) == FAIL)
7214 return;
7215
7216 n = search_cmn(argvars, &match_pos, &flags);
7217 if (n > 0)
7218 {
7219 lnum = match_pos.lnum;
7220 col = match_pos.col;
7221 }
7222
7223 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7224 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7225 if (flags & SP_SUBPAT)
7226 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7227}
7228
7229 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7231{
7232 dict_T *d;
7233 dictitem_T *di;
7234 char_u *csearch;
7235
7236 if (argvars[0].v_type != VAR_DICT)
7237 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007238 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007239 return;
7240 }
7241
7242 if ((d = argvars[0].vval.v_dict) != NULL)
7243 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007244 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007245 if (csearch != NULL)
7246 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247 if (enc_utf8)
7248 {
7249 int pcc[MAX_MCO];
7250 int c = utfc_ptr2char(csearch, pcc);
7251
7252 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7253 }
7254 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007256 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007257 }
7258
7259 di = dict_find(d, (char_u *)"forward", -1);
7260 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007261 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007262 ? FORWARD : BACKWARD);
7263
7264 di = dict_find(d, (char_u *)"until", -1);
7265 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007266 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 }
7268}
7269
7270/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007271 * "setenv()" function
7272 */
7273 static void
7274f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7275{
7276 char_u namebuf[NUMBUFLEN];
7277 char_u valbuf[NUMBUFLEN];
7278 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7279
7280 if (argvars[1].v_type == VAR_SPECIAL
7281 && argvars[1].vval.v_number == VVAL_NULL)
7282 vim_unsetenv(name);
7283 else
7284 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7285}
7286
7287/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 * "setfperm({fname}, {mode})" function
7289 */
7290 static void
7291f_setfperm(typval_T *argvars, typval_T *rettv)
7292{
7293 char_u *fname;
7294 char_u modebuf[NUMBUFLEN];
7295 char_u *mode_str;
7296 int i;
7297 int mask;
7298 int mode = 0;
7299
7300 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007301 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007302 if (fname == NULL)
7303 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007304 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007305 if (mode_str == NULL)
7306 return;
7307 if (STRLEN(mode_str) != 9)
7308 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007309 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007310 return;
7311 }
7312
7313 mask = 1;
7314 for (i = 8; i >= 0; --i)
7315 {
7316 if (mode_str[i] != '-')
7317 mode |= mask;
7318 mask = mask << 1;
7319 }
7320 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7321}
7322
7323/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324 * "setpos()" function
7325 */
7326 static void
7327f_setpos(typval_T *argvars, typval_T *rettv)
7328{
7329 pos_T pos;
7330 int fnum;
7331 char_u *name;
7332 colnr_T curswant = -1;
7333
7334 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007335 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336 if (name != NULL)
7337 {
7338 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7339 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007340 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007341 pos.col = 0;
7342 if (name[0] == '.' && name[1] == NUL)
7343 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007344 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007345 curwin->w_cursor = pos;
7346 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007348 curwin->w_curswant = curswant - 1;
7349 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007351 check_cursor();
7352 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007353 }
7354 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7355 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007356 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007357 if (setmark_pos(name[1], &pos, fnum) == OK)
7358 rettv->vval.v_number = 0;
7359 }
7360 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007361 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362 }
7363 }
7364}
7365
7366/*
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007367 * Translate a register type string to the yank type and block length
7368 */
7369 static int
7370get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
7371{
7372 char_u *stropt = *pp;
7373 switch (*stropt)
7374 {
7375 case 'v': case 'c': // character-wise selection
7376 *yank_type = MCHAR;
7377 break;
7378 case 'V': case 'l': // line-wise selection
7379 *yank_type = MLINE;
7380 break;
7381 case 'b': case Ctrl_V: // block-wise selection
7382 *yank_type = MBLOCK;
7383 if (VIM_ISDIGIT(stropt[1]))
7384 {
7385 ++stropt;
7386 *block_len = getdigits(&stropt) - 1;
7387 --stropt;
7388 }
7389 break;
7390 default:
7391 return FAIL;
7392 }
7393 *pp = stropt;
7394 return OK;
7395}
7396
7397/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398 * "setreg()" function
7399 */
7400 static void
7401f_setreg(typval_T *argvars, typval_T *rettv)
7402{
7403 int regname;
7404 char_u *strregname;
7405 char_u *stropt;
7406 char_u *strval;
7407 int append;
7408 char_u yank_type;
7409 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007410 typval_T *regcontents;
7411 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007413 pointreg = 0;
7414 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007415 block_len = -1;
7416 yank_type = MAUTO;
7417 append = FALSE;
7418
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007419 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007420 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007421
7422 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007423 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424 regname = *strregname;
7425 if (regname == 0 || regname == '@')
7426 regname = '"';
7427
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007428 if (argvars[1].v_type == VAR_DICT)
7429 {
7430 dict_T *d = argvars[1].vval.v_dict;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007431 dictitem_T *di;
7432
7433 if (d == NULL || d->dv_hashtab.ht_used == 0)
7434 {
7435 // Empty dict, clear the register (like setreg(0, []))
7436 char_u *lstval[2] = {NULL, NULL};
7437 write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
7438 return;
7439 }
7440
7441 di = dict_find(d, (char_u *)"regcontents", -1);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007442 if (di != NULL)
7443 regcontents = &di->di_tv;
7444
7445 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
7446 if (stropt != NULL)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007447 {
7448 int ret = get_yank_type(&stropt, &yank_type, &block_len);
7449
7450 if (ret == FAIL || *++stropt != NUL)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007451 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007452 semsg(_(e_invargval), "value");
7453 return;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007454 }
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007455 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007456
7457 if (regname == '"')
7458 {
7459 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
7460 if (stropt != NULL)
7461 {
7462 pointreg = *stropt;
7463 regname = pointreg;
7464 }
7465 }
Bram Moolenaar6a950582020-08-28 16:39:33 +02007466 else if (dict_get_bool(d, (char_u *)"isunnamed", -1) > 0)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007467 pointreg = regname;
7468 }
7469 else
7470 regcontents = &argvars[1];
7471
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007472 if (argvars[2].v_type != VAR_UNKNOWN)
7473 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007474 if (yank_type != MAUTO)
7475 {
7476 semsg(_(e_toomanyarg), "setreg");
7477 return;
7478 }
7479
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007480 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007481 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007482 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007483 for (; *stropt != NUL; ++stropt)
7484 switch (*stropt)
7485 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007486 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007487 append = TRUE;
7488 break;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007489 default:
7490 get_yank_type(&stropt, &yank_type, &block_len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491 }
7492 }
7493
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007494 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 {
7496 char_u **lstval;
7497 char_u **allocval;
7498 char_u buf[NUMBUFLEN];
7499 char_u **curval;
7500 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007501 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502 listitem_T *li;
7503 int len;
7504
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007505 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506 len = ll == NULL ? 0 : ll->lv_len;
7507
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007508 // First half: use for pointers to result lines; second half: use for
7509 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007510 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511 if (lstval == NULL)
7512 return;
7513 curval = lstval;
7514 allocval = lstval + len + 2;
7515 curallocval = allocval;
7516
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007517 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007519 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007520 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007522 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007523 if (strval == NULL)
7524 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007525 if (strval == buf)
7526 {
7527 // Need to make a copy, next tv_get_string_buf_chk() will
7528 // overwrite the string.
7529 strval = vim_strsave(buf);
7530 if (strval == NULL)
7531 goto free_lstval;
7532 *curallocval++ = strval;
7533 }
7534 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007535 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007536 }
7537 *curval++ = NULL;
7538
7539 write_reg_contents_lst(regname, lstval, -1,
7540 append, yank_type, block_len);
7541free_lstval:
7542 while (curallocval > allocval)
7543 vim_free(*--curallocval);
7544 vim_free(lstval);
7545 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007546 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007547 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007548 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007549 if (strval == NULL)
7550 return;
7551 write_reg_contents_ex(regname, strval, -1,
7552 append, yank_type, block_len);
7553 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007554 if (pointreg != 0)
7555 get_yank_register(pointreg, TRUE);
7556
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007557 rettv->vval.v_number = 0;
7558}
7559
7560/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007561 * "settagstack()" function
7562 */
7563 static void
7564f_settagstack(typval_T *argvars, typval_T *rettv)
7565{
7566 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7567 win_T *wp;
7568 dict_T *d;
7569 int action = 'r';
7570
7571 rettv->vval.v_number = -1;
7572
7573 // first argument: window number or id
7574 wp = find_win_by_nr_or_id(&argvars[0]);
7575 if (wp == NULL)
7576 return;
7577
7578 // second argument: dict with items to set in the tag stack
7579 if (argvars[1].v_type != VAR_DICT)
7580 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007581 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007582 return;
7583 }
7584 d = argvars[1].vval.v_dict;
7585 if (d == NULL)
7586 return;
7587
7588 // third argument: action - 'a' for append and 'r' for replace.
7589 // default is to replace the stack.
7590 if (argvars[2].v_type == VAR_UNKNOWN)
7591 action = 'r';
7592 else if (argvars[2].v_type == VAR_STRING)
7593 {
7594 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007595 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007596 if (actstr == NULL)
7597 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007598 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7599 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007600 action = *actstr;
7601 else
7602 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007603 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007604 return;
7605 }
7606 }
7607 else
7608 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007609 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007610 return;
7611 }
7612
7613 if (set_tagstack(wp, d, action) == OK)
7614 rettv->vval.v_number = 0;
7615}
7616
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617#ifdef FEAT_CRYPT
7618/*
7619 * "sha256({string})" function
7620 */
7621 static void
7622f_sha256(typval_T *argvars, typval_T *rettv)
7623{
7624 char_u *p;
7625
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007626 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 rettv->vval.v_string = vim_strsave(
7628 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7629 rettv->v_type = VAR_STRING;
7630}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007631#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632
7633/*
7634 * "shellescape({string})" function
7635 */
7636 static void
7637f_shellescape(typval_T *argvars, typval_T *rettv)
7638{
Bram Moolenaar20615522017-06-05 18:46:26 +02007639 int do_special = non_zero_arg(&argvars[1]);
7640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007641 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007642 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007643 rettv->v_type = VAR_STRING;
7644}
7645
7646/*
7647 * shiftwidth() function
7648 */
7649 static void
7650f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7651{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007652 rettv->vval.v_number = 0;
7653
7654 if (argvars[0].v_type != VAR_UNKNOWN)
7655 {
7656 long col;
7657
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007658 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007659 if (col < 0)
7660 return; // type error; errmsg already given
7661#ifdef FEAT_VARTABS
7662 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7663 return;
7664#endif
7665 }
7666
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667 rettv->vval.v_number = get_sw_value(curbuf);
7668}
7669
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670#ifdef FEAT_FLOAT
7671/*
7672 * "sin()" function
7673 */
7674 static void
7675f_sin(typval_T *argvars, typval_T *rettv)
7676{
7677 float_T f = 0.0;
7678
7679 rettv->v_type = VAR_FLOAT;
7680 if (get_float_arg(argvars, &f) == OK)
7681 rettv->vval.v_float = sin(f);
7682 else
7683 rettv->vval.v_float = 0.0;
7684}
7685
7686/*
7687 * "sinh()" function
7688 */
7689 static void
7690f_sinh(typval_T *argvars, typval_T *rettv)
7691{
7692 float_T f = 0.0;
7693
7694 rettv->v_type = VAR_FLOAT;
7695 if (get_float_arg(argvars, &f) == OK)
7696 rettv->vval.v_float = sinh(f);
7697 else
7698 rettv->vval.v_float = 0.0;
7699}
7700#endif
7701
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007702/*
7703 * "soundfold({word})" function
7704 */
7705 static void
7706f_soundfold(typval_T *argvars, typval_T *rettv)
7707{
7708 char_u *s;
7709
7710 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007711 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007712#ifdef FEAT_SPELL
7713 rettv->vval.v_string = eval_soundfold(s);
7714#else
7715 rettv->vval.v_string = vim_strsave(s);
7716#endif
7717}
7718
7719/*
7720 * "spellbadword()" function
7721 */
7722 static void
7723f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7724{
7725 char_u *word = (char_u *)"";
7726 hlf_T attr = HLF_COUNT;
7727 int len = 0;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007728#ifdef FEAT_SPELL
7729 int wo_spell_save = curwin->w_p_spell;
7730
7731 if (!curwin->w_p_spell)
7732 {
7733 did_set_spelllang(curwin);
7734 curwin->w_p_spell = TRUE;
7735 }
7736
7737 if (*curwin->w_s->b_p_spl == NUL)
7738 {
7739 emsg(_(e_no_spell));
7740 curwin->w_p_spell = wo_spell_save;
7741 return;
7742 }
7743#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744
7745 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007746 {
7747#ifdef FEAT_SPELL
7748 curwin->w_p_spell = wo_spell_save;
7749#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007751 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007752
7753#ifdef FEAT_SPELL
7754 if (argvars[0].v_type == VAR_UNKNOWN)
7755 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007756 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007757 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7758 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007759 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007760 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007761 curwin->w_set_curswant = TRUE;
7762 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007763 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007764 else if (*curbuf->b_s.b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007766 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767 int capcol = -1;
7768
7769 if (str != NULL)
7770 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007771 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007772 while (*str != NUL)
7773 {
7774 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7775 if (attr != HLF_COUNT)
7776 {
7777 word = str;
7778 break;
7779 }
7780 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007781 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007782 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007783 }
7784 }
7785 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007786 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007787#endif
7788
7789 list_append_string(rettv->vval.v_list, word, len);
7790 list_append_string(rettv->vval.v_list, (char_u *)(
7791 attr == HLF_SPB ? "bad" :
7792 attr == HLF_SPR ? "rare" :
7793 attr == HLF_SPL ? "local" :
7794 attr == HLF_SPC ? "caps" :
7795 ""), -1);
7796}
7797
7798/*
7799 * "spellsuggest()" function
7800 */
7801 static void
7802f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7803{
7804#ifdef FEAT_SPELL
7805 char_u *str;
7806 int typeerr = FALSE;
7807 int maxcount;
7808 garray_T ga;
7809 int i;
7810 listitem_T *li;
7811 int need_capital = FALSE;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007812 int wo_spell_save = curwin->w_p_spell;
7813
7814 if (!curwin->w_p_spell)
7815 {
7816 did_set_spelllang(curwin);
7817 curwin->w_p_spell = TRUE;
7818 }
7819
7820 if (*curwin->w_s->b_p_spl == NUL)
7821 {
7822 emsg(_(e_no_spell));
7823 curwin->w_p_spell = wo_spell_save;
7824 return;
7825 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826#endif
7827
7828 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007829 {
7830#ifdef FEAT_SPELL
7831 curwin->w_p_spell = wo_spell_save;
7832#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007833 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007834 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007835
7836#ifdef FEAT_SPELL
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007837 if (*curwin->w_s->b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007838 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007839 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 if (argvars[1].v_type != VAR_UNKNOWN)
7841 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007842 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843 if (maxcount <= 0)
7844 return;
7845 if (argvars[2].v_type != VAR_UNKNOWN)
7846 {
Bram Moolenaar7c27f332020-09-05 22:45:55 +02007847 need_capital = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848 if (typeerr)
7849 return;
7850 }
7851 }
7852 else
7853 maxcount = 25;
7854
7855 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7856
7857 for (i = 0; i < ga.ga_len; ++i)
7858 {
7859 str = ((char_u **)ga.ga_data)[i];
7860
7861 li = listitem_alloc();
7862 if (li == NULL)
7863 vim_free(str);
7864 else
7865 {
7866 li->li_tv.v_type = VAR_STRING;
7867 li->li_tv.v_lock = 0;
7868 li->li_tv.vval.v_string = str;
7869 list_append(rettv->vval.v_list, li);
7870 }
7871 }
7872 ga_clear(&ga);
7873 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007874 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875#endif
7876}
7877
7878 static void
7879f_split(typval_T *argvars, typval_T *rettv)
7880{
7881 char_u *str;
7882 char_u *end;
7883 char_u *pat = NULL;
7884 regmatch_T regmatch;
7885 char_u patbuf[NUMBUFLEN];
7886 char_u *save_cpo;
7887 int match;
7888 colnr_T col = 0;
7889 int keepempty = FALSE;
7890 int typeerr = FALSE;
7891
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007892 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 save_cpo = p_cpo;
7894 p_cpo = (char_u *)"";
7895
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007896 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897 if (argvars[1].v_type != VAR_UNKNOWN)
7898 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007899 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900 if (pat == NULL)
7901 typeerr = TRUE;
7902 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar3986b942020-09-06 16:09:04 +02007903 keepempty = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 }
7905 if (pat == NULL || *pat == NUL)
7906 pat = (char_u *)"[\\x01- ]\\+";
7907
7908 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007909 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910 if (typeerr)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007911 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007912
7913 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7914 if (regmatch.regprog != NULL)
7915 {
7916 regmatch.rm_ic = FALSE;
7917 while (*str != NUL || keepempty)
7918 {
7919 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007920 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 else
7922 match = vim_regexec_nl(&regmatch, str, col);
7923 if (match)
7924 end = regmatch.startp[0];
7925 else
7926 end = str + STRLEN(str);
7927 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7928 && *str != NUL && match && end < regmatch.endp[0]))
7929 {
7930 if (list_append_string(rettv->vval.v_list, str,
7931 (int)(end - str)) == FAIL)
7932 break;
7933 }
7934 if (!match)
7935 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007936 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 if (regmatch.endp[0] > str)
7938 col = 0;
7939 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007940 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007941 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 str = regmatch.endp[0];
7943 }
7944
7945 vim_regfree(regmatch.regprog);
7946 }
7947
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007948theend:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007949 p_cpo = save_cpo;
7950}
7951
7952#ifdef FEAT_FLOAT
7953/*
7954 * "sqrt()" function
7955 */
7956 static void
7957f_sqrt(typval_T *argvars, typval_T *rettv)
7958{
7959 float_T f = 0.0;
7960
7961 rettv->v_type = VAR_FLOAT;
7962 if (get_float_arg(argvars, &f) == OK)
7963 rettv->vval.v_float = sqrt(f);
7964 else
7965 rettv->vval.v_float = 0.0;
7966}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007967#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007968
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007969#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007970/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007971 * "str2float()" function
7972 */
7973 static void
7974f_str2float(typval_T *argvars, typval_T *rettv)
7975{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007976 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007977 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007978
Bram Moolenaar08243d22017-01-10 16:12:29 +01007979 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980 p = skipwhite(p + 1);
7981 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007982 if (isneg)
7983 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984 rettv->v_type = VAR_FLOAT;
7985}
7986#endif
7987
7988/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007989 * "str2list()" function
7990 */
7991 static void
7992f_str2list(typval_T *argvars, typval_T *rettv)
7993{
7994 char_u *p;
7995 int utf8 = FALSE;
7996
7997 if (rettv_list_alloc(rettv) == FAIL)
7998 return;
7999
8000 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaara48f7862020-09-05 20:16:57 +02008001 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar9d401282019-04-06 13:18:12 +02008002
8003 p = tv_get_string(&argvars[0]);
8004
8005 if (has_mbyte || utf8)
8006 {
8007 int (*ptr2len)(char_u *);
8008 int (*ptr2char)(char_u *);
8009
8010 if (utf8 || enc_utf8)
8011 {
8012 ptr2len = utf_ptr2len;
8013 ptr2char = utf_ptr2char;
8014 }
8015 else
8016 {
8017 ptr2len = mb_ptr2len;
8018 ptr2char = mb_ptr2char;
8019 }
8020
8021 for ( ; *p != NUL; p += (*ptr2len)(p))
8022 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8023 }
8024 else
8025 for ( ; *p != NUL; ++p)
8026 list_append_number(rettv->vval.v_list, *p);
8027}
8028
8029/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030 * "str2nr()" function
8031 */
8032 static void
8033f_str2nr(typval_T *argvars, typval_T *rettv)
8034{
8035 int base = 10;
8036 char_u *p;
8037 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008038 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008039 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008040
8041 if (argvars[1].v_type != VAR_UNKNOWN)
8042 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008043 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008044 if (base != 2 && base != 8 && base != 10 && base != 16)
8045 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008046 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008047 return;
8048 }
Bram Moolenaar3986b942020-09-06 16:09:04 +02008049 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2]))
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008050 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008051 }
8052
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008053 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008054 isneg = (*p == '-');
8055 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008056 p = skipwhite(p + 1);
8057 switch (base)
8058 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008059 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02008060 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008061 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008062 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008063 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8064 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008065 if (isneg)
8066 rettv->vval.v_number = -n;
8067 else
8068 rettv->vval.v_number = n;
8069
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070}
8071
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008072/*
8073 * "strgetchar()" function
8074 */
8075 static void
8076f_strgetchar(typval_T *argvars, typval_T *rettv)
8077{
8078 char_u *str;
8079 int len;
8080 int error = FALSE;
8081 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008082 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083
8084 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008085 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 if (str == NULL)
8087 return;
8088 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008089 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008090 if (error)
8091 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008092
Bram Moolenaar13505972019-01-24 15:04:48 +01008093 while (charidx >= 0 && byteidx < len)
8094 {
8095 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008097 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8098 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008099 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008100 --charidx;
8101 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008103}
8104
8105/*
8106 * "stridx()" function
8107 */
8108 static void
8109f_stridx(typval_T *argvars, typval_T *rettv)
8110{
8111 char_u buf[NUMBUFLEN];
8112 char_u *needle;
8113 char_u *haystack;
8114 char_u *save_haystack;
8115 char_u *pos;
8116 int start_idx;
8117
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008118 needle = tv_get_string_chk(&argvars[1]);
8119 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008120 rettv->vval.v_number = -1;
8121 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008122 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008123
8124 if (argvars[2].v_type != VAR_UNKNOWN)
8125 {
8126 int error = FALSE;
8127
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008128 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008129 if (error || start_idx >= (int)STRLEN(haystack))
8130 return;
8131 if (start_idx >= 0)
8132 haystack += start_idx;
8133 }
8134
8135 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8136 if (pos != NULL)
8137 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8138}
8139
8140/*
8141 * "string()" function
8142 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008143 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008144f_string(typval_T *argvars, typval_T *rettv)
8145{
8146 char_u *tofree;
8147 char_u numbuf[NUMBUFLEN];
8148
8149 rettv->v_type = VAR_STRING;
8150 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8151 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008152 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153 if (rettv->vval.v_string != NULL && tofree == NULL)
8154 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8155}
8156
8157/*
8158 * "strlen()" function
8159 */
8160 static void
8161f_strlen(typval_T *argvars, typval_T *rettv)
8162{
8163 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008164 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165}
8166
8167/*
8168 * "strchars()" function
8169 */
8170 static void
8171f_strchars(typval_T *argvars, typval_T *rettv)
8172{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008173 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar3986b942020-09-06 16:09:04 +02008174 int skipcc = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008175 varnumber_T len = 0;
8176 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008177
8178 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar3986b942020-09-06 16:09:04 +02008179 skipcc = (int)tv_get_bool(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008180 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008181 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 else
8183 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8185 while (*s != NUL)
8186 {
8187 func_mb_ptr2char_adv(&s);
8188 ++len;
8189 }
8190 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008191 }
8192}
8193
8194/*
8195 * "strdisplaywidth()" function
8196 */
8197 static void
8198f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8199{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008200 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201 int col = 0;
8202
8203 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008204 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205
8206 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8207}
8208
8209/*
8210 * "strwidth()" function
8211 */
8212 static void
8213f_strwidth(typval_T *argvars, typval_T *rettv)
8214{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008215 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008216
Bram Moolenaar13505972019-01-24 15:04:48 +01008217 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008218}
8219
8220/*
8221 * "strcharpart()" function
8222 */
8223 static void
8224f_strcharpart(typval_T *argvars, typval_T *rettv)
8225{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226 char_u *p;
8227 int nchar;
8228 int nbyte = 0;
8229 int charlen;
8230 int len = 0;
8231 int slen;
8232 int error = FALSE;
8233
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008234 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008235 slen = (int)STRLEN(p);
8236
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008237 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238 if (!error)
8239 {
8240 if (nchar > 0)
8241 while (nchar > 0 && nbyte < slen)
8242 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008243 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008244 --nchar;
8245 }
8246 else
8247 nbyte = nchar;
8248 if (argvars[2].v_type != VAR_UNKNOWN)
8249 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008250 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008251 while (charlen > 0 && nbyte + len < slen)
8252 {
8253 int off = nbyte + len;
8254
8255 if (off < 0)
8256 len += 1;
8257 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008258 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 --charlen;
8260 }
8261 }
8262 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008263 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008264 }
8265
8266 /*
8267 * Only return the overlap between the specified part and the actual
8268 * string.
8269 */
8270 if (nbyte < 0)
8271 {
8272 len += nbyte;
8273 nbyte = 0;
8274 }
8275 else if (nbyte > slen)
8276 nbyte = slen;
8277 if (len < 0)
8278 len = 0;
8279 else if (nbyte + len > slen)
8280 len = slen - nbyte;
8281
8282 rettv->v_type = VAR_STRING;
8283 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008284}
8285
8286/*
8287 * "strpart()" function
8288 */
8289 static void
8290f_strpart(typval_T *argvars, typval_T *rettv)
8291{
8292 char_u *p;
8293 int n;
8294 int len;
8295 int slen;
8296 int error = FALSE;
8297
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008298 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008299 slen = (int)STRLEN(p);
8300
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008301 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302 if (error)
8303 len = 0;
8304 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008305 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008306 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008307 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02008309 // Only return the overlap between the specified part and the actual
8310 // string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008311 if (n < 0)
8312 {
8313 len += n;
8314 n = 0;
8315 }
8316 else if (n > slen)
8317 n = slen;
8318 if (len < 0)
8319 len = 0;
8320 else if (n + len > slen)
8321 len = slen - n;
8322
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02008323 if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN)
8324 {
8325 int off;
8326
8327 // length in characters
8328 for (off = n; off < slen && len > 0; --len)
8329 off += mb_ptr2len(p + off);
8330 len = off - n;
8331 }
8332
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008333 rettv->v_type = VAR_STRING;
8334 rettv->vval.v_string = vim_strnsave(p + n, len);
8335}
8336
8337/*
8338 * "strridx()" function
8339 */
8340 static void
8341f_strridx(typval_T *argvars, typval_T *rettv)
8342{
8343 char_u buf[NUMBUFLEN];
8344 char_u *needle;
8345 char_u *haystack;
8346 char_u *rest;
8347 char_u *lastmatch = NULL;
8348 int haystack_len, end_idx;
8349
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008350 needle = tv_get_string_chk(&argvars[1]);
8351 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008352
8353 rettv->vval.v_number = -1;
8354 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008355 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008356
8357 haystack_len = (int)STRLEN(haystack);
8358 if (argvars[2].v_type != VAR_UNKNOWN)
8359 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008360 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008361 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008362 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008363 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008364 }
8365 else
8366 end_idx = haystack_len;
8367
8368 if (*needle == NUL)
8369 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008370 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371 lastmatch = haystack + end_idx;
8372 }
8373 else
8374 {
8375 for (rest = haystack; *rest != '\0'; ++rest)
8376 {
8377 rest = (char_u *)strstr((char *)rest, (char *)needle);
8378 if (rest == NULL || rest > haystack + end_idx)
8379 break;
8380 lastmatch = rest;
8381 }
8382 }
8383
8384 if (lastmatch == NULL)
8385 rettv->vval.v_number = -1;
8386 else
8387 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8388}
8389
8390/*
8391 * "strtrans()" function
8392 */
8393 static void
8394f_strtrans(typval_T *argvars, typval_T *rettv)
8395{
8396 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008397 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398}
8399
8400/*
8401 * "submatch()" function
8402 */
8403 static void
8404f_submatch(typval_T *argvars, typval_T *rettv)
8405{
8406 int error = FALSE;
8407 int no;
8408 int retList = 0;
8409
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008410 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008411 if (error)
8412 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008413 if (no < 0 || no >= NSUBEXP)
8414 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008415 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008416 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008417 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008418 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaarad304702020-09-06 18:22:53 +02008419 retList = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008420 if (error)
8421 return;
8422
8423 if (retList == 0)
8424 {
8425 rettv->v_type = VAR_STRING;
8426 rettv->vval.v_string = reg_submatch(no);
8427 }
8428 else
8429 {
8430 rettv->v_type = VAR_LIST;
8431 rettv->vval.v_list = reg_submatch_list(no);
8432 }
8433}
8434
8435/*
8436 * "substitute()" function
8437 */
8438 static void
8439f_substitute(typval_T *argvars, typval_T *rettv)
8440{
8441 char_u patbuf[NUMBUFLEN];
8442 char_u subbuf[NUMBUFLEN];
8443 char_u flagsbuf[NUMBUFLEN];
8444
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008445 char_u *str = tv_get_string_chk(&argvars[0]);
8446 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008447 char_u *sub = NULL;
8448 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008449 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008450
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008451 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8452 expr = &argvars[2];
8453 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008454 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008455
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008456 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008457 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8458 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459 rettv->vval.v_string = NULL;
8460 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008461 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008462}
8463
8464/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008465 * "swapinfo(swap_filename)" function
8466 */
8467 static void
8468f_swapinfo(typval_T *argvars, typval_T *rettv)
8469{
8470 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008471 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008472}
8473
8474/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008475 * "swapname(expr)" function
8476 */
8477 static void
8478f_swapname(typval_T *argvars, typval_T *rettv)
8479{
8480 buf_T *buf;
8481
8482 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008483 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008484 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8485 || buf->b_ml.ml_mfp->mf_fname == NULL)
8486 rettv->vval.v_string = NULL;
8487 else
8488 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8489}
8490
8491/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008492 * "synID(lnum, col, trans)" function
8493 */
8494 static void
8495f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8496{
8497 int id = 0;
8498#ifdef FEAT_SYN_HL
8499 linenr_T lnum;
8500 colnr_T col;
8501 int trans;
8502 int transerr = FALSE;
8503
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008504 lnum = tv_get_lnum(argvars); // -1 on type error
8505 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaarfcb6d702020-09-05 21:41:56 +02008506 trans = (int)tv_get_bool_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008507
8508 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8509 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8510 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8511#endif
8512
8513 rettv->vval.v_number = id;
8514}
8515
8516/*
8517 * "synIDattr(id, what [, mode])" function
8518 */
8519 static void
8520f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8521{
8522 char_u *p = NULL;
8523#ifdef FEAT_SYN_HL
8524 int id;
8525 char_u *what;
8526 char_u *mode;
8527 char_u modebuf[NUMBUFLEN];
8528 int modec;
8529
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008530 id = (int)tv_get_number(&argvars[0]);
8531 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008532 if (argvars[2].v_type != VAR_UNKNOWN)
8533 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008534 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008535 modec = TOLOWER_ASC(mode[0]);
8536 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008537 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008538 }
8539 else
8540 {
8541#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8542 if (USE_24BIT)
8543 modec = 'g';
8544 else
8545#endif
8546 if (t_colors > 1)
8547 modec = 'c';
8548 else
8549 modec = 't';
8550 }
8551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008552 switch (TOLOWER_ASC(what[0]))
8553 {
8554 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008555 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008556 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008557 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 p = highlight_has_attr(id, HL_BOLD, modec);
8559 break;
8560
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008561 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008562 p = highlight_color(id, what, modec);
8563 break;
8564
8565 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008566 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008567 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008568 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008569 p = highlight_has_attr(id, HL_ITALIC, modec);
8570 break;
8571
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008572 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008573 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008574 break;
8575
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008576 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008577 p = highlight_has_attr(id, HL_INVERSE, modec);
8578 break;
8579
8580 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008581 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008582 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008583 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008584 else if (TOLOWER_ASC(what[1]) == 't' &&
8585 TOLOWER_ASC(what[2]) == 'r')
8586 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008587 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008588 p = highlight_has_attr(id, HL_STANDOUT, modec);
8589 break;
8590
8591 case 'u':
8592 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008593 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008594 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8595 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008596 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008597 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8598 break;
8599 }
8600
8601 if (p != NULL)
8602 p = vim_strsave(p);
8603#endif
8604 rettv->v_type = VAR_STRING;
8605 rettv->vval.v_string = p;
8606}
8607
8608/*
8609 * "synIDtrans(id)" function
8610 */
8611 static void
8612f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8613{
8614 int id;
8615
8616#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008617 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008618
8619 if (id > 0)
8620 id = syn_get_final_id(id);
8621 else
8622#endif
8623 id = 0;
8624
8625 rettv->vval.v_number = id;
8626}
8627
8628/*
8629 * "synconcealed(lnum, col)" function
8630 */
8631 static void
8632f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8633{
8634#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8635 linenr_T lnum;
8636 colnr_T col;
8637 int syntax_flags = 0;
8638 int cchar;
8639 int matchid = 0;
8640 char_u str[NUMBUFLEN];
8641#endif
8642
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008643 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644
8645#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008646 lnum = tv_get_lnum(argvars); // -1 on type error
8647 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008648
Bram Moolenaara80faa82020-04-12 19:37:17 +02008649 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008650
8651 if (rettv_list_alloc(rettv) != FAIL)
8652 {
8653 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8654 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8655 && curwin->w_p_cole > 0)
8656 {
8657 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8658 syntax_flags = get_syntax_info(&matchid);
8659
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008660 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008661 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8662 {
8663 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008664 if (cchar == NUL && curwin->w_p_cole == 1)
8665 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008666 if (cchar != NUL)
8667 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008668 if (has_mbyte)
8669 (*mb_char2bytes)(cchar, str);
8670 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008671 str[0] = cchar;
8672 }
8673 }
8674 }
8675
8676 list_append_number(rettv->vval.v_list,
8677 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008678 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008679 list_append_string(rettv->vval.v_list, str, -1);
8680 list_append_number(rettv->vval.v_list, matchid);
8681 }
8682#endif
8683}
8684
8685/*
8686 * "synstack(lnum, col)" function
8687 */
8688 static void
8689f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8690{
8691#ifdef FEAT_SYN_HL
8692 linenr_T lnum;
8693 colnr_T col;
8694 int i;
8695 int id;
8696#endif
8697
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008698 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008699
8700#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008701 lnum = tv_get_lnum(argvars); // -1 on type error
8702 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008703
8704 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8705 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8706 && rettv_list_alloc(rettv) != FAIL)
8707 {
8708 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8709 for (i = 0; ; ++i)
8710 {
8711 id = syn_get_stack_item(i);
8712 if (id < 0)
8713 break;
8714 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8715 break;
8716 }
8717 }
8718#endif
8719}
8720
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721/*
8722 * "tabpagebuflist()" function
8723 */
8724 static void
8725f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8726{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008727 tabpage_T *tp;
8728 win_T *wp = NULL;
8729
8730 if (argvars[0].v_type == VAR_UNKNOWN)
8731 wp = firstwin;
8732 else
8733 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008734 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008735 if (tp != NULL)
8736 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8737 }
8738 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8739 {
8740 for (; wp != NULL; wp = wp->w_next)
8741 if (list_append_number(rettv->vval.v_list,
8742 wp->w_buffer->b_fnum) == FAIL)
8743 break;
8744 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008745}
8746
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008747/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008748 * "tagfiles()" function
8749 */
8750 static void
8751f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8752{
8753 char_u *fname;
8754 tagname_T tn;
8755 int first;
8756
8757 if (rettv_list_alloc(rettv) == FAIL)
8758 return;
8759 fname = alloc(MAXPATHL);
8760 if (fname == NULL)
8761 return;
8762
8763 for (first = TRUE; ; first = FALSE)
8764 if (get_tagfname(&tn, first, fname) == FAIL
8765 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8766 break;
8767 tagname_free(&tn);
8768 vim_free(fname);
8769}
8770
8771/*
8772 * "taglist()" function
8773 */
8774 static void
8775f_taglist(typval_T *argvars, typval_T *rettv)
8776{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008777 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008778 char_u *tag_pattern;
8779
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008780 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008781
8782 rettv->vval.v_number = FALSE;
8783 if (*tag_pattern == NUL)
8784 return;
8785
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008786 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008787 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008788 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008789 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008790}
8791
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008792#ifdef FEAT_FLOAT
8793/*
8794 * "tan()" function
8795 */
8796 static void
8797f_tan(typval_T *argvars, typval_T *rettv)
8798{
8799 float_T f = 0.0;
8800
8801 rettv->v_type = VAR_FLOAT;
8802 if (get_float_arg(argvars, &f) == OK)
8803 rettv->vval.v_float = tan(f);
8804 else
8805 rettv->vval.v_float = 0.0;
8806}
8807
8808/*
8809 * "tanh()" function
8810 */
8811 static void
8812f_tanh(typval_T *argvars, typval_T *rettv)
8813{
8814 float_T f = 0.0;
8815
8816 rettv->v_type = VAR_FLOAT;
8817 if (get_float_arg(argvars, &f) == OK)
8818 rettv->vval.v_float = tanh(f);
8819 else
8820 rettv->vval.v_float = 0.0;
8821}
8822#endif
8823
8824/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008825 * "tolower(string)" function
8826 */
8827 static void
8828f_tolower(typval_T *argvars, typval_T *rettv)
8829{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008830 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008831 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008832}
8833
8834/*
8835 * "toupper(string)" function
8836 */
8837 static void
8838f_toupper(typval_T *argvars, typval_T *rettv)
8839{
8840 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008841 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008842}
8843
8844/*
8845 * "tr(string, fromstr, tostr)" function
8846 */
8847 static void
8848f_tr(typval_T *argvars, typval_T *rettv)
8849{
8850 char_u *in_str;
8851 char_u *fromstr;
8852 char_u *tostr;
8853 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854 int inlen;
8855 int fromlen;
8856 int tolen;
8857 int idx;
8858 char_u *cpstr;
8859 int cplen;
8860 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008861 char_u buf[NUMBUFLEN];
8862 char_u buf2[NUMBUFLEN];
8863 garray_T ga;
8864
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008865 in_str = tv_get_string(&argvars[0]);
8866 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8867 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008868
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008869 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008870 rettv->v_type = VAR_STRING;
8871 rettv->vval.v_string = NULL;
8872 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008873 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008874 ga_init2(&ga, (int)sizeof(char), 80);
8875
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008876 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008877 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008878 if (STRLEN(fromstr) != STRLEN(tostr))
8879 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008880error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008881 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008882 ga_clear(&ga);
8883 return;
8884 }
8885
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008886 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008887 while (*in_str != NUL)
8888 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008889 if (has_mbyte)
8890 {
8891 inlen = (*mb_ptr2len)(in_str);
8892 cpstr = in_str;
8893 cplen = inlen;
8894 idx = 0;
8895 for (p = fromstr; *p != NUL; p += fromlen)
8896 {
8897 fromlen = (*mb_ptr2len)(p);
8898 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8899 {
8900 for (p = tostr; *p != NUL; p += tolen)
8901 {
8902 tolen = (*mb_ptr2len)(p);
8903 if (idx-- == 0)
8904 {
8905 cplen = tolen;
8906 cpstr = p;
8907 break;
8908 }
8909 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008910 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008911 goto error;
8912 break;
8913 }
8914 ++idx;
8915 }
8916
8917 if (first && cpstr == in_str)
8918 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008919 // Check that fromstr and tostr have the same number of
8920 // (multi-byte) characters. Done only once when a character
8921 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008922 first = FALSE;
8923 for (p = tostr; *p != NUL; p += tolen)
8924 {
8925 tolen = (*mb_ptr2len)(p);
8926 --idx;
8927 }
8928 if (idx != 0)
8929 goto error;
8930 }
8931
8932 (void)ga_grow(&ga, cplen);
8933 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8934 ga.ga_len += cplen;
8935
8936 in_str += inlen;
8937 }
8938 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008939 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008940 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008941 p = vim_strchr(fromstr, *in_str);
8942 if (p != NULL)
8943 ga_append(&ga, tostr[p - fromstr]);
8944 else
8945 ga_append(&ga, *in_str);
8946 ++in_str;
8947 }
8948 }
8949
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008950 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008951 (void)ga_grow(&ga, 1);
8952 ga_append(&ga, NUL);
8953
8954 rettv->vval.v_string = ga.ga_data;
8955}
8956
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008957/*
8958 * "trim({expr})" function
8959 */
8960 static void
8961f_trim(typval_T *argvars, typval_T *rettv)
8962{
8963 char_u buf1[NUMBUFLEN];
8964 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008965 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008966 char_u *mask = NULL;
8967 char_u *tail;
8968 char_u *prev;
8969 char_u *p;
8970 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008971 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008972
8973 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008974 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008975 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008976 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008977
8978 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008979 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008980 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008981
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008982 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008983 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008984 int error = 0;
8985
8986 // leading or trailing characters to trim
8987 dir = (int)tv_get_number_chk(&argvars[2], &error);
8988 if (error)
8989 return;
8990 if (dir < 0 || dir > 2)
8991 {
8992 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8993 return;
8994 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008995 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008996 }
8997
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008998 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008999 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009000 // Trim leading characters
9001 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009002 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009003 c1 = PTR2CHAR(head);
9004 if (mask == NULL)
9005 {
9006 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009007 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009008 }
9009 else
9010 {
9011 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9012 if (c1 == PTR2CHAR(p))
9013 break;
9014 if (*p == NUL)
9015 break;
9016 }
9017 MB_PTR_ADV(head);
9018 }
9019 }
9020
9021 tail = head + STRLEN(head);
9022 if (dir == 0 || dir == 2)
9023 {
9024 // Trim trailing characters
9025 for (; tail > head; tail = prev)
9026 {
9027 prev = tail;
9028 MB_PTR_BACK(head, prev);
9029 c1 = PTR2CHAR(prev);
9030 if (mask == NULL)
9031 {
9032 if (c1 > ' ' && c1 != 0xa0)
9033 break;
9034 }
9035 else
9036 {
9037 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9038 if (c1 == PTR2CHAR(p))
9039 break;
9040 if (*p == NUL)
9041 break;
9042 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009043 }
9044 }
Bram Moolenaardf44a272020-06-07 20:49:05 +02009045 rettv->vval.v_string = vim_strnsave(head, tail - head);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009046}
9047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009048#ifdef FEAT_FLOAT
9049/*
9050 * "trunc({float})" function
9051 */
9052 static void
9053f_trunc(typval_T *argvars, typval_T *rettv)
9054{
9055 float_T f = 0.0;
9056
9057 rettv->v_type = VAR_FLOAT;
9058 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009059 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009060 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
9061 else
9062 rettv->vval.v_float = 0.0;
9063}
9064#endif
9065
9066/*
9067 * "type(expr)" function
9068 */
9069 static void
9070f_type(typval_T *argvars, typval_T *rettv)
9071{
9072 int n = -1;
9073
9074 switch (argvars[0].v_type)
9075 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009076 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
9077 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009078 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009079 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
9080 case VAR_LIST: n = VAR_TYPE_LIST; break;
9081 case VAR_DICT: n = VAR_TYPE_DICT; break;
9082 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
9083 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
9084 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02009085 case VAR_JOB: n = VAR_TYPE_JOB; break;
9086 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009087 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009088 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02009089 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01009090 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01009091 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009092 n = -1;
9093 break;
9094 }
9095 rettv->vval.v_number = n;
9096}
9097
9098/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009099 * "virtcol(string)" function
9100 */
9101 static void
9102f_virtcol(typval_T *argvars, typval_T *rettv)
9103{
9104 colnr_T vcol = 0;
9105 pos_T *fp;
9106 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009107 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009108
9109 fp = var2fpos(&argvars[0], FALSE, &fnum);
9110 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9111 && fnum == curbuf->b_fnum)
9112 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009113 // Limit the column to a valid value, getvvcol() doesn't check.
9114 if (fp->col < 0)
9115 fp->col = 0;
9116 else
9117 {
9118 len = (int)STRLEN(ml_get(fp->lnum));
9119 if (fp->col > len)
9120 fp->col = len;
9121 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009122 getvvcol(curwin, fp, NULL, NULL, &vcol);
9123 ++vcol;
9124 }
9125
9126 rettv->vval.v_number = vcol;
9127}
9128
9129/*
9130 * "visualmode()" function
9131 */
9132 static void
9133f_visualmode(typval_T *argvars, typval_T *rettv)
9134{
9135 char_u str[2];
9136
9137 rettv->v_type = VAR_STRING;
9138 str[0] = curbuf->b_visual_mode_eval;
9139 str[1] = NUL;
9140 rettv->vval.v_string = vim_strsave(str);
9141
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009142 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009143 if (non_zero_arg(&argvars[0]))
9144 curbuf->b_visual_mode_eval = NUL;
9145}
9146
9147/*
9148 * "wildmenumode()" function
9149 */
9150 static void
9151f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9152{
9153#ifdef FEAT_WILDMENU
9154 if (wild_menu_showing)
9155 rettv->vval.v_number = 1;
9156#endif
9157}
9158
9159/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01009160 * "windowsversion()" function
9161 */
9162 static void
9163f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9164{
9165 rettv->v_type = VAR_STRING;
9166 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
9167}
9168
9169/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009170 * "wordcount()" function
9171 */
9172 static void
9173f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
9174{
9175 if (rettv_dict_alloc(rettv) == FAIL)
9176 return;
9177 cursor_pos_info(rettv->vval.v_dict);
9178}
9179
9180/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009181 * "xor(expr, expr)" function
9182 */
9183 static void
9184f_xor(typval_T *argvars, typval_T *rettv)
9185{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009186 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9187 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009188}
9189
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009190#endif // FEAT_EVAL