blob: 7bc4f05f5f38750731ea5601e0e113a04ae63c75 [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 *
Bram Moolenaar403dc312020-10-17 19:29:51 +0200273ret_bool(int argcount UNUSED, type_T **argtypes UNUSED)
274{
275 return &t_bool;
276}
277 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100278ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
279{
280 return &t_number;
281}
282 static type_T *
283ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
284{
285 return &t_float;
286}
287 static type_T *
288ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
289{
290 return &t_string;
291}
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200292 static type_T *
293ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100294{
295 return &t_list_any;
296}
297 static type_T *
298ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
299{
300 return &t_list_number;
301}
302 static type_T *
303ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
304{
305 return &t_list_string;
306}
307 static type_T *
308ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
309{
310 return &t_list_dict_any;
311}
312 static type_T *
313ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
314{
315 return &t_dict_any;
316}
317 static type_T *
318ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
319{
320 return &t_dict_number;
321}
322 static type_T *
323ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
324{
325 return &t_dict_string;
326}
327 static type_T *
328ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
329{
330 return &t_blob;
331}
332 static type_T *
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200333ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100334{
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200335 return &t_func_any;
336}
337 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100338ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
339{
340 return &t_channel;
341}
342 static type_T *
343ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
344{
345 return &t_job;
346}
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100347
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200348 static type_T *
349ret_first_arg(int argcount, type_T **argtypes)
350{
351 if (argcount > 0)
352 return argtypes[0];
353 return &t_void;
354}
355
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200356/*
357 * Used for getqflist(): returns list if there is no argument, dict if there is
358 * one.
359 */
360 static type_T *
361ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
362{
363 if (argcount > 0)
364 return &t_dict_any;
365 return &t_list_dict_any;
366}
367
368/*
369 * Used for getloclist(): returns list if there is one argument, dict if there
370 * are two.
371 */
372 static type_T *
373ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
374{
375 if (argcount > 1)
376 return &t_dict_any;
377 return &t_list_dict_any;
378}
379
Bram Moolenaar846178a2020-07-05 17:04:13 +0200380 static type_T *
381ret_argv(int argcount, type_T **argtypes UNUSED)
382{
383 // argv() returns list of strings
384 if (argcount == 0)
385 return &t_list_string;
386
387 // argv(0) returns a string, but argv(-1] returns a list
388 return &t_any;
389}
390
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200391 static type_T *
392ret_remove(int argcount UNUSED, type_T **argtypes)
393{
Bram Moolenaar5e654232020-09-16 15:22:00 +0200394 if (argtypes != NULL)
395 {
396 if (argtypes[0]->tt_type == VAR_LIST
397 || argtypes[0]->tt_type == VAR_DICT)
398 return argtypes[0]->tt_member;
399 if (argtypes[0]->tt_type == VAR_BLOB)
400 return &t_number;
401 }
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200402 return &t_any;
403}
404
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200405 static type_T *
406ret_getreg(int argcount, type_T **argtypes UNUSED)
407{
408 // Assume that if the third argument is passed it's non-zero
409 if (argcount == 3)
410 return &t_list_string;
411 return &t_string;
412}
413
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200414 static type_T *
415ret_maparg(int argcount, type_T **argtypes UNUSED)
416{
417 // Assume that if the fourth argument is passed it's non-zero
418 if (argcount == 4)
419 return &t_dict_any;
420 return &t_string;
421}
422
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100423static type_T *ret_f_function(int argcount, type_T **argtypes);
424
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200425/*
426 * Array with names and number of arguments of all internal functions
427 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
428 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200429typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200431 char *f_name; // function name
432 char f_min_argc; // minimal number of arguments
433 char f_max_argc; // maximal number of arguments
434 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100435 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
436 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200438 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200439} funcentry_T;
440
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200441// values for f_argtype; zero means it cannot be used as a method
442#define FEARG_1 1 // base is the first argument
443#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200444#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200445#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200446#define FEARG_LAST 9 // base is the last argument
447
Bram Moolenaar15c47602020-03-26 22:16:48 +0100448#ifdef FEAT_FLOAT
449# define FLOAT_FUNC(name) name
450#else
451# define FLOAT_FUNC(name) NULL
452#endif
453#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
454# define MATH_FUNC(name) name
455#else
456# define MATH_FUNC(name) NULL
457#endif
458#ifdef FEAT_TIMERS
459# define TIMER_FUNC(name) name
460#else
461# define TIMER_FUNC(name) NULL
462#endif
463#ifdef FEAT_JOB_CHANNEL
464# define JOB_FUNC(name) name
465#else
466# define JOB_FUNC(name) NULL
467#endif
468#ifdef FEAT_PROP_POPUP
469# define PROP_FUNC(name) name
470#else
471# define PROP_FUNC(name) NULL
472#endif
473#ifdef FEAT_SIGNS
474# define SIGN_FUNC(name) name
475#else
476# define SIGN_FUNC(name) NULL
477#endif
478#ifdef FEAT_SOUND
479# define SOUND_FUNC(name) name
480#else
481# define SOUND_FUNC(name) NULL
482#endif
483#ifdef FEAT_TERMINAL
484# define TERM_FUNC(name) name
485#else
486# define TERM_FUNC(name) NULL
487#endif
488
Bram Moolenaarac92e252019-08-03 21:58:38 +0200489static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200490{
Bram Moolenaar15c47602020-03-26 22:16:48 +0100491 {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)},
492 {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfce82b32020-07-05 16:07:21 +0200493 {"add", 2, 2, FEARG_1, ret_first_arg, f_add},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100494 {"and", 2, 2, FEARG_1, ret_number, f_and},
Bram Moolenaar389df252020-07-09 21:20:47 +0200495 {"append", 2, 2, FEARG_2, ret_number, f_append},
Bram Moolenaar92053ce2020-07-09 22:53:30 +0200496 {"appendbufline", 3, 3, FEARG_3, ret_number, f_appendbufline},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"argc", 0, 1, 0, ret_number, f_argc},
498 {"argidx", 0, 0, 0, ret_number, f_argidx},
499 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
Bram Moolenaar846178a2020-07-05 17:04:13 +0200500 {"argv", 0, 2, 0, ret_argv, f_argv},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100501 {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100502 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
503 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
Bram Moolenaarfb517ba2020-06-03 19:55:35 +0200504 {"assert_equalfile", 2, 3, FEARG_1, ret_number, f_assert_equalfile},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100505 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
Bram Moolenaar9bd5d872020-09-06 21:47:48 +0200506 {"assert_fails", 1, 5, FEARG_1, ret_number, f_assert_fails},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100507 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
508 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
509 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
510 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
511 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
512 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
513 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100514 {"atan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_atan)},
515 {"atan2", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_atan2)},
516 {"balloon_gettext", 0, 0, 0, ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100517#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100518 f_balloon_gettext
519#else
520 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100521#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100522 },
523 {"balloon_show", 1, 1, FEARG_1, ret_void,
524#ifdef FEAT_BEVAL
525 f_balloon_show
526#else
527 NULL
528#endif
529 },
530 {"balloon_split", 1, 1, FEARG_1, ret_list_string,
531#if defined(FEAT_BEVAL_TERM)
532 f_balloon_split
533#else
534 NULL
535#endif
536 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100537 {"browse", 4, 4, 0, ret_string, f_browse},
538 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
539 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
540 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
541 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
542 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
543 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
544 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
545 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
546 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
547 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
548 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
549 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
550 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
551 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
552 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
553 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
554 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100555 {"ceil", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_ceil)},
556 {"ch_canread", 1, 1, FEARG_1, ret_number, JOB_FUNC(f_ch_canread)},
557 {"ch_close", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close)},
558 {"ch_close_in", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close_in)},
559 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalexpr)},
560 {"ch_evalraw", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalraw)},
561 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, JOB_FUNC(f_ch_getbufnr)},
562 {"ch_getjob", 1, 1, FEARG_1, ret_job, JOB_FUNC(f_ch_getjob)},
563 {"ch_info", 1, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_ch_info)},
564 {"ch_log", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_log)},
565 {"ch_logfile", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_logfile)},
566 {"ch_open", 1, 2, FEARG_1, ret_channel, JOB_FUNC(f_ch_open)},
567 {"ch_read", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_read)},
568 {"ch_readblob", 1, 2, FEARG_1, ret_blob, JOB_FUNC(f_ch_readblob)},
569 {"ch_readraw", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_readraw)},
570 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendexpr)},
571 {"ch_sendraw", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendraw)},
572 {"ch_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_setoptions)},
573 {"ch_status", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_status)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100574 {"changenr", 0, 0, 0, ret_number, f_changenr},
575 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
Bram Moolenaar4e4473c2020-08-28 22:24:57 +0200576 {"charclass", 1, 1, FEARG_1, ret_number, f_charclass},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100577 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
578 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
579 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
580 {"col", 1, 1, FEARG_1, ret_number, f_col},
581 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
582 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
583 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
584 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
585 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
Bram Moolenaara66ba012020-07-05 18:41:08 +0200586 {"copy", 1, 1, FEARG_1, ret_first_arg, f_copy},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100587 {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)},
588 {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100589 {"count", 2, 4, FEARG_1, ret_number, f_count},
590 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
591 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100592 {"debugbreak", 1, 1, FEARG_1, ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100593#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100594 f_debugbreak
595#else
596 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200597#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100598 },
Bram Moolenaara66ba012020-07-05 18:41:08 +0200599 {"deepcopy", 1, 2, FEARG_1, ret_first_arg, f_deepcopy},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
601 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
602 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
603 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
604 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
605 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
606 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
607 {"environ", 0, 0, 0, ret_dict_string, f_environ},
608 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
609 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
610 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
611 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
612 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
613 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
614 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100615 {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100616 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
617 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
Bram Moolenaarb3c019c2020-07-05 20:08:39 +0200618 {"extend", 2, 3, FEARG_1, ret_first_arg, f_extend},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100619 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
620 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
621 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
622 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
Bram Moolenaar0d94ad62020-07-05 20:16:41 +0200623 {"filter", 2, 2, FEARG_1, ret_first_arg, f_filter},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100624 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
625 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar077a1e62020-06-08 20:50:43 +0200626 {"flatten", 1, 2, FEARG_1, ret_list_any, f_flatten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100627 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)},
628 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)},
629 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100630 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
631 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
632 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
633 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
634 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
635 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
636 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
637 {"foreground", 0, 0, 0, ret_void, f_foreground},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200638 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100639 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
640 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
641 {"get", 2, 3, FEARG_1, ret_any, f_get},
Bram Moolenaar6434fc52020-07-18 22:24:22 +0200642 {"getbufinfo", 0, 1, FEARG_1, ret_list_dict_any, f_getbufinfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100643 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
644 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
645 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
646 {"getchar", 0, 1, 0, ret_number, f_getchar},
647 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
648 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
649 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
650 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
651 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
652 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
653 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
Bram Moolenaar99ca9c42020-09-22 21:55:41 +0200654 {"getcurpos", 0, 1, FEARG_1, ret_list_number, f_getcurpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100655 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
656 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
657 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
658 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
659 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
660 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
661 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
662 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
663 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
664 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200665 {"getloclist", 1, 2, 0, ret_list_or_dict_1, f_getloclist},
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +0200666 {"getmarklist", 0, 1, FEARG_1, ret_list_dict_any, f_getmarklist},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100667 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
668 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
669 {"getpid", 0, 0, 0, ret_number, f_getpid},
670 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200671 {"getqflist", 0, 1, 0, ret_list_or_dict_0, f_getqflist},
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200672 {"getreg", 0, 3, FEARG_1, ret_getreg, f_getreg},
Bram Moolenaarbb861e22020-06-07 18:16:36 +0200673 {"getreginfo", 0, 1, FEARG_1, ret_dict_any, f_getreginfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100674 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
675 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
676 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
677 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
678 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +0200679 {"gettext", 1, 1, FEARG_1, ret_string, f_gettext},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100680 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
681 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
682 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
683 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
684 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
685 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
686 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
687 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100688 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100689 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
690 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
691 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
692 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
693 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
694 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
695 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
696 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
697 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
698 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
699 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
700 {"hostname", 0, 0, 0, ret_string, f_hostname},
701 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
702 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
703 {"index", 2, 4, FEARG_1, ret_number, f_index},
704 {"input", 1, 3, FEARG_1, ret_string, f_input},
705 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
706 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
707 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
708 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
709 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
Bram Moolenaar252e88a2020-07-05 20:47:18 +0200710 {"insert", 2, 3, FEARG_1, ret_first_arg, f_insert},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100711 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
712 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
713 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100714 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100715 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100716 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100717 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100718 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
719 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
720 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
721 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
722 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
723 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100724 {"join", 1, 2, FEARG_1, ret_string, f_join},
725 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
726 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
727 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
728 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
Bram Moolenaar32f335f2020-08-14 18:56:45 +0200729 {"keys", 1, 1, FEARG_1, ret_list_string, f_keys},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100730 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
731 {"len", 1, 1, FEARG_1, ret_number, f_len},
732 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
733 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
734 {"line", 1, 2, FEARG_1, ret_number, f_line},
735 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
736 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
737 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
738 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
739 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
740 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
741 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100742 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
743 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
744 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200745#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100746 f_luaeval
747#else
748 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200749#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100750 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100751 {"map", 2, 2, FEARG_1, ret_any, f_map},
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200752 {"maparg", 1, 4, FEARG_1, ret_maparg, f_maparg},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100753 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200754 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100755 {"match", 2, 4, FEARG_1, ret_any, f_match},
756 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
757 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
758 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
759 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
760 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
Bram Moolenaar4f73b8e2020-09-22 20:33:50 +0200761 {"matchfuzzy", 2, 3, FEARG_1, ret_list_string, f_matchfuzzy},
762 {"matchfuzzypos", 2, 3, FEARG_1, ret_list_any, f_matchfuzzypos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100763 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
764 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
765 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
766 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100767 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100768#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100769 f_menu_info
770#else
771 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100772#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100773 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100774 {"min", 1, 1, FEARG_1, ret_any, f_min},
775 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
776 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100777 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100779 f_mzeval
780#else
781 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200782#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100783 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100784 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
785 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
786 {"or", 2, 2, FEARG_1, ret_number, f_or},
Bram Moolenaar6a33ef02020-09-25 22:42:48 +0200787 {"pathshorten", 1, 2, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100788 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200789#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100790 f_perleval
791#else
792 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100794 },
795 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
796 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200797 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100798 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
799 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
800 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
Bram Moolenaar403dc312020-10-17 19:29:51 +0200801 {"popup_filter_menu", 2, 2, 0, ret_bool, PROP_FUNC(f_popup_filter_menu)},
802 {"popup_filter_yesno", 2, 2, 0, ret_bool, PROP_FUNC(f_popup_filter_yesno)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100803 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
804 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
805 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
806 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
807 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200808 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100809 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
810 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
811 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
812 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
813 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
814 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
815 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
816 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100817 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
818 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar077cc7a2020-09-04 16:35:35 +0200819 {"prompt_getprompt", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_prompt_getprompt)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100820 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
821 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
822 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
823 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
824 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
825 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
826 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
827 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
828 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
829 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
830 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
831 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
832 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100833 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
834 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100835 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100837 f_py3eval
838#else
839 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200840#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100841 },
842 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100844 f_pyeval
845#else
846 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100848 },
849 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100850#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100851 f_pyxeval
852#else
853 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100854#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100855 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100856 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
857 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +0200858 {"readdir", 1, 3, FEARG_1, ret_list_string, f_readdir},
859 {"readdirex", 1, 3, FEARG_1, ret_list_dict_any, f_readdirex},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100860 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
Bram Moolenaar85629982020-06-01 18:39:20 +0200861 {"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100862 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
863 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
864 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100865 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100866 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
867 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
868 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
869 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
870 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
871 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
Bram Moolenaar9978d472020-07-05 16:01:56 +0200872 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200873 {"remove", 2, 3, FEARG_1, ret_remove, f_remove},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100874 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
Bram Moolenaar9978d472020-07-05 16:01:56 +0200875 {"repeat", 2, 2, FEARG_1, ret_first_arg, f_repeat},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100876 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
Bram Moolenaar67627352020-07-05 21:10:24 +0200877 {"reverse", 1, 1, FEARG_1, ret_first_arg, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100878 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
879 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100880#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100881 f_rubyeval
882#else
883 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100884#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100885 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100886 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
887 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
888 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
889 {"screencol", 0, 0, 0, ret_number, f_screencol},
890 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
891 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
892 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200893 {"search", 1, 5, FEARG_1, ret_number, f_search},
Bram Moolenaare8f5ec02020-06-01 17:28:35 +0200894 {"searchcount", 0, 1, FEARG_1, ret_dict_any, f_searchcount},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100895 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
896 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
897 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200898 {"searchpos", 1, 5, FEARG_1, ret_list_number, f_searchpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100899 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
900 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
901 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
902 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
Bram Moolenaar08aac3c2020-08-28 21:04:24 +0200903 {"setcellwidths", 1, 1, FEARG_1, ret_void, f_setcellwidths},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100904 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
905 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
906 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
907 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
908 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
909 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
910 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
911 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
912 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
913 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
914 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
915 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
916 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
917 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100918 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200919#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100920 f_sha256
921#else
922 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100924 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100925 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
926 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100927 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
928 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
929 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
930 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
931 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
932 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
933 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
934 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
935 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200936 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100937 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
938 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200939 {"sort", 1, 3, FEARG_1, ret_first_arg, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100940 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
941 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
942 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
943 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100944 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
945 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
946 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
947 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100948 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100949 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
950 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100951 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100952 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
953 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
954 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
955 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
956 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100957 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200958#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100959 f_strftime
960#else
961 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200962#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100963 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100964 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
965 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
966 {"string", 1, 1, FEARG_1, ret_string, f_string},
967 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
Bram Moolenaar6c53fca2020-08-23 17:34:46 +0200968 {"strpart", 2, 4, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100969 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100970#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100971 f_strptime
972#else
973 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100974#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100975 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100976 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
977 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
978 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
979 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
980 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
981 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
982 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
983 {"synID", 3, 3, 0, ret_number, f_synID},
984 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
985 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
986 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
987 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
988 {"system", 1, 2, FEARG_1, ret_string, f_system},
989 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
990 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
991 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
992 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
993 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
994 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100995 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
996 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100997 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100998 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
999 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
1000 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
1001 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
1002 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001003#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001004 f_term_getansicolors
1005#else
1006 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001007#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001008 },
1009 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
1010 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
1011 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
1012 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
1013 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
1014 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
1015 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
1016 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
1017 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
1018 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
1019 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
1020 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
1021 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001022#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001023 f_term_setansicolors
1024#else
1025 NULL
1026#endif
1027 },
1028 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
1029 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
1030 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
1031 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
1032 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
1033 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaar0c0eddd2020-06-13 15:47:25 +02001034 {"terminalprops", 0, 0, 0, ret_dict_string, f_terminalprops},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001035 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
1036 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
1037 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
1038 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
1039 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
1040 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
1041 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
1042 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001043 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001044 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +02001045 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001046 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001047 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +02001048 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001049 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
1050 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
1051 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
1052 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001053 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +02001054#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +01001055 f_test_scrollbar
1056#else
1057 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +02001058#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001059 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001060 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
1061 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
1062 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
1063 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
Bram Moolenaar418f1df2020-08-12 21:34:49 +02001064 {"test_void", 0, 0, 0, ret_void, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001065 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
1066 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
1067 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
1068 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
1069 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001070 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
1071 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
1072 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +02001073 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001074 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001075 {"type", 1, 1, FEARG_1, ret_number, f_type},
1076 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
1077 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
1078 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
1079 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
1080 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
1081 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
1082 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
1083 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
1084 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
1085 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
1086 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
1087 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
1088 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
1089 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
1090 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
1091 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
1092 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
1093 {"wincol", 0, 0, 0, ret_number, f_wincol},
1094 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1095 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1096 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1097 {"winline", 0, 0, 0, ret_number, f_winline},
1098 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1099 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1100 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1101 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1102 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1103 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1104 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1105 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001106};
1107
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001108/*
1109 * Function given to ExpandGeneric() to obtain the list of internal
1110 * or user defined function names.
1111 */
1112 char_u *
1113get_function_name(expand_T *xp, int idx)
1114{
1115 static int intidx = -1;
1116 char_u *name;
1117
1118 if (idx == 0)
1119 intidx = -1;
1120 if (intidx < 0)
1121 {
1122 name = get_user_func_name(xp, idx);
1123 if (name != NULL)
1124 return name;
1125 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001126 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001127 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001128 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001129 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001130 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001131 STRCAT(IObuff, ")");
1132 return IObuff;
1133 }
1134
1135 return NULL;
1136}
1137
1138/*
1139 * Function given to ExpandGeneric() to obtain the list of internal or
1140 * user defined variable or function names.
1141 */
1142 char_u *
1143get_expr_name(expand_T *xp, int idx)
1144{
1145 static int intidx = -1;
1146 char_u *name;
1147
1148 if (idx == 0)
1149 intidx = -1;
1150 if (intidx < 0)
1151 {
1152 name = get_function_name(xp, idx);
1153 if (name != NULL)
1154 return name;
1155 }
1156 return get_user_var_name(xp, ++intidx);
1157}
1158
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001159/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001160 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001161 * Return index, or -1 if not found or "implemented" is TRUE and the function
1162 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001163 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001164 static int
1165find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001166{
1167 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001168 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001169 int cmp;
1170 int x;
1171
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001172 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001173
1174 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001175 while (first <= last)
1176 {
1177 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001178 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001179 if (cmp < 0)
1180 last = x - 1;
1181 else if (cmp > 0)
1182 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001183 else if (implemented && global_functions[x].f_func == NULL)
1184 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001185 else
1186 return x;
1187 }
1188 return -1;
1189}
1190
Bram Moolenaar15c47602020-03-26 22:16:48 +01001191/*
1192 * Find internal function "name" in table "global_functions".
1193 * Return index, or -1 if not found or the function is not implemented.
1194 */
1195 int
1196find_internal_func(char_u *name)
1197{
1198 return find_internal_func_opt(name, TRUE);
1199}
1200
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001201 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001202has_internal_func(char_u *name)
1203{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001204 return find_internal_func_opt(name, TRUE) >= 0;
1205}
1206
1207 static int
1208has_internal_func_name(char_u *name)
1209{
1210 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001211}
1212
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001213 char *
1214internal_func_name(int idx)
1215{
1216 return global_functions[idx].f_name;
1217}
1218
1219 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001220internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001221{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001222 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001223}
1224
1225/*
1226 * Check the argument count to use for internal function "idx".
Bram Moolenaar389df252020-07-09 21:20:47 +02001227 * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
1228 * first argument, 2 if method base is second argument, etc. 9 if method base
1229 * is last argument.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001230 */
1231 int
1232check_internal_func(int idx, int argcount)
1233{
1234 int res;
1235 char *name;
1236
1237 if (argcount < global_functions[idx].f_min_argc)
1238 res = FCERR_TOOFEW;
1239 else if (argcount > global_functions[idx].f_max_argc)
1240 res = FCERR_TOOMANY;
1241 else
Bram Moolenaar389df252020-07-09 21:20:47 +02001242 return global_functions[idx].f_argtype;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001243
1244 name = internal_func_name(idx);
1245 if (res == FCERR_TOOMANY)
1246 semsg(_(e_toomanyarg), name);
1247 else
1248 semsg(_(e_toofewarg), name);
Bram Moolenaar389df252020-07-09 21:20:47 +02001249 return -1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001250}
1251
Bram Moolenaarac92e252019-08-03 21:58:38 +02001252 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001253call_internal_func(
1254 char_u *name,
1255 int argcount,
1256 typval_T *argvars,
1257 typval_T *rettv)
1258{
1259 int i;
1260
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001261 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001262 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001263 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001264 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001265 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001266 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001267 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001268 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001269 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001270 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001271}
1272
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001273 void
1274call_internal_func_by_idx(
1275 int idx,
1276 typval_T *argvars,
1277 typval_T *rettv)
1278{
1279 global_functions[idx].f_func(argvars, rettv);
1280}
1281
Bram Moolenaarac92e252019-08-03 21:58:38 +02001282/*
1283 * Invoke a method for base->method().
1284 */
1285 int
1286call_internal_method(
1287 char_u *name,
1288 int argcount,
1289 typval_T *argvars,
1290 typval_T *rettv,
1291 typval_T *basetv)
1292{
1293 int i;
1294 int fi;
1295 typval_T argv[MAX_FUNC_ARGS + 1];
1296
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001297 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001298 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001299 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001300 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001301 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001302 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001303 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001304 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001305 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001306
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001307 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001308 {
1309 // base value goes last
1310 for (i = 0; i < argcount; ++i)
1311 argv[i] = argvars[i];
1312 argv[argcount] = *basetv;
1313 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001314 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001315 {
1316 // base value goes second
1317 argv[0] = argvars[0];
1318 argv[1] = *basetv;
1319 for (i = 1; i < argcount; ++i)
1320 argv[i + 1] = argvars[i];
1321 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001322 else if (global_functions[fi].f_argtype == FEARG_3)
1323 {
1324 // base value goes third
1325 argv[0] = argvars[0];
1326 argv[1] = argvars[1];
1327 argv[2] = *basetv;
1328 for (i = 2; i < argcount; ++i)
1329 argv[i + 1] = argvars[i];
1330 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001331 else if (global_functions[fi].f_argtype == FEARG_4)
1332 {
1333 // base value goes fourth
1334 argv[0] = argvars[0];
1335 argv[1] = argvars[1];
1336 argv[2] = argvars[2];
1337 argv[3] = *basetv;
1338 for (i = 3; i < argcount; ++i)
1339 argv[i + 1] = argvars[i];
1340 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001341 else
1342 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001343 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001344 argv[0] = *basetv;
1345 for (i = 0; i < argcount; ++i)
1346 argv[i + 1] = argvars[i];
1347 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001348 argv[argcount + 1].v_type = VAR_UNKNOWN;
1349
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001350 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001351 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001352}
1353
1354/*
1355 * Return TRUE for a non-zero Number and a non-empty String.
1356 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001357 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358non_zero_arg(typval_T *argvars)
1359{
1360 return ((argvars[0].v_type == VAR_NUMBER
1361 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001362 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001363 && argvars[0].vval.v_number == VVAL_TRUE)
1364 || (argvars[0].v_type == VAR_STRING
1365 && argvars[0].vval.v_string != NULL
1366 && *argvars[0].vval.v_string != NUL));
1367}
1368
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001369#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001370/*
1371 * Get the float value of "argvars[0]" into "f".
1372 * Returns FAIL when the argument is not a Number or Float.
1373 */
1374 static int
1375get_float_arg(typval_T *argvars, float_T *f)
1376{
1377 if (argvars[0].v_type == VAR_FLOAT)
1378 {
1379 *f = argvars[0].vval.v_float;
1380 return OK;
1381 }
1382 if (argvars[0].v_type == VAR_NUMBER)
1383 {
1384 *f = (float_T)argvars[0].vval.v_number;
1385 return OK;
1386 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001387 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001388 return FAIL;
1389}
1390
1391/*
1392 * "abs(expr)" function
1393 */
1394 static void
1395f_abs(typval_T *argvars, typval_T *rettv)
1396{
1397 if (argvars[0].v_type == VAR_FLOAT)
1398 {
1399 rettv->v_type = VAR_FLOAT;
1400 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1401 }
1402 else
1403 {
1404 varnumber_T n;
1405 int error = FALSE;
1406
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001407 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001408 if (error)
1409 rettv->vval.v_number = -1;
1410 else if (n > 0)
1411 rettv->vval.v_number = n;
1412 else
1413 rettv->vval.v_number = -n;
1414 }
1415}
1416
1417/*
1418 * "acos()" function
1419 */
1420 static void
1421f_acos(typval_T *argvars, typval_T *rettv)
1422{
1423 float_T f = 0.0;
1424
1425 rettv->v_type = VAR_FLOAT;
1426 if (get_float_arg(argvars, &f) == OK)
1427 rettv->vval.v_float = acos(f);
1428 else
1429 rettv->vval.v_float = 0.0;
1430}
1431#endif
1432
1433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 * "and(expr, expr)" function
1435 */
1436 static void
1437f_and(typval_T *argvars, typval_T *rettv)
1438{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001439 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1440 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001441}
1442
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001443#ifdef FEAT_FLOAT
1444/*
1445 * "asin()" function
1446 */
1447 static void
1448f_asin(typval_T *argvars, typval_T *rettv)
1449{
1450 float_T f = 0.0;
1451
1452 rettv->v_type = VAR_FLOAT;
1453 if (get_float_arg(argvars, &f) == OK)
1454 rettv->vval.v_float = asin(f);
1455 else
1456 rettv->vval.v_float = 0.0;
1457}
1458
1459/*
1460 * "atan()" function
1461 */
1462 static void
1463f_atan(typval_T *argvars, typval_T *rettv)
1464{
1465 float_T f = 0.0;
1466
1467 rettv->v_type = VAR_FLOAT;
1468 if (get_float_arg(argvars, &f) == OK)
1469 rettv->vval.v_float = atan(f);
1470 else
1471 rettv->vval.v_float = 0.0;
1472}
1473
1474/*
1475 * "atan2()" function
1476 */
1477 static void
1478f_atan2(typval_T *argvars, typval_T *rettv)
1479{
1480 float_T fx = 0.0, fy = 0.0;
1481
1482 rettv->v_type = VAR_FLOAT;
1483 if (get_float_arg(argvars, &fx) == OK
1484 && get_float_arg(&argvars[1], &fy) == OK)
1485 rettv->vval.v_float = atan2(fx, fy);
1486 else
1487 rettv->vval.v_float = 0.0;
1488}
1489#endif
1490
1491/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001492 * "balloon_show()" function
1493 */
1494#ifdef FEAT_BEVAL
1495 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001496f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1497{
1498 rettv->v_type = VAR_STRING;
1499 if (balloonEval != NULL)
1500 {
1501 if (balloonEval->msg == NULL)
1502 rettv->vval.v_string = NULL;
1503 else
1504 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1505 }
1506}
1507
1508 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001509f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1510{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001511 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001512 {
1513 if (argvars[0].v_type == VAR_LIST
1514# ifdef FEAT_GUI
1515 && !gui.in_use
1516# endif
1517 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001518 {
1519 list_T *l = argvars[0].vval.v_list;
1520
1521 // empty list removes the balloon
1522 post_balloon(balloonEval, NULL,
1523 l == NULL || l->lv_len == 0 ? NULL : l);
1524 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001525 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001526 {
1527 char_u *mesg = tv_get_string_chk(&argvars[0]);
1528
1529 if (mesg != NULL)
1530 // empty string removes the balloon
1531 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1532 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001533 }
1534}
1535
Bram Moolenaar669a8282017-11-19 20:13:05 +01001536# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001537 static void
1538f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1539{
1540 if (rettv_list_alloc(rettv) == OK)
1541 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001542 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001543
1544 if (msg != NULL)
1545 {
1546 pumitem_T *array;
1547 int size = split_message(msg, &array);
1548 int i;
1549
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001550 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001551 for (i = 1; i < size - 1; ++i)
1552 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001553 while (size > 0)
1554 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001555 vim_free(array);
1556 }
1557 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001558}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001559# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001560#endif
1561
1562/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001563 * Get the buffer from "arg" and give an error and return NULL if it is not
1564 * valid.
1565 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001566 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001567get_buf_arg(typval_T *arg)
1568{
1569 buf_T *buf;
1570
1571 ++emsg_off;
1572 buf = tv_get_buf(arg, FALSE);
1573 --emsg_off;
1574 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001575 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001576 return buf;
1577}
1578
1579/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580 * "byte2line(byte)" function
1581 */
1582 static void
1583f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1584{
1585#ifndef FEAT_BYTEOFF
1586 rettv->vval.v_number = -1;
1587#else
1588 long boff = 0;
1589
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001590 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001591 if (boff < 0)
1592 rettv->vval.v_number = -1;
1593 else
1594 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1595 (linenr_T)0, &boff);
1596#endif
1597}
1598
1599 static void
1600byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1601{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603 char_u *str;
1604 varnumber_T idx;
1605
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001606 str = tv_get_string_chk(&argvars[0]);
1607 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001608 rettv->vval.v_number = -1;
1609 if (str == NULL || idx < 0)
1610 return;
1611
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001612 t = str;
1613 for ( ; idx > 0; idx--)
1614 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001615 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616 return;
1617 if (enc_utf8 && comp)
1618 t += utf_ptr2len(t);
1619 else
1620 t += (*mb_ptr2len)(t);
1621 }
1622 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001623}
1624
1625/*
1626 * "byteidx()" function
1627 */
1628 static void
1629f_byteidx(typval_T *argvars, typval_T *rettv)
1630{
1631 byteidx(argvars, rettv, FALSE);
1632}
1633
1634/*
1635 * "byteidxcomp()" function
1636 */
1637 static void
1638f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1639{
1640 byteidx(argvars, rettv, TRUE);
1641}
1642
1643/*
1644 * "call(func, arglist [, dict])" function
1645 */
1646 static void
1647f_call(typval_T *argvars, typval_T *rettv)
1648{
1649 char_u *func;
1650 partial_T *partial = NULL;
1651 dict_T *selfdict = NULL;
1652
1653 if (argvars[1].v_type != VAR_LIST)
1654 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001655 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001656 return;
1657 }
1658 if (argvars[1].vval.v_list == NULL)
1659 return;
1660
1661 if (argvars[0].v_type == VAR_FUNC)
1662 func = argvars[0].vval.v_string;
1663 else if (argvars[0].v_type == VAR_PARTIAL)
1664 {
1665 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001666 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667 }
1668 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001669 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001670 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001671 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001672
1673 if (argvars[2].v_type != VAR_UNKNOWN)
1674 {
1675 if (argvars[2].v_type != VAR_DICT)
1676 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001677 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001678 return;
1679 }
1680 selfdict = argvars[2].vval.v_dict;
1681 }
1682
1683 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1684}
1685
1686#ifdef FEAT_FLOAT
1687/*
1688 * "ceil({float})" function
1689 */
1690 static void
1691f_ceil(typval_T *argvars, typval_T *rettv)
1692{
1693 float_T f = 0.0;
1694
1695 rettv->v_type = VAR_FLOAT;
1696 if (get_float_arg(argvars, &f) == OK)
1697 rettv->vval.v_float = ceil(f);
1698 else
1699 rettv->vval.v_float = 0.0;
1700}
1701#endif
1702
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001703/*
1704 * "changenr()" function
1705 */
1706 static void
1707f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1708{
1709 rettv->vval.v_number = curbuf->b_u_seq_cur;
1710}
1711
1712/*
1713 * "char2nr(string)" function
1714 */
1715 static void
1716f_char2nr(typval_T *argvars, typval_T *rettv)
1717{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001718 if (has_mbyte)
1719 {
1720 int utf8 = 0;
1721
1722 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar24f77502020-09-04 19:50:57 +02001723 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001724
1725 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001726 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001728 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001729 }
1730 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001731 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001732}
1733
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001734 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001735get_optional_window(typval_T *argvars, int idx)
1736{
1737 win_T *win = curwin;
1738
1739 if (argvars[idx].v_type != VAR_UNKNOWN)
1740 {
1741 win = find_win_by_nr_or_id(&argvars[idx]);
1742 if (win == NULL)
1743 {
1744 emsg(_(e_invalwindow));
1745 return NULL;
1746 }
1747 }
1748 return win;
1749}
1750
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001751/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001752 * "col(string)" function
1753 */
1754 static void
1755f_col(typval_T *argvars, typval_T *rettv)
1756{
1757 colnr_T col = 0;
1758 pos_T *fp;
1759 int fnum = curbuf->b_fnum;
1760
1761 fp = var2fpos(&argvars[0], FALSE, &fnum);
1762 if (fp != NULL && fnum == curbuf->b_fnum)
1763 {
1764 if (fp->col == MAXCOL)
1765 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001766 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001767 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1768 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1769 else
1770 col = MAXCOL;
1771 }
1772 else
1773 {
1774 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001775 // col(".") when the cursor is on the NUL at the end of the line
1776 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001777 if (virtual_active() && fp == &curwin->w_cursor)
1778 {
1779 char_u *p = ml_get_cursor();
1780
1781 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1782 curwin->w_virtcol - curwin->w_cursor.coladd))
1783 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001784 int l;
1785
1786 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1787 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001788 }
1789 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790 }
1791 }
1792 rettv->vval.v_number = col;
1793}
1794
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001795/*
1796 * "confirm(message, buttons[, default [, type]])" function
1797 */
1798 static void
1799f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1800{
1801#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1802 char_u *message;
1803 char_u *buttons = NULL;
1804 char_u buf[NUMBUFLEN];
1805 char_u buf2[NUMBUFLEN];
1806 int def = 1;
1807 int type = VIM_GENERIC;
1808 char_u *typestr;
1809 int error = FALSE;
1810
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001811 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001812 if (message == NULL)
1813 error = TRUE;
1814 if (argvars[1].v_type != VAR_UNKNOWN)
1815 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001816 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001817 if (buttons == NULL)
1818 error = TRUE;
1819 if (argvars[2].v_type != VAR_UNKNOWN)
1820 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001821 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822 if (argvars[3].v_type != VAR_UNKNOWN)
1823 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001824 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 if (typestr == NULL)
1826 error = TRUE;
1827 else
1828 {
1829 switch (TOUPPER_ASC(*typestr))
1830 {
1831 case 'E': type = VIM_ERROR; break;
1832 case 'Q': type = VIM_QUESTION; break;
1833 case 'I': type = VIM_INFO; break;
1834 case 'W': type = VIM_WARNING; break;
1835 case 'G': type = VIM_GENERIC; break;
1836 }
1837 }
1838 }
1839 }
1840 }
1841
1842 if (buttons == NULL || *buttons == NUL)
1843 buttons = (char_u *)_("&Ok");
1844
1845 if (!error)
1846 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1847 def, NULL, FALSE);
1848#endif
1849}
1850
1851/*
1852 * "copy()" function
1853 */
1854 static void
1855f_copy(typval_T *argvars, typval_T *rettv)
1856{
1857 item_copy(&argvars[0], rettv, FALSE, 0);
1858}
1859
1860#ifdef FEAT_FLOAT
1861/*
1862 * "cos()" function
1863 */
1864 static void
1865f_cos(typval_T *argvars, typval_T *rettv)
1866{
1867 float_T f = 0.0;
1868
1869 rettv->v_type = VAR_FLOAT;
1870 if (get_float_arg(argvars, &f) == OK)
1871 rettv->vval.v_float = cos(f);
1872 else
1873 rettv->vval.v_float = 0.0;
1874}
1875
1876/*
1877 * "cosh()" function
1878 */
1879 static void
1880f_cosh(typval_T *argvars, typval_T *rettv)
1881{
1882 float_T f = 0.0;
1883
1884 rettv->v_type = VAR_FLOAT;
1885 if (get_float_arg(argvars, &f) == OK)
1886 rettv->vval.v_float = cosh(f);
1887 else
1888 rettv->vval.v_float = 0.0;
1889}
1890#endif
1891
1892/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001893 * "cursor(lnum, col)" function, or
1894 * "cursor(list)"
1895 *
1896 * Moves the cursor to the specified line and column.
1897 * Returns 0 when the position could be set, -1 otherwise.
1898 */
1899 static void
1900f_cursor(typval_T *argvars, typval_T *rettv)
1901{
1902 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001903 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001904 int set_curswant = TRUE;
1905
1906 rettv->vval.v_number = -1;
1907 if (argvars[1].v_type == VAR_UNKNOWN)
1908 {
1909 pos_T pos;
1910 colnr_T curswant = -1;
1911
1912 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1913 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001914 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001915 return;
1916 }
1917 line = pos.lnum;
1918 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001919 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001920 if (curswant >= 0)
1921 {
1922 curwin->w_curswant = curswant - 1;
1923 set_curswant = FALSE;
1924 }
1925 }
1926 else
1927 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001928 line = tv_get_lnum(argvars);
1929 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001930 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001931 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001932 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001933 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001934 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935 if (line > 0)
1936 curwin->w_cursor.lnum = line;
1937 if (col > 0)
1938 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001939 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001940
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001941 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001943 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001944 if (has_mbyte)
1945 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001946
1947 curwin->w_set_curswant = set_curswant;
1948 rettv->vval.v_number = 0;
1949}
1950
Bram Moolenaar4f974752019-02-17 17:44:42 +01001951#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001952/*
1953 * "debugbreak()" function
1954 */
1955 static void
1956f_debugbreak(typval_T *argvars, typval_T *rettv)
1957{
1958 int pid;
1959
1960 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001961 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001962 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001963 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001964 else
1965 {
1966 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1967
1968 if (hProcess != NULL)
1969 {
1970 DebugBreakProcess(hProcess);
1971 CloseHandle(hProcess);
1972 rettv->vval.v_number = OK;
1973 }
1974 }
1975}
1976#endif
1977
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978/*
1979 * "deepcopy()" function
1980 */
1981 static void
1982f_deepcopy(typval_T *argvars, typval_T *rettv)
1983{
1984 int noref = 0;
1985 int copyID;
1986
1987 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar44b4a242020-09-05 17:18:28 +02001988 noref = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989 if (noref < 0 || noref > 1)
Bram Moolenaarbade44e2020-09-26 22:39:24 +02001990 semsg(_(e_using_number_as_bool_nr), noref);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991 else
1992 {
1993 copyID = get_copyID();
1994 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1995 }
1996}
1997
1998/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001999 * "did_filetype()" function
2000 */
2001 static void
2002f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2003{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002005}
2006
2007/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01002008 * "echoraw({expr})" function
2009 */
2010 static void
2011f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
2012{
2013 char_u *str = tv_get_string_chk(&argvars[0]);
2014
2015 if (str != NULL && *str != NUL)
2016 {
2017 out_str(str);
2018 out_flush();
2019 }
2020}
2021
2022/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023 * "empty({expr})" function
2024 */
2025 static void
2026f_empty(typval_T *argvars, typval_T *rettv)
2027{
2028 int n = FALSE;
2029
2030 switch (argvars[0].v_type)
2031 {
2032 case VAR_STRING:
2033 case VAR_FUNC:
2034 n = argvars[0].vval.v_string == NULL
2035 || *argvars[0].vval.v_string == NUL;
2036 break;
2037 case VAR_PARTIAL:
2038 n = FALSE;
2039 break;
2040 case VAR_NUMBER:
2041 n = argvars[0].vval.v_number == 0;
2042 break;
2043 case VAR_FLOAT:
2044#ifdef FEAT_FLOAT
2045 n = argvars[0].vval.v_float == 0.0;
2046 break;
2047#endif
2048 case VAR_LIST:
2049 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002050 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002051 break;
2052 case VAR_DICT:
2053 n = argvars[0].vval.v_dict == NULL
2054 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2055 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01002056 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002057 case VAR_SPECIAL:
2058 n = argvars[0].vval.v_number != VVAL_TRUE;
2059 break;
2060
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002061 case VAR_BLOB:
2062 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002063 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2064 break;
2065
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002066 case VAR_JOB:
2067#ifdef FEAT_JOB_CHANNEL
2068 n = argvars[0].vval.v_job == NULL
2069 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2070 break;
2071#endif
2072 case VAR_CHANNEL:
2073#ifdef FEAT_JOB_CHANNEL
2074 n = argvars[0].vval.v_channel == NULL
2075 || !channel_is_open(argvars[0].vval.v_channel);
2076 break;
2077#endif
2078 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002079 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002080 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01002081 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082 n = TRUE;
2083 break;
2084 }
2085
2086 rettv->vval.v_number = n;
2087}
2088
2089/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002090 * "environ()" function
2091 */
2092 static void
2093f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2094{
2095#if !defined(AMIGA)
2096 int i = 0;
2097 char_u *entry, *value;
2098# ifdef MSWIN
2099 extern wchar_t **_wenviron;
2100# else
2101 extern char **environ;
2102# endif
2103
2104 if (rettv_dict_alloc(rettv) != OK)
2105 return;
2106
2107# ifdef MSWIN
2108 if (*_wenviron == NULL)
2109 return;
2110# else
2111 if (*environ == NULL)
2112 return;
2113# endif
2114
2115 for (i = 0; ; ++i)
2116 {
2117# ifdef MSWIN
2118 short_u *p;
2119
2120 if ((p = (short_u *)_wenviron[i]) == NULL)
2121 return;
2122 entry = utf16_to_enc(p, NULL);
2123# else
2124 if ((entry = (char_u *)environ[i]) == NULL)
2125 return;
2126 entry = vim_strsave(entry);
2127# endif
2128 if (entry == NULL) // out of memory
2129 return;
2130 if ((value = vim_strchr(entry, '=')) == NULL)
2131 {
2132 vim_free(entry);
2133 continue;
2134 }
2135 *value++ = NUL;
2136 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2137 vim_free(entry);
2138 }
2139#endif
2140}
2141
2142/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002143 * "escape({string}, {chars})" function
2144 */
2145 static void
2146f_escape(typval_T *argvars, typval_T *rettv)
2147{
2148 char_u buf[NUMBUFLEN];
2149
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002150 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2151 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002152 rettv->v_type = VAR_STRING;
2153}
2154
2155/*
2156 * "eval()" function
2157 */
2158 static void
2159f_eval(typval_T *argvars, typval_T *rettv)
2160{
2161 char_u *s, *p;
2162
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002163 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 if (s != NULL)
2165 s = skipwhite(s);
2166
2167 p = s;
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02002168 if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 {
2170 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002171 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172 need_clr_eos = FALSE;
2173 rettv->v_type = VAR_NUMBER;
2174 rettv->vval.v_number = 0;
2175 }
2176 else if (*s != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02002177 semsg(_(e_trailing_arg), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178}
2179
2180/*
2181 * "eventhandler()" function
2182 */
2183 static void
2184f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2185{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002186 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002187}
2188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002189static garray_T redir_execute_ga;
2190
2191/*
2192 * Append "value[value_len]" to the execute() output.
2193 */
2194 void
2195execute_redir_str(char_u *value, int value_len)
2196{
2197 int len;
2198
2199 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002200 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002201 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002202 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002203 if (ga_grow(&redir_execute_ga, len) == OK)
2204 {
2205 mch_memmove((char *)redir_execute_ga.ga_data
2206 + redir_execute_ga.ga_len, value, len);
2207 redir_execute_ga.ga_len += len;
2208 }
2209}
2210
2211/*
2212 * Get next line from a list.
2213 * Called by do_cmdline() to get the next line.
2214 * Returns allocated string, or NULL for end of function.
2215 */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216 static char_u *
2217get_list_line(
2218 int c UNUSED,
2219 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002220 int indent UNUSED,
Bram Moolenaar66250c92020-08-20 15:02:42 +02002221 getline_opt_T options UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002222{
2223 listitem_T **p = (listitem_T **)cookie;
2224 listitem_T *item = *p;
2225 char_u buf[NUMBUFLEN];
2226 char_u *s;
2227
2228 if (item == NULL)
2229 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002230 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002231 *p = item->li_next;
2232 return s == NULL ? NULL : vim_strsave(s);
2233}
2234
2235/*
2236 * "execute()" function
2237 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002238 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002239execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002240{
2241 char_u *cmd = NULL;
2242 list_T *list = NULL;
2243 int save_msg_silent = msg_silent;
2244 int save_emsg_silent = emsg_silent;
2245 int save_emsg_noredir = emsg_noredir;
2246 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002247 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002248 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002249 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002250 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002251
2252 rettv->vval.v_string = NULL;
2253 rettv->v_type = VAR_STRING;
2254
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002255 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002257 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002258 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002259 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002260 return;
2261 ++list->lv_refcount;
2262 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002263 else if (argvars[arg_off].v_type == VAR_JOB
2264 || argvars[arg_off].v_type == VAR_CHANNEL)
2265 {
2266 emsg(_(e_inval_string));
2267 return;
2268 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 else
2270 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002271 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002272 if (cmd == NULL)
2273 return;
2274 }
2275
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002276 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002277 {
2278 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002279 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280
2281 if (s == NULL)
2282 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002283 if (*s == NUL)
2284 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002285 if (STRNCMP(s, "silent", 6) == 0)
2286 ++msg_silent;
2287 if (STRCMP(s, "silent!") == 0)
2288 {
2289 emsg_silent = TRUE;
2290 emsg_noredir = TRUE;
2291 }
2292 }
2293 else
2294 ++msg_silent;
2295
2296 if (redir_execute)
2297 save_ga = redir_execute_ga;
2298 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2299 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002300 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002301 if (!echo_output)
2302 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303
2304 if (cmd != NULL)
2305 do_cmdline_cmd(cmd);
2306 else
2307 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002308 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002309
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002310 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002311 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002312 do_cmdline(NULL, get_list_line, (void *)&item,
2313 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2314 --list->lv_refcount;
2315 }
2316
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002317 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002318 if (ga_grow(&redir_execute_ga, 1) == OK)
2319 {
2320 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2321 rettv->vval.v_string = redir_execute_ga.ga_data;
2322 }
2323 else
2324 {
2325 ga_clear(&redir_execute_ga);
2326 rettv->vval.v_string = NULL;
2327 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002328 msg_silent = save_msg_silent;
2329 emsg_silent = save_emsg_silent;
2330 emsg_noredir = save_emsg_noredir;
2331
2332 redir_execute = save_redir_execute;
2333 if (redir_execute)
2334 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002335 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002336
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002337 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002338 if (echo_output)
2339 // When not working silently: put it in column zero. A following
2340 // "echon" will overwrite the message, unavoidably.
2341 msg_col = 0;
2342 else
2343 // When working silently: Put it back where it was, since nothing
2344 // should have been written.
2345 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002346}
2347
2348/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002349 * "execute()" function
2350 */
2351 static void
2352f_execute(typval_T *argvars, typval_T *rettv)
2353{
2354 execute_common(argvars, rettv, 0);
2355}
2356
2357/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002358 * "exists()" function
2359 */
2360 static void
2361f_exists(typval_T *argvars, typval_T *rettv)
2362{
2363 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002366 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002367 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002368 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002369 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370 if (mch_getenv(p + 1) != NULL)
2371 n = TRUE;
2372 else
2373 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002374 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002375 p = expand_env_save(p);
2376 if (p != NULL && *p != '$')
2377 n = TRUE;
2378 vim_free(p);
2379 }
2380 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002381 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002382 {
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02002383 n = (eval_option(&p, NULL, TRUE) == OK);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002384 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002385 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002386 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002387 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002388 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002389 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002390 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002391 else if (*p == '?') // internal function only
2392 {
2393 n = has_internal_func_name(p + 1);
2394 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002395 else if (*p == ':')
2396 {
2397 n = cmd_exists(p + 1);
2398 }
2399 else if (*p == '#')
2400 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002401 if (p[1] == '#')
2402 n = autocmd_supported(p + 2);
2403 else
2404 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002405 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002406 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002407 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002408 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002409 }
2410
2411 rettv->vval.v_number = n;
2412}
2413
2414#ifdef FEAT_FLOAT
2415/*
2416 * "exp()" function
2417 */
2418 static void
2419f_exp(typval_T *argvars, typval_T *rettv)
2420{
2421 float_T f = 0.0;
2422
2423 rettv->v_type = VAR_FLOAT;
2424 if (get_float_arg(argvars, &f) == OK)
2425 rettv->vval.v_float = exp(f);
2426 else
2427 rettv->vval.v_float = 0.0;
2428}
2429#endif
2430
2431/*
2432 * "expand()" function
2433 */
2434 static void
2435f_expand(typval_T *argvars, typval_T *rettv)
2436{
2437 char_u *s;
2438 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002439 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2441 expand_T xpc;
2442 int error = FALSE;
2443 char_u *result;
Bram Moolenaar8f187fc2020-09-26 18:47:11 +02002444#ifdef BACKSLASH_IN_FILENAME
2445 char_u *p_csl_save = p_csl;
2446
2447 // avoid using 'completeslash' here
2448 p_csl = empty_option;
2449#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450
2451 rettv->v_type = VAR_STRING;
2452 if (argvars[1].v_type != VAR_UNKNOWN
2453 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02002454 && tv_get_bool_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002455 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002456 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002458 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 if (*s == '%' || *s == '#' || *s == '<')
2460 {
2461 ++emsg_off;
2462 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2463 --emsg_off;
2464 if (rettv->v_type == VAR_LIST)
2465 {
2466 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2467 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002468 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 }
2470 else
2471 rettv->vval.v_string = result;
2472 }
2473 else
2474 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002475 // When the optional second argument is non-zero, don't remove matches
2476 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002477 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02002478 && tv_get_bool_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002479 options |= WILD_KEEP_ALL;
2480 if (!error)
2481 {
2482 ExpandInit(&xpc);
2483 xpc.xp_context = EXPAND_FILES;
2484 if (p_wic)
2485 options += WILD_ICASE;
2486 if (rettv->v_type == VAR_STRING)
2487 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2488 options, WILD_ALL);
2489 else if (rettv_list_alloc(rettv) != FAIL)
2490 {
2491 int i;
2492
2493 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2494 for (i = 0; i < xpc.xp_numfiles; i++)
2495 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2496 ExpandCleanup(&xpc);
2497 }
2498 }
2499 else
2500 rettv->vval.v_string = NULL;
2501 }
Bram Moolenaar8f187fc2020-09-26 18:47:11 +02002502#ifdef BACKSLASH_IN_FILENAME
2503 p_csl = p_csl_save;
2504#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002505}
2506
2507/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002508 * "expandcmd()" function
2509 * Expand all the special characters in a command string.
2510 */
2511 static void
2512f_expandcmd(typval_T *argvars, typval_T *rettv)
2513{
2514 exarg_T eap;
2515 char_u *cmdstr;
2516 char *errormsg = NULL;
2517
2518 rettv->v_type = VAR_STRING;
2519 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2520
2521 memset(&eap, 0, sizeof(eap));
2522 eap.cmd = cmdstr;
2523 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002524 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002525 eap.usefilter = FALSE;
2526 eap.nextcmd = NULL;
2527 eap.cmdidx = CMD_USER;
2528
2529 expand_filename(&eap, &cmdstr, &errormsg);
2530 if (errormsg != NULL && *errormsg != NUL)
2531 emsg(errormsg);
2532
2533 rettv->vval.v_string = cmdstr;
2534}
2535
2536/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 * "feedkeys()" function
2538 */
2539 static void
2540f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2541{
2542 int remap = TRUE;
2543 int insert = FALSE;
2544 char_u *keys, *flags;
2545 char_u nbuf[NUMBUFLEN];
2546 int typed = FALSE;
2547 int execute = FALSE;
2548 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002549 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002550 char_u *keys_esc;
2551
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002552 // This is not allowed in the sandbox. If the commands would still be
2553 // executed in the sandbox it would be OK, but it probably happens later,
2554 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002555 if (check_secure())
2556 return;
2557
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002558 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002559
2560 if (argvars[1].v_type != VAR_UNKNOWN)
2561 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002562 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563 for ( ; *flags != NUL; ++flags)
2564 {
2565 switch (*flags)
2566 {
2567 case 'n': remap = FALSE; break;
2568 case 'm': remap = TRUE; break;
2569 case 't': typed = TRUE; break;
2570 case 'i': insert = TRUE; break;
2571 case 'x': execute = TRUE; break;
2572 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002573 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 }
2575 }
2576 }
2577
2578 if (*keys != NUL || execute)
2579 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002580 // Need to escape K_SPECIAL and CSI before putting the string in the
2581 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 keys_esc = vim_strsave_escape_csi(keys);
2583 if (keys_esc != NULL)
2584 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002585 if (lowlevel)
2586 {
2587#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002588 int idx;
2589 int len = (int)STRLEN(keys);
2590
2591 for (idx = 0; idx < len; ++idx)
2592 {
2593 // if a CTRL-C was typed, set got_int, similar to what
2594 // happens in fill_input_buf()
2595 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2596 got_int = TRUE;
2597 add_to_input_buf(keys + idx, 1);
2598 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002599#else
2600 emsg(_("E980: lowlevel input not supported"));
2601#endif
2602 }
2603 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002604 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002605 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002606 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002607 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002608#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002609 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002610#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002611 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002612 typebuf_was_filled = TRUE;
2613 }
2614 vim_free(keys_esc);
2615
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002616 if (execute)
2617 {
2618 int save_msg_scroll = msg_scroll;
2619
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002620 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 msg_scroll = FALSE;
2622
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002623 if (!dangerous)
Bram Moolenaar4934ad02020-09-28 22:29:58 +02002624 {
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002625 ++ex_normal_busy;
Bram Moolenaar4934ad02020-09-28 22:29:58 +02002626 ++in_feedkeys;
2627 }
Bram Moolenaar905dd902019-04-07 14:21:47 +02002628 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002629 if (!dangerous)
Bram Moolenaar189832b2020-09-23 12:29:11 +02002630 {
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002631 --ex_normal_busy;
Bram Moolenaar4934ad02020-09-28 22:29:58 +02002632 --in_feedkeys;
Bram Moolenaar189832b2020-09-23 12:29:11 +02002633 }
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002634
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002635 msg_scroll |= save_msg_scroll;
2636 }
2637 }
2638 }
2639}
2640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002641#ifdef FEAT_FLOAT
2642/*
2643 * "float2nr({float})" function
2644 */
2645 static void
2646f_float2nr(typval_T *argvars, typval_T *rettv)
2647{
2648 float_T f = 0.0;
2649
2650 if (get_float_arg(argvars, &f) == OK)
2651 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002652 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002653 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002654 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002655 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 else
2657 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002658 }
2659}
2660
2661/*
2662 * "floor({float})" function
2663 */
2664 static void
2665f_floor(typval_T *argvars, typval_T *rettv)
2666{
2667 float_T f = 0.0;
2668
2669 rettv->v_type = VAR_FLOAT;
2670 if (get_float_arg(argvars, &f) == OK)
2671 rettv->vval.v_float = floor(f);
2672 else
2673 rettv->vval.v_float = 0.0;
2674}
2675
2676/*
2677 * "fmod()" function
2678 */
2679 static void
2680f_fmod(typval_T *argvars, typval_T *rettv)
2681{
2682 float_T fx = 0.0, fy = 0.0;
2683
2684 rettv->v_type = VAR_FLOAT;
2685 if (get_float_arg(argvars, &fx) == OK
2686 && get_float_arg(&argvars[1], &fy) == OK)
2687 rettv->vval.v_float = fmod(fx, fy);
2688 else
2689 rettv->vval.v_float = 0.0;
2690}
2691#endif
2692
2693/*
2694 * "fnameescape({string})" function
2695 */
2696 static void
2697f_fnameescape(typval_T *argvars, typval_T *rettv)
2698{
2699 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002700 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002701 rettv->v_type = VAR_STRING;
2702}
2703
2704/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705 * "foreground()" function
2706 */
2707 static void
2708f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2709{
2710#ifdef FEAT_GUI
2711 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002712 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002714 return;
2715 }
2716#endif
2717#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002718 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719#endif
2720}
2721
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002722 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002723common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002724{
2725 char_u *s;
2726 char_u *name;
2727 int use_string = FALSE;
2728 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002729 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002730 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002731
2732 if (argvars[0].v_type == VAR_FUNC)
2733 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002734 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002735 s = argvars[0].vval.v_string;
2736 }
2737 else if (argvars[0].v_type == VAR_PARTIAL
2738 && argvars[0].vval.v_partial != NULL)
2739 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002740 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002741 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002742 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002743 }
2744 else
2745 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002746 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002747 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002748 use_string = TRUE;
2749 }
2750
Bram Moolenaar843b8842016-08-21 14:36:15 +02002751 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002752 {
2753 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002754 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002755 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2756 if (*name != NUL)
2757 s = NULL;
2758 }
2759
Bram Moolenaar843b8842016-08-21 14:36:15 +02002760 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2761 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002762 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002763 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002764 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002765 ? find_func(trans_name, is_global, NULL) == NULL
2766 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002767 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002768 else
2769 {
2770 int dict_idx = 0;
2771 int arg_idx = 0;
2772 list_T *list = NULL;
2773
2774 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2775 {
2776 char sid_buf[25];
2777 int off = *s == 's' ? 2 : 5;
2778
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002779 // Expand s: and <SID> into <SNR>nr_, so that the function can
2780 // also be called from another script. Using trans_function_name()
2781 // would also work, but some plugins depend on the name being
2782 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002783 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002784 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002785 if (name != NULL)
2786 {
2787 STRCPY(name, sid_buf);
2788 STRCAT(name, s + off);
2789 }
2790 }
2791 else
2792 name = vim_strsave(s);
2793
2794 if (argvars[1].v_type != VAR_UNKNOWN)
2795 {
2796 if (argvars[2].v_type != VAR_UNKNOWN)
2797 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002798 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002799 arg_idx = 1;
2800 dict_idx = 2;
2801 }
2802 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002803 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002804 dict_idx = 1;
2805 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002806 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002807 arg_idx = 1;
2808 if (dict_idx > 0)
2809 {
2810 if (argvars[dict_idx].v_type != VAR_DICT)
2811 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002812 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002813 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002814 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002815 }
2816 if (argvars[dict_idx].vval.v_dict == NULL)
2817 dict_idx = 0;
2818 }
2819 if (arg_idx > 0)
2820 {
2821 if (argvars[arg_idx].v_type != VAR_LIST)
2822 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002823 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002824 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002825 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002826 }
2827 list = argvars[arg_idx].vval.v_list;
2828 if (list == NULL || list->lv_len == 0)
2829 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002830 else if (list->lv_len > MAX_FUNC_ARGS)
2831 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002832 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002833 vim_free(name);
2834 goto theend;
2835 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002836 }
2837 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002838 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002839 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002840 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002841
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002842 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002843 if (pt == NULL)
2844 vim_free(name);
2845 else
2846 {
2847 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2848 {
2849 listitem_T *li;
2850 int i = 0;
2851 int arg_len = 0;
2852 int lv_len = 0;
2853
2854 if (arg_pt != NULL)
2855 arg_len = arg_pt->pt_argc;
2856 if (list != NULL)
2857 lv_len = list->lv_len;
2858 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002859 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860 if (pt->pt_argv == NULL)
2861 {
2862 vim_free(pt);
2863 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002864 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002865 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002866 for (i = 0; i < arg_len; i++)
2867 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2868 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002869 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002870 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002871 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002872 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002873 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002874 }
2875
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002876 // For "function(dict.func, [], dict)" and "func" is a partial
2877 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878 if (dict_idx > 0)
2879 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002880 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002881 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2882 ++pt->pt_dict->dv_refcount;
2883 }
2884 else if (arg_pt != NULL)
2885 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002886 // If the dict was bound automatically the result is also
2887 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002888 pt->pt_dict = arg_pt->pt_dict;
2889 pt->pt_auto = arg_pt->pt_auto;
2890 if (pt->pt_dict != NULL)
2891 ++pt->pt_dict->dv_refcount;
2892 }
2893
2894 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002895 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2896 {
2897 pt->pt_func = arg_pt->pt_func;
2898 func_ptr_ref(pt->pt_func);
2899 vim_free(name);
2900 }
2901 else if (is_funcref)
2902 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002903 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002904 func_ptr_ref(pt->pt_func);
2905 vim_free(name);
2906 }
2907 else
2908 {
2909 pt->pt_name = name;
2910 func_ref(name);
2911 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 }
2913 rettv->v_type = VAR_PARTIAL;
2914 rettv->vval.v_partial = pt;
2915 }
2916 else
2917 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002918 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002919 rettv->v_type = VAR_FUNC;
2920 rettv->vval.v_string = name;
2921 func_ref(name);
2922 }
2923 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002924theend:
2925 vim_free(trans_name);
2926}
2927
2928/*
2929 * "funcref()" function
2930 */
2931 static void
2932f_funcref(typval_T *argvars, typval_T *rettv)
2933{
2934 common_function(argvars, rettv, TRUE);
2935}
2936
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002937 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002938ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002939{
2940 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2941 return &t_func_any;
Bram Moolenaar5e654232020-09-16 15:22:00 +02002942 return &t_func_unknown;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002943}
2944
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002945/*
2946 * "function()" function
2947 */
2948 static void
2949f_function(typval_T *argvars, typval_T *rettv)
2950{
2951 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002952}
2953
2954/*
2955 * "garbagecollect()" function
2956 */
2957 static void
2958f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2959{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002960 // This is postponed until we are back at the toplevel, because we may be
2961 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002962 want_garbage_collect = TRUE;
2963
Bram Moolenaar2df47312020-09-05 17:30:44 +02002964 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002965 garbage_collect_at_exit = TRUE;
2966}
2967
2968/*
2969 * "get()" function
2970 */
2971 static void
2972f_get(typval_T *argvars, typval_T *rettv)
2973{
2974 listitem_T *li;
2975 list_T *l;
2976 dictitem_T *di;
2977 dict_T *d;
2978 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002979 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002980
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002981 if (argvars[0].v_type == VAR_BLOB)
2982 {
2983 int error = FALSE;
2984 int idx = tv_get_number_chk(&argvars[1], &error);
2985
2986 if (!error)
2987 {
2988 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002989 if (idx < 0)
2990 idx = blob_len(argvars[0].vval.v_blob) + idx;
2991 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2992 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002993 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002994 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002995 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002996 tv = rettv;
2997 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002998 }
2999 }
3000 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003001 {
3002 if ((l = argvars[0].vval.v_list) != NULL)
3003 {
3004 int error = FALSE;
3005
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003006 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003007 if (!error && li != NULL)
3008 tv = &li->li_tv;
3009 }
3010 }
3011 else if (argvars[0].v_type == VAR_DICT)
3012 {
3013 if ((d = argvars[0].vval.v_dict) != NULL)
3014 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003015 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016 if (di != NULL)
3017 tv = &di->di_tv;
3018 }
3019 }
3020 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3021 {
3022 partial_T *pt;
3023 partial_T fref_pt;
3024
3025 if (argvars[0].v_type == VAR_PARTIAL)
3026 pt = argvars[0].vval.v_partial;
3027 else
3028 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02003029 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003030 fref_pt.pt_name = argvars[0].vval.v_string;
3031 pt = &fref_pt;
3032 }
3033
3034 if (pt != NULL)
3035 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003036 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003037 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038
3039 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3040 {
3041 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003042 n = partial_name(pt);
3043 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003044 rettv->vval.v_string = NULL;
3045 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003046 {
3047 rettv->vval.v_string = vim_strsave(n);
3048 if (rettv->v_type == VAR_FUNC)
3049 func_ref(rettv->vval.v_string);
3050 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003051 }
3052 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003053 {
3054 what_is_dict = TRUE;
3055 if (pt->pt_dict != NULL)
3056 rettv_dict_set(rettv, pt->pt_dict);
3057 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 else if (STRCMP(what, "args") == 0)
3059 {
3060 rettv->v_type = VAR_LIST;
3061 if (rettv_list_alloc(rettv) == OK)
3062 {
3063 int i;
3064
3065 for (i = 0; i < pt->pt_argc; ++i)
3066 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3067 }
3068 }
3069 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003070 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003071
3072 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3073 // third argument
3074 if (!what_is_dict)
3075 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 }
3077 }
3078 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003079 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003080
3081 if (tv == NULL)
3082 {
3083 if (argvars[2].v_type != VAR_UNKNOWN)
3084 copy_tv(&argvars[2], rettv);
3085 }
3086 else
3087 copy_tv(tv, rettv);
3088}
3089
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003090/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003091 * "getchangelist()" function
3092 */
3093 static void
3094f_getchangelist(typval_T *argvars, typval_T *rettv)
3095{
3096#ifdef FEAT_JUMPLIST
3097 buf_T *buf;
3098 int i;
3099 list_T *l;
3100 dict_T *d;
3101#endif
3102
3103 if (rettv_list_alloc(rettv) != OK)
3104 return;
3105
3106#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003107 if (argvars[0].v_type == VAR_UNKNOWN)
3108 buf = curbuf;
3109 else
Bram Moolenaara5d38412020-09-02 21:02:35 +02003110 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003111 if (buf == NULL)
3112 return;
3113
3114 l = list_alloc();
3115 if (l == NULL)
3116 return;
3117
3118 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3119 return;
3120 /*
3121 * The current window change list index tracks only the position in the
3122 * current buffer change list. For other buffers, use the change list
3123 * length as the current index.
3124 */
3125 list_append_number(rettv->vval.v_list,
3126 (varnumber_T)((buf == curwin->w_buffer)
3127 ? curwin->w_changelistidx : buf->b_changelistlen));
3128
3129 for (i = 0; i < buf->b_changelistlen; ++i)
3130 {
3131 if (buf->b_changelist[i].lnum == 0)
3132 continue;
3133 if ((d = dict_alloc()) == NULL)
3134 return;
3135 if (list_append_dict(l, d) == FAIL)
3136 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003137 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3138 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003139 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003140 }
3141#endif
3142}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003143
3144/*
3145 * "getcharsearch()" function
3146 */
3147 static void
3148f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3149{
3150 if (rettv_dict_alloc(rettv) != FAIL)
3151 {
3152 dict_T *dict = rettv->vval.v_dict;
3153
Bram Moolenaare0be1672018-07-08 16:50:37 +02003154 dict_add_string(dict, "char", last_csearch());
3155 dict_add_number(dict, "forward", last_csearch_forward());
3156 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003157 }
3158}
3159
3160/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003161 * "getenv()" function
3162 */
3163 static void
3164f_getenv(typval_T *argvars, typval_T *rettv)
3165{
3166 int mustfree = FALSE;
3167 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3168
3169 if (p == NULL)
3170 {
3171 rettv->v_type = VAR_SPECIAL;
3172 rettv->vval.v_number = VVAL_NULL;
3173 return;
3174 }
3175 if (!mustfree)
3176 p = vim_strsave(p);
3177 rettv->vval.v_string = p;
3178 rettv->v_type = VAR_STRING;
3179}
3180
3181/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003182 * "getfontname()" function
3183 */
3184 static void
3185f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3186{
3187 rettv->v_type = VAR_STRING;
3188 rettv->vval.v_string = NULL;
3189#ifdef FEAT_GUI
3190 if (gui.in_use)
3191 {
3192 GuiFont font;
3193 char_u *name = NULL;
3194
3195 if (argvars[0].v_type == VAR_UNKNOWN)
3196 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003197 // Get the "Normal" font. Either the name saved by
3198 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003199 font = gui.norm_font;
3200 name = hl_get_font_name();
3201 }
3202 else
3203 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003204 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003205 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003206 return;
3207 font = gui_mch_get_font(name, FALSE);
3208 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003209 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003210 }
3211 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3212 if (argvars[0].v_type != VAR_UNKNOWN)
3213 gui_mch_free_font(font);
3214 }
3215#endif
3216}
3217
3218/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003219 * "getjumplist()" function
3220 */
3221 static void
3222f_getjumplist(typval_T *argvars, typval_T *rettv)
3223{
3224#ifdef FEAT_JUMPLIST
3225 win_T *wp;
3226 int i;
3227 list_T *l;
3228 dict_T *d;
3229#endif
3230
3231 if (rettv_list_alloc(rettv) != OK)
3232 return;
3233
3234#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003235 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003236 if (wp == NULL)
3237 return;
3238
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003239 cleanup_jumplist(wp, TRUE);
3240
Bram Moolenaar4f505882018-02-10 21:06:32 +01003241 l = list_alloc();
3242 if (l == NULL)
3243 return;
3244
3245 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3246 return;
3247 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3248
3249 for (i = 0; i < wp->w_jumplistlen; ++i)
3250 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003251 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3252 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003253 if ((d = dict_alloc()) == NULL)
3254 return;
3255 if (list_append_dict(l, d) == FAIL)
3256 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003257 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3258 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003259 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003260 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003261 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003262 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003263 }
3264#endif
3265}
3266
3267/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268 * "getpid()" function
3269 */
3270 static void
3271f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3272{
3273 rettv->vval.v_number = mch_get_pid();
3274}
3275
3276 static void
3277getpos_both(
3278 typval_T *argvars,
3279 typval_T *rettv,
3280 int getcurpos)
3281{
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003282 pos_T *fp = NULL;
3283 win_T *wp = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003284 list_T *l;
3285 int fnum = -1;
3286
3287 if (rettv_list_alloc(rettv) == OK)
3288 {
3289 l = rettv->vval.v_list;
3290 if (getcurpos)
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003291 {
3292 if (argvars[0].v_type != VAR_UNKNOWN)
3293 {
3294 wp = find_win_by_nr_or_id(&argvars[0]);
3295 if (wp != NULL)
3296 fp = &wp->w_cursor;
3297 }
3298 else
3299 fp = &curwin->w_cursor;
3300 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301 else
3302 fp = var2fpos(&argvars[0], TRUE, &fnum);
3303 if (fnum != -1)
3304 list_append_number(l, (varnumber_T)fnum);
3305 else
3306 list_append_number(l, (varnumber_T)0);
3307 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3308 : (varnumber_T)0);
3309 list_append_number(l, (fp != NULL)
3310 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3311 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003312 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003313 (varnumber_T)0);
3314 if (getcurpos)
3315 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003316 int save_set_curswant = curwin->w_set_curswant;
3317 colnr_T save_curswant = curwin->w_curswant;
3318 colnr_T save_virtcol = curwin->w_virtcol;
3319
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003320 if (wp == curwin)
3321 update_curswant();
3322 list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
3323 ? (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003324
3325 // Do not change "curswant", as it is unexpected that a get
3326 // function has a side effect.
Bram Moolenaar99ca9c42020-09-22 21:55:41 +02003327 if (wp == curwin && save_set_curswant)
Bram Moolenaar19a66852019-03-07 11:25:32 +01003328 {
3329 curwin->w_set_curswant = save_set_curswant;
3330 curwin->w_curswant = save_curswant;
3331 curwin->w_virtcol = save_virtcol;
3332 curwin->w_valid &= ~VALID_VIRTCOL;
3333 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003334 }
3335 }
3336 else
3337 rettv->vval.v_number = FALSE;
3338}
3339
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003340/*
3341 * "getcurpos()" function
3342 */
3343 static void
3344f_getcurpos(typval_T *argvars, typval_T *rettv)
3345{
3346 getpos_both(argvars, rettv, TRUE);
3347}
3348
3349/*
3350 * "getpos(string)" function
3351 */
3352 static void
3353f_getpos(typval_T *argvars, typval_T *rettv)
3354{
3355 getpos_both(argvars, rettv, FALSE);
3356}
3357
3358/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003359 * "getreg()" function
3360 */
3361 static void
3362f_getreg(typval_T *argvars, typval_T *rettv)
3363{
3364 char_u *strregname;
3365 int regname;
3366 int arg2 = FALSE;
3367 int return_list = FALSE;
3368 int error = FALSE;
3369
3370 if (argvars[0].v_type != VAR_UNKNOWN)
3371 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003372 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003373 error = strregname == NULL;
3374 if (argvars[1].v_type != VAR_UNKNOWN)
3375 {
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02003376 arg2 = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02003378 return_list = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003379 }
3380 }
3381 else
3382 strregname = get_vim_var_str(VV_REG);
3383
3384 if (error)
3385 return;
3386
3387 regname = (strregname == NULL ? '"' : *strregname);
3388 if (regname == 0)
3389 regname = '"';
3390
3391 if (return_list)
3392 {
3393 rettv->v_type = VAR_LIST;
3394 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3395 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3396 if (rettv->vval.v_list == NULL)
3397 (void)rettv_list_alloc(rettv);
3398 else
3399 ++rettv->vval.v_list->lv_refcount;
3400 }
3401 else
3402 {
3403 rettv->v_type = VAR_STRING;
3404 rettv->vval.v_string = get_reg_contents(regname,
3405 arg2 ? GREG_EXPR_SRC : 0);
3406 }
3407}
3408
3409/*
3410 * "getregtype()" function
3411 */
3412 static void
3413f_getregtype(typval_T *argvars, typval_T *rettv)
3414{
3415 char_u *strregname;
3416 int regname;
3417 char_u buf[NUMBUFLEN + 2];
3418 long reglen = 0;
3419
3420 if (argvars[0].v_type != VAR_UNKNOWN)
3421 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003422 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003423 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003424 {
3425 rettv->v_type = VAR_STRING;
3426 rettv->vval.v_string = NULL;
3427 return;
3428 }
3429 }
3430 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003431 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003432 strregname = get_vim_var_str(VV_REG);
3433
3434 regname = (strregname == NULL ? '"' : *strregname);
3435 if (regname == 0)
3436 regname = '"';
3437
3438 buf[0] = NUL;
3439 buf[1] = NUL;
3440 switch (get_reg_type(regname, &reglen))
3441 {
3442 case MLINE: buf[0] = 'V'; break;
3443 case MCHAR: buf[0] = 'v'; break;
3444 case MBLOCK:
3445 buf[0] = Ctrl_V;
3446 sprintf((char *)buf + 1, "%ld", reglen + 1);
3447 break;
3448 }
3449 rettv->v_type = VAR_STRING;
3450 rettv->vval.v_string = vim_strsave(buf);
3451}
3452
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003453/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003454 * "gettagstack()" function
3455 */
3456 static void
3457f_gettagstack(typval_T *argvars, typval_T *rettv)
3458{
3459 win_T *wp = curwin; // default is current window
3460
3461 if (rettv_dict_alloc(rettv) != OK)
3462 return;
3463
3464 if (argvars[0].v_type != VAR_UNKNOWN)
3465 {
3466 wp = find_win_by_nr_or_id(&argvars[0]);
3467 if (wp == NULL)
3468 return;
3469 }
3470
3471 get_tagstack(wp, rettv->vval.v_dict);
3472}
3473
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +02003474/*
3475 * "gettext()" function
3476 */
3477 static void
3478f_gettext(typval_T *argvars, typval_T *rettv)
3479{
3480 if (argvars[0].v_type != VAR_STRING
3481 || argvars[0].vval.v_string == NULL
3482 || *argvars[0].vval.v_string == NUL)
3483 {
3484 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
3485 }
3486 else
3487 {
3488 rettv->v_type = VAR_STRING;
3489 rettv->vval.v_string = vim_strsave(
3490 (char_u *)_(argvars[0].vval.v_string));
3491 }
3492}
3493
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003494// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003495#include "version.h"
3496
3497/*
3498 * "has()" function
3499 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003500 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003501f_has(typval_T *argvars, typval_T *rettv)
3502{
3503 int i;
3504 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003505 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003507 typedef struct {
3508 char *name;
3509 short present;
3510 } has_item_T;
3511 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003512 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003513 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003515 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003516#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003517 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003518#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003519 },
3520 {"arp",
3521#if defined(AMIGA) && defined(FEAT_ARP)
3522 1
3523#else
3524 0
3525#endif
3526 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003527 {"haiku",
3528#ifdef __HAIKU__
3529 1
3530#else
3531 0
3532#endif
3533 },
3534 {"bsd",
3535#if defined(BSD) && !defined(MACOS_X)
3536 1
3537#else
3538 0
3539#endif
3540 },
3541 {"hpux",
3542#ifdef hpux
3543 1
3544#else
3545 0
3546#endif
3547 },
3548 {"linux",
3549#ifdef __linux__
3550 1
3551#else
3552 0
3553#endif
3554 },
3555 {"mac", // Mac OS X (and, once, Mac OS Classic)
3556#ifdef MACOS_X
3557 1
3558#else
3559 0
3560#endif
3561 },
3562 {"osx", // Mac OS X
3563#ifdef MACOS_X
3564 1
3565#else
3566 0
3567#endif
3568 },
3569 {"macunix", // Mac OS X, with the darwin feature
3570#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3571 1
3572#else
3573 0
3574#endif
3575 },
3576 {"osxdarwin", // synonym for macunix
3577#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3578 1
3579#else
3580 0
3581#endif
3582 },
3583 {"qnx",
3584#ifdef __QNX__
3585 1
3586#else
3587 0
3588#endif
3589 },
3590 {"sun",
3591#ifdef SUN_SYSTEM
3592 1
3593#else
3594 0
3595#endif
3596 },
3597 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003598#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003599 1
3600#else
3601 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003603 },
3604 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003606 1
3607#else
3608 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003609#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003610 },
3611 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003612#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003613 1
3614#else
3615 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003616#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003617 },
3618 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003619#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003620 1
3621#else
3622 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003623#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003624 },
3625 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003626#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003627 1
3628#else
3629 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003630#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003631 },
3632 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003633#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003634 1
3635#else
3636 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003638 },
3639 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003640#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003641 1
3642#else
3643 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003645 },
3646 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003648 1
3649#else
3650 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003652 },
3653 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003655 1
3656#else
3657 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003658#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003659 },
3660 {"autocmd", 1},
3661 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003662#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003663 1
3664#else
3665 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003666#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003667 },
3668 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003669#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003670 1
3671#else
3672 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003673#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003674 },
3675 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003676#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003677 1
3678#else
3679 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003680#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003681 },
3682 {"balloon_multiline",
3683#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3684 // MS-Windows requires runtime check, see below
3685 1
3686#else
3687 0
3688#endif
3689 },
3690 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003691#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003692 1
3693#else
3694 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003695#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003696 },
3697 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003698#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003699 1
3700#else
3701 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003702#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003703 },
3704 {"all_builtin_terms",
3705#if defined(ALL_BUILTIN_TCAPS)
3706 1
3707#else
3708 0
3709#endif
3710 },
3711 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003712#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003713 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003715 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003716#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003717 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003718#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003719 },
3720 {"byte_offset",
3721#ifdef FEAT_BYTEOFF
3722 1
3723#else
3724 0
3725#endif
3726 },
3727 {"channel",
3728#ifdef FEAT_JOB_CHANNEL
3729 1
3730#else
3731 0
3732#endif
3733 },
3734 {"cindent",
3735#ifdef FEAT_CINDENT
3736 1
3737#else
3738 0
3739#endif
3740 },
3741 {"clientserver",
3742#ifdef FEAT_CLIENTSERVER
3743 1
3744#else
3745 0
3746#endif
3747 },
3748 {"clipboard",
3749#ifdef FEAT_CLIPBOARD
3750 1
3751#else
3752 0
3753#endif
3754 },
3755 {"cmdline_compl", 1},
3756 {"cmdline_hist", 1},
3757 {"comments", 1},
3758 {"conceal",
3759#ifdef FEAT_CONCEAL
3760 1
3761#else
3762 0
3763#endif
3764 },
3765 {"cryptv",
3766#ifdef FEAT_CRYPT
3767 1
3768#else
3769 0
3770#endif
3771 },
3772 {"crypt-blowfish",
3773#ifdef FEAT_CRYPT
3774 1
3775#else
3776 0
3777#endif
3778 },
3779 {"crypt-blowfish2",
3780#ifdef FEAT_CRYPT
3781 1
3782#else
3783 0
3784#endif
3785 },
3786 {"cscope",
3787#ifdef FEAT_CSCOPE
3788 1
3789#else
3790 0
3791#endif
3792 },
3793 {"cursorbind", 1},
3794 {"cursorshape",
3795#ifdef CURSOR_SHAPE
3796 1
3797#else
3798 0
3799#endif
3800 },
3801 {"debug",
3802#ifdef DEBUG
3803 1
3804#else
3805 0
3806#endif
3807 },
3808 {"dialog_con",
3809#ifdef FEAT_CON_DIALOG
3810 1
3811#else
3812 0
3813#endif
3814 },
3815 {"dialog_gui",
3816#ifdef FEAT_GUI_DIALOG
3817 1
3818#else
3819 0
3820#endif
3821 },
3822 {"diff",
3823#ifdef FEAT_DIFF
3824 1
3825#else
3826 0
3827#endif
3828 },
3829 {"digraphs",
3830#ifdef FEAT_DIGRAPHS
3831 1
3832#else
3833 0
3834#endif
3835 },
3836 {"directx",
3837#ifdef FEAT_DIRECTX
3838 1
3839#else
3840 0
3841#endif
3842 },
3843 {"dnd",
3844#ifdef FEAT_DND
3845 1
3846#else
3847 0
3848#endif
3849 },
3850 {"emacs_tags",
3851#ifdef FEAT_EMACS_TAGS
3852 1
3853#else
3854 0
3855#endif
3856 },
3857 {"eval", 1}, // always present, of course!
3858 {"ex_extra", 1}, // graduated feature
3859 {"extra_search",
3860#ifdef FEAT_SEARCH_EXTRA
3861 1
3862#else
3863 0
3864#endif
3865 },
3866 {"file_in_path",
3867#ifdef FEAT_SEARCHPATH
3868 1
3869#else
3870 0
3871#endif
3872 },
3873 {"filterpipe",
3874#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3875 1
3876#else
3877 0
3878#endif
3879 },
3880 {"find_in_path",
3881#ifdef FEAT_FIND_ID
3882 1
3883#else
3884 0
3885#endif
3886 },
3887 {"float",
3888#ifdef FEAT_FLOAT
3889 1
3890#else
3891 0
3892#endif
3893 },
3894 {"folding",
3895#ifdef FEAT_FOLDING
3896 1
3897#else
3898 0
3899#endif
3900 },
3901 {"footer",
3902#ifdef FEAT_FOOTER
3903 1
3904#else
3905 0
3906#endif
3907 },
3908 {"fork",
3909#if !defined(USE_SYSTEM) && defined(UNIX)
3910 1
3911#else
3912 0
3913#endif
3914 },
3915 {"gettext",
3916#ifdef FEAT_GETTEXT
3917 1
3918#else
3919 0
3920#endif
3921 },
3922 {"gui",
3923#ifdef FEAT_GUI
3924 1
3925#else
3926 0
3927#endif
3928 },
3929 {"gui_neXtaw",
3930#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3931 1
3932#else
3933 0
3934#endif
3935 },
3936 {"gui_athena",
3937#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3938 1
3939#else
3940 0
3941#endif
3942 },
3943 {"gui_gtk",
3944#ifdef FEAT_GUI_GTK
3945 1
3946#else
3947 0
3948#endif
3949 },
3950 {"gui_gtk2",
3951#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3952 1
3953#else
3954 0
3955#endif
3956 },
3957 {"gui_gtk3",
3958#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3959 1
3960#else
3961 0
3962#endif
3963 },
3964 {"gui_gnome",
3965#ifdef FEAT_GUI_GNOME
3966 1
3967#else
3968 0
3969#endif
3970 },
3971 {"gui_haiku",
3972#ifdef FEAT_GUI_HAIKU
3973 1
3974#else
3975 0
3976#endif
3977 },
Bram Moolenaar097148e2020-08-11 21:58:20 +02003978 {"gui_mac", 0},
Bram Moolenaar79296512020-03-22 16:17:14 +01003979 {"gui_motif",
3980#ifdef FEAT_GUI_MOTIF
3981 1
3982#else
3983 0
3984#endif
3985 },
3986 {"gui_photon",
3987#ifdef FEAT_GUI_PHOTON
3988 1
3989#else
3990 0
3991#endif
3992 },
3993 {"gui_win32",
3994#ifdef FEAT_GUI_MSWIN
3995 1
3996#else
3997 0
3998#endif
3999 },
4000 {"iconv",
4001#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
4002 1
4003#else
4004 0
4005#endif
4006 },
4007 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02004008 {"ipv6",
4009#ifdef FEAT_IPV6
4010 1
4011#else
4012 0
4013#endif
4014 },
Bram Moolenaar79296512020-03-22 16:17:14 +01004015 {"job",
4016#ifdef FEAT_JOB_CHANNEL
4017 1
4018#else
4019 0
4020#endif
4021 },
4022 {"jumplist",
4023#ifdef FEAT_JUMPLIST
4024 1
4025#else
4026 0
4027#endif
4028 },
4029 {"keymap",
4030#ifdef FEAT_KEYMAP
4031 1
4032#else
4033 0
4034#endif
4035 },
4036 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
4037 {"langmap",
4038#ifdef FEAT_LANGMAP
4039 1
4040#else
4041 0
4042#endif
4043 },
4044 {"libcall",
4045#ifdef FEAT_LIBCALL
4046 1
4047#else
4048 0
4049#endif
4050 },
4051 {"linebreak",
4052#ifdef FEAT_LINEBREAK
4053 1
4054#else
4055 0
4056#endif
4057 },
4058 {"lispindent",
4059#ifdef FEAT_LISP
4060 1
4061#else
4062 0
4063#endif
4064 },
4065 {"listcmds", 1},
4066 {"localmap", 1},
4067 {"lua",
4068#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
4069 1
4070#else
4071 0
4072#endif
4073 },
4074 {"menu",
4075#ifdef FEAT_MENU
4076 1
4077#else
4078 0
4079#endif
4080 },
4081 {"mksession",
4082#ifdef FEAT_SESSION
4083 1
4084#else
4085 0
4086#endif
4087 },
4088 {"modify_fname", 1},
4089 {"mouse", 1},
4090 {"mouseshape",
4091#ifdef FEAT_MOUSESHAPE
4092 1
4093#else
4094 0
4095#endif
4096 },
4097 {"mouse_dec",
4098#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
4099 1
4100#else
4101 0
4102#endif
4103 },
4104 {"mouse_gpm",
4105#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
4106 1
4107#else
4108 0
4109#endif
4110 },
4111 {"mouse_jsbterm",
4112#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
4113 1
4114#else
4115 0
4116#endif
4117 },
4118 {"mouse_netterm",
4119#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
4120 1
4121#else
4122 0
4123#endif
4124 },
4125 {"mouse_pterm",
4126#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
4127 1
4128#else
4129 0
4130#endif
4131 },
4132 {"mouse_sgr",
4133#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4134 1
4135#else
4136 0
4137#endif
4138 },
4139 {"mouse_sysmouse",
4140#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4141 1
4142#else
4143 0
4144#endif
4145 },
4146 {"mouse_urxvt",
4147#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4148 1
4149#else
4150 0
4151#endif
4152 },
4153 {"mouse_xterm",
4154#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4155 1
4156#else
4157 0
4158#endif
4159 },
4160 {"multi_byte", 1},
4161 {"multi_byte_ime",
4162#ifdef FEAT_MBYTE_IME
4163 1
4164#else
4165 0
4166#endif
4167 },
4168 {"multi_lang",
4169#ifdef FEAT_MULTI_LANG
4170 1
4171#else
4172 0
4173#endif
4174 },
4175 {"mzscheme",
4176#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4177 1
4178#else
4179 0
4180#endif
4181 },
4182 {"num64", 1},
4183 {"ole",
4184#ifdef FEAT_OLE
4185 1
4186#else
4187 0
4188#endif
4189 },
4190 {"packages",
4191#ifdef FEAT_EVAL
4192 1
4193#else
4194 0
4195#endif
4196 },
4197 {"path_extra",
4198#ifdef FEAT_PATH_EXTRA
4199 1
4200#else
4201 0
4202#endif
4203 },
4204 {"perl",
4205#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4206 1
4207#else
4208 0
4209#endif
4210 },
4211 {"persistent_undo",
4212#ifdef FEAT_PERSISTENT_UNDO
4213 1
4214#else
4215 0
4216#endif
4217 },
4218 {"python_compiled",
4219#if defined(FEAT_PYTHON)
4220 1
4221#else
4222 0
4223#endif
4224 },
4225 {"python_dynamic",
4226#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4227 1
4228#else
4229 0
4230#endif
4231 },
4232 {"python",
4233#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4234 1
4235#else
4236 0
4237#endif
4238 },
4239 {"pythonx",
4240#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4241 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4242 1
4243#else
4244 0
4245#endif
4246 },
4247 {"python3_compiled",
4248#if defined(FEAT_PYTHON3)
4249 1
4250#else
4251 0
4252#endif
4253 },
4254 {"python3_dynamic",
4255#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4256 1
4257#else
4258 0
4259#endif
4260 },
4261 {"python3",
4262#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4263 1
4264#else
4265 0
4266#endif
4267 },
4268 {"popupwin",
4269#ifdef FEAT_PROP_POPUP
4270 1
4271#else
4272 0
4273#endif
4274 },
4275 {"postscript",
4276#ifdef FEAT_POSTSCRIPT
4277 1
4278#else
4279 0
4280#endif
4281 },
4282 {"printer",
4283#ifdef FEAT_PRINTER
4284 1
4285#else
4286 0
4287#endif
4288 },
4289 {"profile",
4290#ifdef FEAT_PROFILE
4291 1
4292#else
4293 0
4294#endif
4295 },
4296 {"reltime",
4297#ifdef FEAT_RELTIME
4298 1
4299#else
4300 0
4301#endif
4302 },
4303 {"quickfix",
4304#ifdef FEAT_QUICKFIX
4305 1
4306#else
4307 0
4308#endif
4309 },
4310 {"rightleft",
4311#ifdef FEAT_RIGHTLEFT
4312 1
4313#else
4314 0
4315#endif
4316 },
4317 {"ruby",
4318#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4319 1
4320#else
4321 0
4322#endif
4323 },
4324 {"scrollbind", 1},
4325 {"showcmd",
4326#ifdef FEAT_CMDL_INFO
4327 1
4328#else
4329 0
4330#endif
4331 },
4332 {"cmdline_info",
4333#ifdef FEAT_CMDL_INFO
4334 1
4335#else
4336 0
4337#endif
4338 },
4339 {"signs",
4340#ifdef FEAT_SIGNS
4341 1
4342#else
4343 0
4344#endif
4345 },
4346 {"smartindent",
4347#ifdef FEAT_SMARTINDENT
4348 1
4349#else
4350 0
4351#endif
4352 },
4353 {"startuptime",
4354#ifdef STARTUPTIME
4355 1
4356#else
4357 0
4358#endif
4359 },
4360 {"statusline",
4361#ifdef FEAT_STL_OPT
4362 1
4363#else
4364 0
4365#endif
4366 },
4367 {"netbeans_intg",
4368#ifdef FEAT_NETBEANS_INTG
4369 1
4370#else
4371 0
4372#endif
4373 },
4374 {"sound",
4375#ifdef FEAT_SOUND
4376 1
4377#else
4378 0
4379#endif
4380 },
4381 {"spell",
4382#ifdef FEAT_SPELL
4383 1
4384#else
4385 0
4386#endif
4387 },
4388 {"syntax",
4389#ifdef FEAT_SYN_HL
4390 1
4391#else
4392 0
4393#endif
4394 },
4395 {"system",
4396#if defined(USE_SYSTEM) || !defined(UNIX)
4397 1
4398#else
4399 0
4400#endif
4401 },
4402 {"tag_binary",
4403#ifdef FEAT_TAG_BINS
4404 1
4405#else
4406 0
4407#endif
4408 },
4409 {"tcl",
4410#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4411 1
4412#else
4413 0
4414#endif
4415 },
4416 {"termguicolors",
4417#ifdef FEAT_TERMGUICOLORS
4418 1
4419#else
4420 0
4421#endif
4422 },
4423 {"terminal",
4424#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4425 1
4426#else
4427 0
4428#endif
4429 },
4430 {"terminfo",
4431#ifdef TERMINFO
4432 1
4433#else
4434 0
4435#endif
4436 },
4437 {"termresponse",
4438#ifdef FEAT_TERMRESPONSE
4439 1
4440#else
4441 0
4442#endif
4443 },
4444 {"textobjects",
4445#ifdef FEAT_TEXTOBJ
4446 1
4447#else
4448 0
4449#endif
4450 },
4451 {"textprop",
4452#ifdef FEAT_PROP_POPUP
4453 1
4454#else
4455 0
4456#endif
4457 },
4458 {"tgetent",
4459#ifdef HAVE_TGETENT
4460 1
4461#else
4462 0
4463#endif
4464 },
4465 {"timers",
4466#ifdef FEAT_TIMERS
4467 1
4468#else
4469 0
4470#endif
4471 },
4472 {"title",
4473#ifdef FEAT_TITLE
4474 1
4475#else
4476 0
4477#endif
4478 },
4479 {"toolbar",
4480#ifdef FEAT_TOOLBAR
4481 1
4482#else
4483 0
4484#endif
4485 },
4486 {"unnamedplus",
4487#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4488 1
4489#else
4490 0
4491#endif
4492 },
4493 {"user-commands", 1}, // was accidentally included in 5.4
4494 {"user_commands", 1},
4495 {"vartabs",
4496#ifdef FEAT_VARTABS
4497 1
4498#else
4499 0
4500#endif
4501 },
4502 {"vertsplit", 1},
4503 {"viminfo",
4504#ifdef FEAT_VIMINFO
4505 1
4506#else
4507 0
4508#endif
4509 },
4510 {"vimscript-1", 1},
4511 {"vimscript-2", 1},
4512 {"vimscript-3", 1},
4513 {"vimscript-4", 1},
4514 {"virtualedit", 1},
4515 {"visual", 1},
4516 {"visualextra", 1},
4517 {"vreplace", 1},
4518 {"vtp",
4519#ifdef FEAT_VTP
4520 1
4521#else
4522 0
4523#endif
4524 },
4525 {"wildignore",
4526#ifdef FEAT_WILDIGN
4527 1
4528#else
4529 0
4530#endif
4531 },
4532 {"wildmenu",
4533#ifdef FEAT_WILDMENU
4534 1
4535#else
4536 0
4537#endif
4538 },
4539 {"windows", 1},
4540 {"winaltkeys",
4541#ifdef FEAT_WAK
4542 1
4543#else
4544 0
4545#endif
4546 },
4547 {"writebackup",
4548#ifdef FEAT_WRITEBACKUP
4549 1
4550#else
4551 0
4552#endif
4553 },
4554 {"xim",
4555#ifdef FEAT_XIM
4556 1
4557#else
4558 0
4559#endif
4560 },
4561 {"xfontset",
4562#ifdef FEAT_XFONTSET
4563 1
4564#else
4565 0
4566#endif
4567 },
4568 {"xpm",
4569#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4570 1
4571#else
4572 0
4573#endif
4574 },
4575 {"xpm_w32", // for backward compatibility
4576#ifdef FEAT_XPM_W32
4577 1
4578#else
4579 0
4580#endif
4581 },
4582 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004583#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004584 1
4585#else
4586 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004587#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004588 },
4589 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004590#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004591 1
4592#else
4593 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004595 },
4596 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004597#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004598 1
4599#else
4600 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004601#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004602 },
4603 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004604#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004605 1
4606#else
4607 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004608#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004609 },
4610 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004612 1
4613#else
4614 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004615#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004616 },
4617 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004618 };
4619
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004620 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004621 for (i = 0; has_list[i].name != NULL; ++i)
4622 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004623 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004624 x = TRUE;
4625 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004626 break;
4627 }
4628
Bram Moolenaar79296512020-03-22 16:17:14 +01004629 // features also in has_list[] but sometimes enabled at runtime
4630 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004631 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004632 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004633 {
4634 // intentionally empty
4635 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004636#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004637 else if (STRICMP(name, "balloon_multiline") == 0)
4638 n = multiline_balloon_available();
4639#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004640#ifdef VIMDLL
4641 else if (STRICMP(name, "filterpipe") == 0)
4642 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004643#endif
4644#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4645 else if (STRICMP(name, "iconv") == 0)
4646 n = iconv_enabled(FALSE);
4647#endif
4648#ifdef DYNAMIC_LUA
4649 else if (STRICMP(name, "lua") == 0)
4650 n = lua_enabled(FALSE);
4651#endif
4652#ifdef DYNAMIC_MZSCHEME
4653 else if (STRICMP(name, "mzscheme") == 0)
4654 n = mzscheme_enabled(FALSE);
4655#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004656#ifdef DYNAMIC_PERL
4657 else if (STRICMP(name, "perl") == 0)
4658 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004659#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004660#ifdef DYNAMIC_PYTHON
4661 else if (STRICMP(name, "python") == 0)
4662 n = python_enabled(FALSE);
4663#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664#ifdef DYNAMIC_PYTHON3
4665 else if (STRICMP(name, "python3") == 0)
4666 n = python3_enabled(FALSE);
4667#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004668#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4669 else if (STRICMP(name, "pythonx") == 0)
4670 {
4671# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4672 if (p_pyx == 0)
4673 n = python3_enabled(FALSE) || python_enabled(FALSE);
4674 else if (p_pyx == 3)
4675 n = python3_enabled(FALSE);
4676 else if (p_pyx == 2)
4677 n = python_enabled(FALSE);
4678# elif defined(DYNAMIC_PYTHON)
4679 n = python_enabled(FALSE);
4680# elif defined(DYNAMIC_PYTHON3)
4681 n = python3_enabled(FALSE);
4682# endif
4683 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004684#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004685#ifdef DYNAMIC_RUBY
4686 else if (STRICMP(name, "ruby") == 0)
4687 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004688#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004689#ifdef DYNAMIC_TCL
4690 else if (STRICMP(name, "tcl") == 0)
4691 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004692#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004693#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004694 else if (STRICMP(name, "terminal") == 0)
4695 n = terminal_enabled();
4696#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004697 }
4698
Bram Moolenaar79296512020-03-22 16:17:14 +01004699 // features not in has_list[]
4700 if (x == FALSE)
4701 {
4702 if (STRNICMP(name, "patch", 5) == 0)
4703 {
4704 x = TRUE;
4705 if (name[5] == '-'
4706 && STRLEN(name) >= 11
4707 && vim_isdigit(name[6])
4708 && vim_isdigit(name[8])
4709 && vim_isdigit(name[10]))
4710 {
4711 int major = atoi((char *)name + 6);
4712 int minor = atoi((char *)name + 8);
4713
4714 // Expect "patch-9.9.01234".
4715 n = (major < VIM_VERSION_MAJOR
4716 || (major == VIM_VERSION_MAJOR
4717 && (minor < VIM_VERSION_MINOR
4718 || (minor == VIM_VERSION_MINOR
4719 && has_patch(atoi((char *)name + 10))))));
4720 }
4721 else
4722 n = has_patch(atoi((char *)name + 5));
4723 }
4724 else if (STRICMP(name, "vim_starting") == 0)
4725 {
4726 x = TRUE;
4727 n = (starting != 0);
4728 }
4729 else if (STRICMP(name, "ttyin") == 0)
4730 {
4731 x = TRUE;
4732 n = mch_input_isatty();
4733 }
4734 else if (STRICMP(name, "ttyout") == 0)
4735 {
4736 x = TRUE;
4737 n = stdout_isatty;
4738 }
4739 else if (STRICMP(name, "multi_byte_encoding") == 0)
4740 {
4741 x = TRUE;
4742 n = has_mbyte;
4743 }
4744 else if (STRICMP(name, "gui_running") == 0)
4745 {
4746 x = TRUE;
4747#ifdef FEAT_GUI
4748 n = (gui.in_use || gui.starting);
4749#endif
4750 }
4751 else if (STRICMP(name, "browse") == 0)
4752 {
4753 x = TRUE;
4754#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4755 n = gui.in_use; // gui_mch_browse() works when GUI is running
4756#endif
4757 }
4758 else if (STRICMP(name, "syntax_items") == 0)
4759 {
4760 x = TRUE;
4761#ifdef FEAT_SYN_HL
4762 n = syntax_present(curwin);
4763#endif
4764 }
4765 else if (STRICMP(name, "vcon") == 0)
4766 {
4767 x = TRUE;
4768#ifdef FEAT_VTP
4769 n = is_term_win32() && has_vtp_working();
4770#endif
4771 }
4772 else if (STRICMP(name, "netbeans_enabled") == 0)
4773 {
4774 x = TRUE;
4775#ifdef FEAT_NETBEANS_INTG
4776 n = netbeans_active();
4777#endif
4778 }
4779 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4780 {
4781 x = TRUE;
4782#ifdef FEAT_MOUSE_GPM
4783 n = gpm_enabled();
4784#endif
4785 }
4786 else if (STRICMP(name, "conpty") == 0)
4787 {
4788 x = TRUE;
4789#if defined(FEAT_TERMINAL) && defined(MSWIN)
4790 n = use_conpty();
4791#endif
4792 }
4793 else if (STRICMP(name, "clipboard_working") == 0)
4794 {
4795 x = TRUE;
4796#ifdef FEAT_CLIPBOARD
4797 n = clip_star.available;
4798#endif
4799 }
4800 }
4801
Bram Moolenaar04637e22020-09-05 18:45:29 +02004802 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]))
Bram Moolenaar79296512020-03-22 16:17:14 +01004803 // return whether feature could ever be enabled
4804 rettv->vval.v_number = x;
4805 else
4806 // return whether feature is enabled
4807 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004808}
4809
4810/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004811 * "haslocaldir()" function
4812 */
4813 static void
4814f_haslocaldir(typval_T *argvars, typval_T *rettv)
4815{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004816 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004817 win_T *wp = NULL;
4818
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004819 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4820
4821 // Check for window-local and tab-local directories
4822 if (wp != NULL && wp->w_localdir != NULL)
4823 rettv->vval.v_number = 1;
4824 else if (tp != NULL && tp->tp_localdir != NULL)
4825 rettv->vval.v_number = 2;
4826 else
4827 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828}
4829
4830/*
4831 * "hasmapto()" function
4832 */
4833 static void
4834f_hasmapto(typval_T *argvars, typval_T *rettv)
4835{
4836 char_u *name;
4837 char_u *mode;
4838 char_u buf[NUMBUFLEN];
4839 int abbr = FALSE;
4840
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004841 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004842 if (argvars[1].v_type == VAR_UNKNOWN)
4843 mode = (char_u *)"nvo";
4844 else
4845 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004846 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004847 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar04d594b2020-09-02 22:25:35 +02004848 abbr = (int)tv_get_bool(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004849 }
4850
4851 if (map_to_exists(name, mode, abbr))
4852 rettv->vval.v_number = TRUE;
4853 else
4854 rettv->vval.v_number = FALSE;
4855}
4856
4857/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004858 * "highlightID(name)" function
4859 */
4860 static void
4861f_hlID(typval_T *argvars, typval_T *rettv)
4862{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004863 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004864}
4865
4866/*
4867 * "highlight_exists()" function
4868 */
4869 static void
4870f_hlexists(typval_T *argvars, typval_T *rettv)
4871{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004872 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004873}
4874
4875/*
4876 * "hostname()" function
4877 */
4878 static void
4879f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4880{
4881 char_u hostname[256];
4882
4883 mch_get_host_name(hostname, 256);
4884 rettv->v_type = VAR_STRING;
4885 rettv->vval.v_string = vim_strsave(hostname);
4886}
4887
4888/*
4889 * iconv() function
4890 */
4891 static void
4892f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4893{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894 char_u buf1[NUMBUFLEN];
4895 char_u buf2[NUMBUFLEN];
4896 char_u *from, *to, *str;
4897 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004898
4899 rettv->v_type = VAR_STRING;
4900 rettv->vval.v_string = NULL;
4901
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004902 str = tv_get_string(&argvars[0]);
4903 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4904 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004905 vimconv.vc_type = CONV_NONE;
4906 convert_setup(&vimconv, from, to);
4907
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004908 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909 if (vimconv.vc_type == CONV_NONE)
4910 rettv->vval.v_string = vim_strsave(str);
4911 else
4912 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4913
4914 convert_setup(&vimconv, NULL, NULL);
4915 vim_free(from);
4916 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917}
4918
4919/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004920 * "index()" function
4921 */
4922 static void
4923f_index(typval_T *argvars, typval_T *rettv)
4924{
4925 list_T *l;
4926 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004927 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004928 long idx = 0;
4929 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004930 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931
4932 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004933 if (argvars[0].v_type == VAR_BLOB)
4934 {
4935 typval_T tv;
4936 int start = 0;
4937
4938 if (argvars[2].v_type != VAR_UNKNOWN)
4939 {
4940 start = tv_get_number_chk(&argvars[2], &error);
4941 if (error)
4942 return;
4943 }
4944 b = argvars[0].vval.v_blob;
4945 if (b == NULL)
4946 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004947 if (start < 0)
4948 {
4949 start = blob_len(b) + start;
4950 if (start < 0)
4951 start = 0;
4952 }
4953
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004954 for (idx = start; idx < blob_len(b); ++idx)
4955 {
4956 tv.v_type = VAR_NUMBER;
4957 tv.vval.v_number = blob_get(b, idx);
4958 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4959 {
4960 rettv->vval.v_number = idx;
4961 return;
4962 }
4963 }
4964 return;
4965 }
4966 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004967 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004968 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004969 return;
4970 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972 l = argvars[0].vval.v_list;
4973 if (l != NULL)
4974 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004975 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 item = l->lv_first;
4977 if (argvars[2].v_type != VAR_UNKNOWN)
4978 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004979 // Start at specified item. Use the cached index that list_find()
4980 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004981 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004982 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004983 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaar6c553f92020-09-02 22:10:34 +02004984 ic = (int)tv_get_bool_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004985 if (error)
4986 item = NULL;
4987 }
4988
4989 for ( ; item != NULL; item = item->li_next, ++idx)
4990 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4991 {
4992 rettv->vval.v_number = idx;
4993 break;
4994 }
4995 }
4996}
4997
4998static int inputsecret_flag = 0;
4999
5000/*
5001 * "input()" function
5002 * Also handles inputsecret() when inputsecret is set.
5003 */
5004 static void
5005f_input(typval_T *argvars, typval_T *rettv)
5006{
5007 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5008}
5009
5010/*
5011 * "inputdialog()" function
5012 */
5013 static void
5014f_inputdialog(typval_T *argvars, typval_T *rettv)
5015{
5016#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005017 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005018 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5019 {
5020 char_u *message;
5021 char_u buf[NUMBUFLEN];
5022 char_u *defstr = (char_u *)"";
5023
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005024 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005026 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005027 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5028 else
5029 IObuff[0] = NUL;
5030 if (message != NULL && defstr != NULL
5031 && do_dialog(VIM_QUESTION, NULL, message,
5032 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5033 rettv->vval.v_string = vim_strsave(IObuff);
5034 else
5035 {
5036 if (message != NULL && defstr != NULL
5037 && argvars[1].v_type != VAR_UNKNOWN
5038 && argvars[2].v_type != VAR_UNKNOWN)
5039 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005040 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005041 else
5042 rettv->vval.v_string = NULL;
5043 }
5044 rettv->v_type = VAR_STRING;
5045 }
5046 else
5047#endif
5048 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5049}
5050
5051/*
5052 * "inputlist()" function
5053 */
5054 static void
5055f_inputlist(typval_T *argvars, typval_T *rettv)
5056{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005057 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005058 listitem_T *li;
5059 int selected;
5060 int mouse_used;
5061
5062#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005063 // While starting up, there is no place to enter text. When running tests
5064 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02005065 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005066 return;
5067#endif
5068 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5069 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005070 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005071 return;
5072 }
5073
5074 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005075 msg_row = Rows - 1; // for when 'cmdheight' > 1
5076 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 msg_scroll = TRUE;
5078 msg_clr_eos();
5079
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005080 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005081 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02005082 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005083 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005084 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005085 msg_putchar('\n');
5086 }
5087
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005088 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005089 selected = prompt_for_number(&mouse_used);
5090 if (mouse_used)
5091 selected -= lines_left;
5092
5093 rettv->vval.v_number = selected;
5094}
5095
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5097
5098/*
5099 * "inputrestore()" function
5100 */
5101 static void
5102f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5103{
5104 if (ga_userinput.ga_len > 0)
5105 {
5106 --ga_userinput.ga_len;
5107 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5108 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005109 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110 }
5111 else if (p_verbose > 1)
5112 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005113 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005114 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115 }
5116}
5117
5118/*
5119 * "inputsave()" function
5120 */
5121 static void
5122f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5123{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005124 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005125 if (ga_grow(&ga_userinput, 1) == OK)
5126 {
5127 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5128 + ga_userinput.ga_len);
5129 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005130 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005131 }
5132 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005133 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005134}
5135
5136/*
5137 * "inputsecret()" function
5138 */
5139 static void
5140f_inputsecret(typval_T *argvars, typval_T *rettv)
5141{
5142 ++cmdline_star;
5143 ++inputsecret_flag;
5144 f_input(argvars, rettv);
5145 --cmdline_star;
5146 --inputsecret_flag;
5147}
5148
5149/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005150 * "interrupt()" function
5151 */
5152 static void
5153f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5154{
5155 got_int = TRUE;
5156}
5157
5158/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005159 * "invert(expr)" function
5160 */
5161 static void
5162f_invert(typval_T *argvars, typval_T *rettv)
5163{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005164 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005165}
5166
5167/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005168 * "islocked()" function
5169 */
5170 static void
5171f_islocked(typval_T *argvars, typval_T *rettv)
5172{
5173 lval_T lv;
5174 char_u *end;
5175 dictitem_T *di;
5176
5177 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005178 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005179 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005180 if (end != NULL && lv.ll_name != NULL)
5181 {
5182 if (*end != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02005183 semsg(_(e_trailing_arg), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005184 else
5185 {
5186 if (lv.ll_tv == NULL)
5187 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005188 di = find_var(lv.ll_name, NULL, TRUE);
5189 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005190 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005191 // Consider a variable locked when:
5192 // 1. the variable itself is locked
5193 // 2. the value of the variable is locked.
5194 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005195 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5196 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005197 }
5198 }
5199 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005200 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005202 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005204 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005205 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5206 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005207 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005208 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5209 }
5210 }
5211
5212 clear_lval(&lv);
5213}
5214
5215#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5216/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005217 * "isinf()" function
5218 */
5219 static void
5220f_isinf(typval_T *argvars, typval_T *rettv)
5221{
5222 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5223 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5224}
5225
5226/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005227 * "isnan()" function
5228 */
5229 static void
5230f_isnan(typval_T *argvars, typval_T *rettv)
5231{
5232 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5233 && isnan(argvars[0].vval.v_float);
5234}
5235#endif
5236
5237/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005238 * "last_buffer_nr()" function.
5239 */
5240 static void
5241f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5242{
5243 int n = 0;
5244 buf_T *buf;
5245
Bram Moolenaar29323592016-07-24 22:04:11 +02005246 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005247 if (n < buf->b_fnum)
5248 n = buf->b_fnum;
5249
5250 rettv->vval.v_number = n;
5251}
5252
5253/*
5254 * "len()" function
5255 */
5256 static void
5257f_len(typval_T *argvars, typval_T *rettv)
5258{
5259 switch (argvars[0].v_type)
5260 {
5261 case VAR_STRING:
5262 case VAR_NUMBER:
5263 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005264 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005265 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005266 case VAR_BLOB:
5267 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5268 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005269 case VAR_LIST:
5270 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5271 break;
5272 case VAR_DICT:
5273 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5274 break;
5275 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005276 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005277 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005278 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005279 case VAR_SPECIAL:
5280 case VAR_FLOAT:
5281 case VAR_FUNC:
5282 case VAR_PARTIAL:
5283 case VAR_JOB:
5284 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005285 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005286 break;
5287 }
5288}
5289
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005290 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005291libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292{
5293#ifdef FEAT_LIBCALL
5294 char_u *string_in;
5295 char_u **string_result;
5296 int nr_result;
5297#endif
5298
5299 rettv->v_type = type;
5300 if (type != VAR_NUMBER)
5301 rettv->vval.v_string = NULL;
5302
5303 if (check_restricted() || check_secure())
5304 return;
5305
5306#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005307 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005308 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5309 {
5310 string_in = NULL;
5311 if (argvars[2].v_type == VAR_STRING)
5312 string_in = argvars[2].vval.v_string;
5313 if (type == VAR_NUMBER)
5314 string_result = NULL;
5315 else
5316 string_result = &rettv->vval.v_string;
5317 if (mch_libcall(argvars[0].vval.v_string,
5318 argvars[1].vval.v_string,
5319 string_in,
5320 argvars[2].vval.v_number,
5321 string_result,
5322 &nr_result) == OK
5323 && type == VAR_NUMBER)
5324 rettv->vval.v_number = nr_result;
5325 }
5326#endif
5327}
5328
5329/*
5330 * "libcall()" function
5331 */
5332 static void
5333f_libcall(typval_T *argvars, typval_T *rettv)
5334{
5335 libcall_common(argvars, rettv, VAR_STRING);
5336}
5337
5338/*
5339 * "libcallnr()" function
5340 */
5341 static void
5342f_libcallnr(typval_T *argvars, typval_T *rettv)
5343{
5344 libcall_common(argvars, rettv, VAR_NUMBER);
5345}
5346
5347/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005348 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005349 */
5350 static void
5351f_line(typval_T *argvars, typval_T *rettv)
5352{
5353 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005354 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005355 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005356 int id;
5357 tabpage_T *tp;
5358 win_T *wp;
5359 win_T *save_curwin;
5360 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005362 if (argvars[1].v_type != VAR_UNKNOWN)
5363 {
5364 // use window specified in the second argument
5365 id = (int)tv_get_number(&argvars[1]);
5366 wp = win_id2wp_tp(id, &tp);
5367 if (wp != NULL && tp != NULL)
5368 {
5369 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5370 == OK)
5371 {
5372 check_cursor();
5373 fp = var2fpos(&argvars[0], TRUE, &fnum);
5374 }
5375 restore_win_noblock(save_curwin, save_curtab, TRUE);
5376 }
5377 }
5378 else
5379 // use current window
5380 fp = var2fpos(&argvars[0], TRUE, &fnum);
5381
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005382 if (fp != NULL)
5383 lnum = fp->lnum;
5384 rettv->vval.v_number = lnum;
5385}
5386
5387/*
5388 * "line2byte(lnum)" function
5389 */
5390 static void
5391f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5392{
5393#ifndef FEAT_BYTEOFF
5394 rettv->vval.v_number = -1;
5395#else
5396 linenr_T lnum;
5397
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005398 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005399 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5400 rettv->vval.v_number = -1;
5401 else
5402 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5403 if (rettv->vval.v_number >= 0)
5404 ++rettv->vval.v_number;
5405#endif
5406}
5407
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005408#ifdef FEAT_FLOAT
5409/*
5410 * "log()" function
5411 */
5412 static void
5413f_log(typval_T *argvars, typval_T *rettv)
5414{
5415 float_T f = 0.0;
5416
5417 rettv->v_type = VAR_FLOAT;
5418 if (get_float_arg(argvars, &f) == OK)
5419 rettv->vval.v_float = log(f);
5420 else
5421 rettv->vval.v_float = 0.0;
5422}
5423
5424/*
5425 * "log10()" function
5426 */
5427 static void
5428f_log10(typval_T *argvars, typval_T *rettv)
5429{
5430 float_T f = 0.0;
5431
5432 rettv->v_type = VAR_FLOAT;
5433 if (get_float_arg(argvars, &f) == OK)
5434 rettv->vval.v_float = log10(f);
5435 else
5436 rettv->vval.v_float = 0.0;
5437}
5438#endif
5439
5440#ifdef FEAT_LUA
5441/*
5442 * "luaeval()" function
5443 */
5444 static void
5445f_luaeval(typval_T *argvars, typval_T *rettv)
5446{
5447 char_u *str;
5448 char_u buf[NUMBUFLEN];
5449
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005450 if (check_restricted() || check_secure())
5451 return;
5452
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005453 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005454 do_luaeval(str, argvars + 1, rettv);
5455}
5456#endif
5457
5458/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005459 * "maparg()" function
5460 */
5461 static void
5462f_maparg(typval_T *argvars, typval_T *rettv)
5463{
5464 get_maparg(argvars, rettv, TRUE);
5465}
5466
5467/*
5468 * "mapcheck()" function
5469 */
5470 static void
5471f_mapcheck(typval_T *argvars, typval_T *rettv)
5472{
5473 get_maparg(argvars, rettv, FALSE);
5474}
5475
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005476typedef enum
5477{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005478 MATCH_END, // matchend()
5479 MATCH_MATCH, // match()
5480 MATCH_STR, // matchstr()
5481 MATCH_LIST, // matchlist()
5482 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005483} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005484
5485 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005486find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005487{
5488 char_u *str = NULL;
5489 long len = 0;
5490 char_u *expr = NULL;
5491 char_u *pat;
5492 regmatch_T regmatch;
5493 char_u patbuf[NUMBUFLEN];
5494 char_u strbuf[NUMBUFLEN];
5495 char_u *save_cpo;
5496 long start = 0;
5497 long nth = 1;
5498 colnr_T startcol = 0;
5499 int match = 0;
5500 list_T *l = NULL;
5501 listitem_T *li = NULL;
5502 long idx = 0;
5503 char_u *tofree = NULL;
5504
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005505 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005506 save_cpo = p_cpo;
5507 p_cpo = (char_u *)"";
5508
5509 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005510 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005512 // type MATCH_LIST: return empty list when there are no matches.
5513 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514 if (rettv_list_alloc(rettv) == FAIL)
5515 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005516 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005517 && (list_append_string(rettv->vval.v_list,
5518 (char_u *)"", 0) == FAIL
5519 || list_append_number(rettv->vval.v_list,
5520 (varnumber_T)-1) == FAIL
5521 || list_append_number(rettv->vval.v_list,
5522 (varnumber_T)-1) == FAIL
5523 || list_append_number(rettv->vval.v_list,
5524 (varnumber_T)-1) == FAIL))
5525 {
5526 list_free(rettv->vval.v_list);
5527 rettv->vval.v_list = NULL;
5528 goto theend;
5529 }
5530 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005531 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005532 {
5533 rettv->v_type = VAR_STRING;
5534 rettv->vval.v_string = NULL;
5535 }
5536
5537 if (argvars[0].v_type == VAR_LIST)
5538 {
5539 if ((l = argvars[0].vval.v_list) == NULL)
5540 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005541 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005542 li = l->lv_first;
5543 }
5544 else
5545 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005546 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005547 len = (long)STRLEN(str);
5548 }
5549
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005550 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005551 if (pat == NULL)
5552 goto theend;
5553
5554 if (argvars[2].v_type != VAR_UNKNOWN)
5555 {
5556 int error = FALSE;
5557
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005558 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005559 if (error)
5560 goto theend;
5561 if (l != NULL)
5562 {
5563 li = list_find(l, start);
5564 if (li == NULL)
5565 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005566 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005567 }
5568 else
5569 {
5570 if (start < 0)
5571 start = 0;
5572 if (start > len)
5573 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005574 // When "count" argument is there ignore matches before "start",
5575 // otherwise skip part of the string. Differs when pattern is "^"
5576 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 if (argvars[3].v_type != VAR_UNKNOWN)
5578 startcol = start;
5579 else
5580 {
5581 str += start;
5582 len -= start;
5583 }
5584 }
5585
5586 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005587 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005588 if (error)
5589 goto theend;
5590 }
5591
5592 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5593 if (regmatch.regprog != NULL)
5594 {
5595 regmatch.rm_ic = p_ic;
5596
5597 for (;;)
5598 {
5599 if (l != NULL)
5600 {
5601 if (li == NULL)
5602 {
5603 match = FALSE;
5604 break;
5605 }
5606 vim_free(tofree);
5607 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5608 if (str == NULL)
5609 break;
5610 }
5611
5612 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5613
5614 if (match && --nth <= 0)
5615 break;
5616 if (l == NULL && !match)
5617 break;
5618
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005619 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005620 if (l != NULL)
5621 {
5622 li = li->li_next;
5623 ++idx;
5624 }
5625 else
5626 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005627 startcol = (colnr_T)(regmatch.startp[0]
5628 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005629 if (startcol > (colnr_T)len
5630 || str + startcol <= regmatch.startp[0])
5631 {
5632 match = FALSE;
5633 break;
5634 }
5635 }
5636 }
5637
5638 if (match)
5639 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005640 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005641 {
5642 listitem_T *li1 = rettv->vval.v_list->lv_first;
5643 listitem_T *li2 = li1->li_next;
5644 listitem_T *li3 = li2->li_next;
5645 listitem_T *li4 = li3->li_next;
5646
5647 vim_free(li1->li_tv.vval.v_string);
5648 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005649 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005650 li3->li_tv.vval.v_number =
5651 (varnumber_T)(regmatch.startp[0] - expr);
5652 li4->li_tv.vval.v_number =
5653 (varnumber_T)(regmatch.endp[0] - expr);
5654 if (l != NULL)
5655 li2->li_tv.vval.v_number = (varnumber_T)idx;
5656 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005657 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005658 {
5659 int i;
5660
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005661 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005662 for (i = 0; i < NSUBEXP; ++i)
5663 {
5664 if (regmatch.endp[i] == NULL)
5665 {
5666 if (list_append_string(rettv->vval.v_list,
5667 (char_u *)"", 0) == FAIL)
5668 break;
5669 }
5670 else if (list_append_string(rettv->vval.v_list,
5671 regmatch.startp[i],
5672 (int)(regmatch.endp[i] - regmatch.startp[i]))
5673 == FAIL)
5674 break;
5675 }
5676 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005677 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005678 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005679 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005680 if (l != NULL)
5681 copy_tv(&li->li_tv, rettv);
5682 else
5683 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005684 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685 }
5686 else if (l != NULL)
5687 rettv->vval.v_number = idx;
5688 else
5689 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005690 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691 rettv->vval.v_number =
5692 (varnumber_T)(regmatch.startp[0] - str);
5693 else
5694 rettv->vval.v_number =
5695 (varnumber_T)(regmatch.endp[0] - str);
5696 rettv->vval.v_number += (varnumber_T)(str - expr);
5697 }
5698 }
5699 vim_regfree(regmatch.regprog);
5700 }
5701
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005702theend:
5703 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005704 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005705 listitem_remove(rettv->vval.v_list,
5706 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005707 vim_free(tofree);
5708 p_cpo = save_cpo;
5709}
5710
5711/*
5712 * "match()" function
5713 */
5714 static void
5715f_match(typval_T *argvars, typval_T *rettv)
5716{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005717 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005718}
5719
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005720/*
5721 * "matchend()" function
5722 */
5723 static void
5724f_matchend(typval_T *argvars, typval_T *rettv)
5725{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005726 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005727}
5728
5729/*
5730 * "matchlist()" function
5731 */
5732 static void
5733f_matchlist(typval_T *argvars, typval_T *rettv)
5734{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005735 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005736}
5737
5738/*
5739 * "matchstr()" function
5740 */
5741 static void
5742f_matchstr(typval_T *argvars, typval_T *rettv)
5743{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005744 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005745}
5746
5747/*
5748 * "matchstrpos()" function
5749 */
5750 static void
5751f_matchstrpos(typval_T *argvars, typval_T *rettv)
5752{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005753 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005754}
5755
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005756 static void
5757max_min(typval_T *argvars, typval_T *rettv, int domax)
5758{
5759 varnumber_T n = 0;
5760 varnumber_T i;
5761 int error = FALSE;
5762
5763 if (argvars[0].v_type == VAR_LIST)
5764 {
5765 list_T *l;
5766 listitem_T *li;
5767
5768 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005769 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005770 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005771 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005772 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005773 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5774 n = l->lv_u.nonmat.lv_start;
5775 else
5776 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5777 * l->lv_u.nonmat.lv_stride;
5778 }
5779 else
5780 {
5781 li = l->lv_first;
5782 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005784 n = tv_get_number_chk(&li->li_tv, &error);
5785 for (;;)
5786 {
5787 li = li->li_next;
5788 if (li == NULL)
5789 break;
5790 i = tv_get_number_chk(&li->li_tv, &error);
5791 if (domax ? i > n : i < n)
5792 n = i;
5793 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794 }
5795 }
5796 }
5797 }
5798 else if (argvars[0].v_type == VAR_DICT)
5799 {
5800 dict_T *d;
5801 int first = TRUE;
5802 hashitem_T *hi;
5803 int todo;
5804
5805 d = argvars[0].vval.v_dict;
5806 if (d != NULL)
5807 {
5808 todo = (int)d->dv_hashtab.ht_used;
5809 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5810 {
5811 if (!HASHITEM_EMPTY(hi))
5812 {
5813 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005814 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005815 if (first)
5816 {
5817 n = i;
5818 first = FALSE;
5819 }
5820 else if (domax ? i > n : i < n)
5821 n = i;
5822 }
5823 }
5824 }
5825 }
5826 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005827 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005828 rettv->vval.v_number = error ? 0 : n;
5829}
5830
5831/*
5832 * "max()" function
5833 */
5834 static void
5835f_max(typval_T *argvars, typval_T *rettv)
5836{
5837 max_min(argvars, rettv, TRUE);
5838}
5839
5840/*
5841 * "min()" function
5842 */
5843 static void
5844f_min(typval_T *argvars, typval_T *rettv)
5845{
5846 max_min(argvars, rettv, FALSE);
5847}
5848
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005849#if defined(FEAT_MZSCHEME) || defined(PROTO)
5850/*
5851 * "mzeval()" function
5852 */
5853 static void
5854f_mzeval(typval_T *argvars, typval_T *rettv)
5855{
5856 char_u *str;
5857 char_u buf[NUMBUFLEN];
5858
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005859 if (check_restricted() || check_secure())
5860 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005861 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005862 do_mzeval(str, rettv);
5863}
5864
5865 void
5866mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5867{
5868 typval_T argvars[3];
5869
5870 argvars[0].v_type = VAR_STRING;
5871 argvars[0].vval.v_string = name;
5872 copy_tv(args, &argvars[1]);
5873 argvars[2].v_type = VAR_UNKNOWN;
5874 f_call(argvars, rettv);
5875 clear_tv(&argvars[1]);
5876}
5877#endif
5878
5879/*
5880 * "nextnonblank()" function
5881 */
5882 static void
5883f_nextnonblank(typval_T *argvars, typval_T *rettv)
5884{
5885 linenr_T lnum;
5886
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005887 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005888 {
5889 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5890 {
5891 lnum = 0;
5892 break;
5893 }
5894 if (*skipwhite(ml_get(lnum)) != NUL)
5895 break;
5896 }
5897 rettv->vval.v_number = lnum;
5898}
5899
5900/*
5901 * "nr2char()" function
5902 */
5903 static void
5904f_nr2char(typval_T *argvars, typval_T *rettv)
5905{
5906 char_u buf[NUMBUFLEN];
5907
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005908 if (has_mbyte)
5909 {
5910 int utf8 = 0;
5911
5912 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaared6a4302020-09-05 20:29:41 +02005913 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005915 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005916 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005917 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005918 }
5919 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005920 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005921 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005922 buf[1] = NUL;
5923 }
5924 rettv->v_type = VAR_STRING;
5925 rettv->vval.v_string = vim_strsave(buf);
5926}
5927
5928/*
5929 * "or(expr, expr)" function
5930 */
5931 static void
5932f_or(typval_T *argvars, typval_T *rettv)
5933{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005934 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5935 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005936}
5937
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005938#ifdef FEAT_PERL
5939/*
5940 * "perleval()" function
5941 */
5942 static void
5943f_perleval(typval_T *argvars, typval_T *rettv)
5944{
5945 char_u *str;
5946 char_u buf[NUMBUFLEN];
5947
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005948 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005949 do_perleval(str, rettv);
5950}
5951#endif
5952
5953#ifdef FEAT_FLOAT
5954/*
5955 * "pow()" function
5956 */
5957 static void
5958f_pow(typval_T *argvars, typval_T *rettv)
5959{
5960 float_T fx = 0.0, fy = 0.0;
5961
5962 rettv->v_type = VAR_FLOAT;
5963 if (get_float_arg(argvars, &fx) == OK
5964 && get_float_arg(&argvars[1], &fy) == OK)
5965 rettv->vval.v_float = pow(fx, fy);
5966 else
5967 rettv->vval.v_float = 0.0;
5968}
5969#endif
5970
5971/*
5972 * "prevnonblank()" function
5973 */
5974 static void
5975f_prevnonblank(typval_T *argvars, typval_T *rettv)
5976{
5977 linenr_T lnum;
5978
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005979 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005980 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5981 lnum = 0;
5982 else
5983 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5984 --lnum;
5985 rettv->vval.v_number = lnum;
5986}
5987
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005988// This dummy va_list is here because:
5989// - passing a NULL pointer doesn't work when va_list isn't a pointer
5990// - locally in the function results in a "used before set" warning
5991// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005992static va_list ap;
5993
5994/*
5995 * "printf()" function
5996 */
5997 static void
5998f_printf(typval_T *argvars, typval_T *rettv)
5999{
6000 char_u buf[NUMBUFLEN];
6001 int len;
6002 char_u *s;
6003 int saved_did_emsg = did_emsg;
6004 char *fmt;
6005
6006 rettv->v_type = VAR_STRING;
6007 rettv->vval.v_string = NULL;
6008
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006009 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006010 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006011 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006012 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006013 if (!did_emsg)
6014 {
6015 s = alloc(len + 1);
6016 if (s != NULL)
6017 {
6018 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006019 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
6020 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006021 }
6022 }
6023 did_emsg |= saved_did_emsg;
6024}
6025
6026/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006027 * "pum_getpos()" function
6028 */
6029 static void
6030f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6031{
6032 if (rettv_dict_alloc(rettv) != OK)
6033 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006034 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006035}
6036
6037/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006038 * "pumvisible()" function
6039 */
6040 static void
6041f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6042{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006043 if (pum_visible())
6044 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006045}
6046
6047#ifdef FEAT_PYTHON3
6048/*
6049 * "py3eval()" function
6050 */
6051 static void
6052f_py3eval(typval_T *argvars, typval_T *rettv)
6053{
6054 char_u *str;
6055 char_u buf[NUMBUFLEN];
6056
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006057 if (check_restricted() || check_secure())
6058 return;
6059
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006060 if (p_pyx == 0)
6061 p_pyx = 3;
6062
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006063 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006064 do_py3eval(str, rettv);
6065}
6066#endif
6067
6068#ifdef FEAT_PYTHON
6069/*
6070 * "pyeval()" function
6071 */
6072 static void
6073f_pyeval(typval_T *argvars, typval_T *rettv)
6074{
6075 char_u *str;
6076 char_u buf[NUMBUFLEN];
6077
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006078 if (check_restricted() || check_secure())
6079 return;
6080
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006081 if (p_pyx == 0)
6082 p_pyx = 2;
6083
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006084 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006085 do_pyeval(str, rettv);
6086}
6087#endif
6088
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006089#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
6090/*
6091 * "pyxeval()" function
6092 */
6093 static void
6094f_pyxeval(typval_T *argvars, typval_T *rettv)
6095{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006096 if (check_restricted() || check_secure())
6097 return;
6098
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006099# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
6100 init_pyxversion();
6101 if (p_pyx == 2)
6102 f_pyeval(argvars, rettv);
6103 else
6104 f_py3eval(argvars, rettv);
6105# elif defined(FEAT_PYTHON)
6106 f_pyeval(argvars, rettv);
6107# elif defined(FEAT_PYTHON3)
6108 f_py3eval(argvars, rettv);
6109# endif
6110}
6111#endif
6112
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006113static UINT32_T srand_seed_for_testing = 0;
6114static int srand_seed_for_testing_is_used = FALSE;
6115
6116 static void
6117f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
6118{
6119 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006120 srand_seed_for_testing_is_used = FALSE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006121 else
6122 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006123 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
6124 srand_seed_for_testing_is_used = TRUE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006125 }
6126}
6127
6128 static void
6129init_srand(UINT32_T *x)
6130{
6131#ifndef MSWIN
6132 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6133#endif
6134
6135 if (srand_seed_for_testing_is_used)
6136 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006137 *x = srand_seed_for_testing;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006138 return;
6139 }
6140#ifndef MSWIN
6141 if (dev_urandom_state != FAIL)
6142 {
6143 int fd = open("/dev/urandom", O_RDONLY);
6144 struct {
6145 union {
6146 UINT32_T number;
6147 char bytes[sizeof(UINT32_T)];
6148 } contents;
6149 } buf;
6150
6151 // Attempt reading /dev/urandom.
6152 if (fd == -1)
6153 dev_urandom_state = FAIL;
6154 else
6155 {
6156 buf.contents.number = 0;
6157 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6158 != sizeof(UINT32_T))
6159 dev_urandom_state = FAIL;
6160 else
6161 {
6162 dev_urandom_state = OK;
6163 *x = buf.contents.number;
6164 }
6165 close(fd);
6166 }
6167 }
6168 if (dev_urandom_state != OK)
6169 // Reading /dev/urandom doesn't work, fall back to time().
6170#endif
6171 *x = vim_time();
6172}
6173
6174#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6175#define SPLITMIX32(x, z) ( \
6176 z = (x += 0x9e3779b9), \
6177 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6178 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6179 z ^ (z >> 16) \
6180 )
6181#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6182 result = ROTL(y * 5, 7) * 9; \
6183 t = y << 9; \
6184 z ^= x; \
6185 w ^= y; \
6186 y ^= z, x ^= w; \
6187 z ^= t; \
6188 w = ROTL(w, 11);
6189
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006191 * "rand()" function
6192 */
6193 static void
6194f_rand(typval_T *argvars, typval_T *rettv)
6195{
6196 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006197 static UINT32_T gx, gy, gz, gw;
6198 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006199 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006200 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006201
6202 if (argvars[0].v_type == VAR_UNKNOWN)
6203 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006204 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006205 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006206 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006207 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006208 init_srand(&x);
6209
6210 gx = SPLITMIX32(x, z);
6211 gy = SPLITMIX32(x, z);
6212 gz = SPLITMIX32(x, z);
6213 gw = SPLITMIX32(x, z);
6214 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006215 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006216
6217 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006218 }
6219 else if (argvars[0].v_type == VAR_LIST)
6220 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006221 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006222 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006223 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006224
6225 lx = list_find(l, 0L);
6226 ly = list_find(l, 1L);
6227 lz = list_find(l, 2L);
6228 lw = list_find(l, 3L);
6229 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6230 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6231 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6232 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6233 x = (UINT32_T)lx->li_tv.vval.v_number;
6234 y = (UINT32_T)ly->li_tv.vval.v_number;
6235 z = (UINT32_T)lz->li_tv.vval.v_number;
6236 w = (UINT32_T)lw->li_tv.vval.v_number;
6237
6238 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6239
6240 lx->li_tv.vval.v_number = (varnumber_T)x;
6241 ly->li_tv.vval.v_number = (varnumber_T)y;
6242 lz->li_tv.vval.v_number = (varnumber_T)z;
6243 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006244 }
6245 else
6246 goto theend;
6247
6248 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006249 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006250 return;
6251
6252theend:
6253 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006254 rettv->v_type = VAR_NUMBER;
6255 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006256}
6257
6258/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006259 * "srand()" function
6260 */
6261 static void
6262f_srand(typval_T *argvars, typval_T *rettv)
6263{
6264 UINT32_T x = 0, z;
6265
6266 if (rettv_list_alloc(rettv) == FAIL)
6267 return;
6268 if (argvars[0].v_type == VAR_UNKNOWN)
6269 {
6270 init_srand(&x);
6271 }
6272 else
6273 {
6274 int error = FALSE;
6275
6276 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6277 if (error)
6278 return;
6279 }
6280
6281 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6282 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6283 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6284 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6285}
6286
6287#undef ROTL
6288#undef SPLITMIX32
6289#undef SHUFFLE_XOSHIRO128STARSTAR
6290
6291/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006292 * "range()" function
6293 */
6294 static void
6295f_range(typval_T *argvars, typval_T *rettv)
6296{
6297 varnumber_T start;
6298 varnumber_T end;
6299 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300 int error = FALSE;
6301
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006302 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006303 if (argvars[1].v_type == VAR_UNKNOWN)
6304 {
6305 end = start - 1;
6306 start = 0;
6307 }
6308 else
6309 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006310 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006311 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006312 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 }
6314
6315 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006316 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006317 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006318 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006319 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006320 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006321 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006323 list_T *list = rettv->vval.v_list;
6324
6325 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006326 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006327 // be called.
6328 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006329 list->lv_u.nonmat.lv_start = start;
6330 list->lv_u.nonmat.lv_end = end;
6331 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006332 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006333 }
6334}
6335
6336/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006337 * Materialize "list".
6338 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006339 */
6340 void
6341range_list_materialize(list_T *list)
6342{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006343 varnumber_T start = list->lv_u.nonmat.lv_start;
6344 varnumber_T end = list->lv_u.nonmat.lv_end;
6345 int stride = list->lv_u.nonmat.lv_stride;
6346 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006347
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006348 list->lv_first = NULL;
6349 list->lv_u.mat.lv_last = NULL;
6350 list->lv_len = 0;
6351 list->lv_u.mat.lv_idx_item = NULL;
6352 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6353 if (list_append_number(list, (varnumber_T)i) == FAIL)
6354 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355}
6356
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006357/*
6358 * "getreginfo()" function
6359 */
6360 static void
6361f_getreginfo(typval_T *argvars, typval_T *rettv)
6362{
6363 char_u *strregname;
6364 int regname;
6365 char_u buf[NUMBUFLEN + 2];
6366 long reglen = 0;
6367 dict_T *dict;
6368 list_T *list;
6369
6370 if (argvars[0].v_type != VAR_UNKNOWN)
6371 {
6372 strregname = tv_get_string_chk(&argvars[0]);
6373 if (strregname == NULL)
6374 return;
6375 }
6376 else
6377 strregname = get_vim_var_str(VV_REG);
6378
6379 regname = (strregname == NULL ? '"' : *strregname);
6380 if (regname == 0 || regname == '@')
6381 regname = '"';
6382
6383 if (rettv_dict_alloc(rettv) == FAIL)
6384 return;
6385 dict = rettv->vval.v_dict;
6386
6387 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
6388 if (list == NULL)
6389 return;
Bram Moolenaar91639192020-06-29 19:55:58 +02006390 (void)dict_add_list(dict, "regcontents", list);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006391
6392 buf[0] = NUL;
6393 buf[1] = NUL;
6394 switch (get_reg_type(regname, &reglen))
6395 {
6396 case MLINE: buf[0] = 'V'; break;
6397 case MCHAR: buf[0] = 'v'; break;
6398 case MBLOCK:
6399 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
6400 reglen + 1);
6401 break;
6402 }
Bram Moolenaar91639192020-06-29 19:55:58 +02006403 (void)dict_add_string(dict, (char *)"regtype", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006404
6405 buf[0] = get_register_name(get_unname_register());
6406 buf[1] = NUL;
6407 if (regname == '"')
Bram Moolenaar91639192020-06-29 19:55:58 +02006408 (void)dict_add_string(dict, (char *)"points_to", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006409 else
6410 {
6411 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
6412
6413 if (item != NULL)
6414 {
6415 item->di_tv.v_type = VAR_SPECIAL;
6416 item->di_tv.vval.v_number = regname == buf[0]
6417 ? VVAL_TRUE : VVAL_FALSE;
Bram Moolenaar91639192020-06-29 19:55:58 +02006418 (void)dict_add(dict, item);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006419 }
6420 }
6421}
6422
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006423 static void
6424return_register(int regname, typval_T *rettv)
6425{
6426 char_u buf[2] = {0, 0};
6427
6428 buf[0] = (char_u)regname;
6429 rettv->v_type = VAR_STRING;
6430 rettv->vval.v_string = vim_strsave(buf);
6431}
6432
6433/*
6434 * "reg_executing()" function
6435 */
6436 static void
6437f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6438{
6439 return_register(reg_executing, rettv);
6440}
6441
6442/*
6443 * "reg_recording()" function
6444 */
6445 static void
6446f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6447{
6448 return_register(reg_recording, rettv);
6449}
6450
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006451/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006452 * "rename({from}, {to})" function
6453 */
6454 static void
6455f_rename(typval_T *argvars, typval_T *rettv)
6456{
6457 char_u buf[NUMBUFLEN];
6458
6459 if (check_restricted() || check_secure())
6460 rettv->vval.v_number = -1;
6461 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006462 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6463 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006464}
6465
6466/*
6467 * "repeat()" function
6468 */
6469 static void
6470f_repeat(typval_T *argvars, typval_T *rettv)
6471{
6472 char_u *p;
6473 int n;
6474 int slen;
6475 int len;
6476 char_u *r;
6477 int i;
6478
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006479 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006480 if (argvars[0].v_type == VAR_LIST)
6481 {
6482 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6483 while (n-- > 0)
6484 if (list_extend(rettv->vval.v_list,
6485 argvars[0].vval.v_list, NULL) == FAIL)
6486 break;
6487 }
6488 else
6489 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006490 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491 rettv->v_type = VAR_STRING;
6492 rettv->vval.v_string = NULL;
6493
6494 slen = (int)STRLEN(p);
6495 len = slen * n;
6496 if (len <= 0)
6497 return;
6498
6499 r = alloc(len + 1);
6500 if (r != NULL)
6501 {
6502 for (i = 0; i < n; i++)
6503 mch_memmove(r + i * slen, p, (size_t)slen);
6504 r[len] = NUL;
6505 }
6506
6507 rettv->vval.v_string = r;
6508 }
6509}
6510
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006511#define SP_NOMOVE 0x01 // don't move cursor
6512#define SP_REPEAT 0x02 // repeat to find outer pair
6513#define SP_RETCOUNT 0x04 // return matchcount
6514#define SP_SETPCMARK 0x08 // set previous context mark
6515#define SP_START 0x10 // accept match at start position
6516#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6517#define SP_END 0x40 // leave cursor at end of match
6518#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006519
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006520/*
6521 * Get flags for a search function.
6522 * Possibly sets "p_ws".
6523 * Returns BACKWARD, FORWARD or zero (for an error).
6524 */
6525 static int
6526get_search_arg(typval_T *varp, int *flagsp)
6527{
6528 int dir = FORWARD;
6529 char_u *flags;
6530 char_u nbuf[NUMBUFLEN];
6531 int mask;
6532
6533 if (varp->v_type != VAR_UNKNOWN)
6534 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006535 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006536 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006537 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 while (*flags != NUL)
6539 {
6540 switch (*flags)
6541 {
6542 case 'b': dir = BACKWARD; break;
6543 case 'w': p_ws = TRUE; break;
6544 case 'W': p_ws = FALSE; break;
6545 default: mask = 0;
6546 if (flagsp != NULL)
6547 switch (*flags)
6548 {
6549 case 'c': mask = SP_START; break;
6550 case 'e': mask = SP_END; break;
6551 case 'm': mask = SP_RETCOUNT; break;
6552 case 'n': mask = SP_NOMOVE; break;
6553 case 'p': mask = SP_SUBPAT; break;
6554 case 'r': mask = SP_REPEAT; break;
6555 case 's': mask = SP_SETPCMARK; break;
6556 case 'z': mask = SP_COLUMN; break;
6557 }
6558 if (mask == 0)
6559 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006560 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006561 dir = 0;
6562 }
6563 else
6564 *flagsp |= mask;
6565 }
6566 if (dir == 0)
6567 break;
6568 ++flags;
6569 }
6570 }
6571 return dir;
6572}
6573
6574/*
6575 * Shared by search() and searchpos() functions.
6576 */
6577 static int
6578search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6579{
6580 int flags;
6581 char_u *pat;
6582 pos_T pos;
6583 pos_T save_cursor;
6584 int save_p_ws = p_ws;
6585 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006586 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006587 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006589 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590 long time_limit = 0;
6591#endif
6592 int options = SEARCH_KEEP;
6593 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006594 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006595 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006596 pos_T firstpos;
6597
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006598 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006599 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600 if (dir == 0)
6601 goto theend;
6602 flags = *flagsp;
6603 if (flags & SP_START)
6604 options |= SEARCH_START;
6605 if (flags & SP_END)
6606 options |= SEARCH_END;
6607 if (flags & SP_COLUMN)
6608 options |= SEARCH_COL;
6609
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006610 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006611 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6612 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006613 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006614 if (lnum_stop < 0)
6615 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616 if (argvars[3].v_type != VAR_UNKNOWN)
6617 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006618#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006619 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620 if (time_limit < 0)
6621 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006622#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02006623 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006624 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006625 }
6626
6627#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006628 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006629 profile_setlimit(time_limit, &tm);
6630#endif
6631
6632 /*
6633 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6634 * Check to make sure only those flags are set.
6635 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6636 * flags cannot be set. Check for that condition also.
6637 */
6638 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6639 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6640 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006641 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 goto theend;
6643 }
6644
6645 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006646 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02006647 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006648 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6649#ifdef FEAT_RELTIME
6650 sia.sa_tm = &tm;
6651#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006652
6653 // Repeat until {skip} returns FALSE.
6654 for (;;)
6655 {
6656 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006657 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006658 // finding the first match again means there is no match where {skip}
6659 // evaluates to zero.
6660 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
6661 subpatnum = FAIL;
6662
Bram Moolenaara9c01042020-06-07 14:50:50 +02006663 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006664 // didn't find it or no skip argument
6665 break;
6666 firstpos = pos;
6667
Bram Moolenaara9c01042020-06-07 14:50:50 +02006668 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006669 {
6670 int do_skip;
6671 int err;
6672 pos_T save_pos = curwin->w_cursor;
6673
6674 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006675 err = FALSE;
6676 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006677 curwin->w_cursor = save_pos;
6678 if (err)
6679 {
6680 // Evaluating {skip} caused an error, break here.
6681 subpatnum = FAIL;
6682 break;
6683 }
6684 if (!do_skip)
6685 break;
6686 }
6687 }
6688
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 if (subpatnum != FAIL)
6690 {
6691 if (flags & SP_SUBPAT)
6692 retval = subpatnum;
6693 else
6694 retval = pos.lnum;
6695 if (flags & SP_SETPCMARK)
6696 setpcmark();
6697 curwin->w_cursor = pos;
6698 if (match_pos != NULL)
6699 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006700 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 match_pos->lnum = pos.lnum;
6702 match_pos->col = pos.col + 1;
6703 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006704 // "/$" will put the cursor after the end of the line, may need to
6705 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006706 check_cursor();
6707 }
6708
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006709 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006710 if (flags & SP_NOMOVE)
6711 curwin->w_cursor = save_cursor;
6712 else
6713 curwin->w_set_curswant = TRUE;
6714theend:
6715 p_ws = save_p_ws;
6716
6717 return retval;
6718}
6719
6720#ifdef FEAT_FLOAT
6721
6722/*
6723 * round() is not in C90, use ceil() or floor() instead.
6724 */
6725 float_T
6726vim_round(float_T f)
6727{
6728 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6729}
6730
6731/*
6732 * "round({float})" function
6733 */
6734 static void
6735f_round(typval_T *argvars, typval_T *rettv)
6736{
6737 float_T f = 0.0;
6738
6739 rettv->v_type = VAR_FLOAT;
6740 if (get_float_arg(argvars, &f) == OK)
6741 rettv->vval.v_float = vim_round(f);
6742 else
6743 rettv->vval.v_float = 0.0;
6744}
6745#endif
6746
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006747#ifdef FEAT_RUBY
6748/*
6749 * "rubyeval()" function
6750 */
6751 static void
6752f_rubyeval(typval_T *argvars, typval_T *rettv)
6753{
6754 char_u *str;
6755 char_u buf[NUMBUFLEN];
6756
6757 str = tv_get_string_buf(&argvars[0], buf);
6758 do_rubyeval(str, rettv);
6759}
6760#endif
6761
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006762/*
6763 * "screenattr()" function
6764 */
6765 static void
6766f_screenattr(typval_T *argvars, typval_T *rettv)
6767{
6768 int row;
6769 int col;
6770 int c;
6771
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006772 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6773 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774 if (row < 0 || row >= screen_Rows
6775 || col < 0 || col >= screen_Columns)
6776 c = -1;
6777 else
6778 c = ScreenAttrs[LineOffset[row] + col];
6779 rettv->vval.v_number = c;
6780}
6781
6782/*
6783 * "screenchar()" function
6784 */
6785 static void
6786f_screenchar(typval_T *argvars, typval_T *rettv)
6787{
6788 int row;
6789 int col;
6790 int off;
6791 int c;
6792
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006793 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6794 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006795 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 c = -1;
6797 else
6798 {
6799 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006800 if (enc_utf8 && ScreenLinesUC[off] != 0)
6801 c = ScreenLinesUC[off];
6802 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006803 c = ScreenLines[off];
6804 }
6805 rettv->vval.v_number = c;
6806}
6807
6808/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006809 * "screenchars()" function
6810 */
6811 static void
6812f_screenchars(typval_T *argvars, typval_T *rettv)
6813{
6814 int row;
6815 int col;
6816 int off;
6817 int c;
6818 int i;
6819
6820 if (rettv_list_alloc(rettv) == FAIL)
6821 return;
6822 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6823 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6824 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6825 return;
6826
6827 off = LineOffset[row] + col;
6828 if (enc_utf8 && ScreenLinesUC[off] != 0)
6829 c = ScreenLinesUC[off];
6830 else
6831 c = ScreenLines[off];
6832 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6833
6834 if (enc_utf8)
6835
6836 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6837 list_append_number(rettv->vval.v_list,
6838 (varnumber_T)ScreenLinesC[i][off]);
6839}
6840
6841/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842 * "screencol()" function
6843 *
6844 * First column is 1 to be consistent with virtcol().
6845 */
6846 static void
6847f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6848{
6849 rettv->vval.v_number = screen_screencol() + 1;
6850}
6851
6852/*
6853 * "screenrow()" function
6854 */
6855 static void
6856f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6857{
6858 rettv->vval.v_number = screen_screenrow() + 1;
6859}
6860
6861/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006862 * "screenstring()" function
6863 */
6864 static void
6865f_screenstring(typval_T *argvars, typval_T *rettv)
6866{
6867 int row;
6868 int col;
6869 int off;
6870 int c;
6871 int i;
6872 char_u buf[MB_MAXBYTES + 1];
6873 int buflen = 0;
6874
6875 rettv->vval.v_string = NULL;
6876 rettv->v_type = VAR_STRING;
6877
6878 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6879 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6880 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6881 return;
6882
6883 off = LineOffset[row] + col;
6884 if (enc_utf8 && ScreenLinesUC[off] != 0)
6885 c = ScreenLinesUC[off];
6886 else
6887 c = ScreenLines[off];
6888 buflen += mb_char2bytes(c, buf);
6889
6890 if (enc_utf8)
6891 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6892 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6893
6894 buf[buflen] = NUL;
6895 rettv->vval.v_string = vim_strsave(buf);
6896}
6897
6898/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006899 * "search()" function
6900 */
6901 static void
6902f_search(typval_T *argvars, typval_T *rettv)
6903{
6904 int flags = 0;
6905
6906 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6907}
6908
6909/*
6910 * "searchdecl()" function
6911 */
6912 static void
6913f_searchdecl(typval_T *argvars, typval_T *rettv)
6914{
Bram Moolenaar30788d32020-09-05 21:35:16 +02006915 int locally = TRUE;
6916 int thisblock = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006917 int error = FALSE;
6918 char_u *name;
6919
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006920 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006921
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006922 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006923 if (argvars[1].v_type != VAR_UNKNOWN)
6924 {
Bram Moolenaar30788d32020-09-05 21:35:16 +02006925 locally = !(int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar30788d32020-09-05 21:35:16 +02006927 thisblock = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006928 }
6929 if (!error && name != NULL)
6930 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6931 locally, thisblock, SEARCH_KEEP) == FAIL;
6932}
6933
6934/*
6935 * Used by searchpair() and searchpairpos()
6936 */
6937 static int
6938searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6939{
6940 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006941 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006942 int save_p_ws = p_ws;
6943 int dir;
6944 int flags = 0;
6945 char_u nbuf1[NUMBUFLEN];
6946 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006947 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 long lnum_stop = 0;
6949 long time_limit = 0;
6950
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006951 // Get the three pattern arguments: start, middle, end. Will result in an
6952 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006953 spat = tv_get_string_chk(&argvars[0]);
6954 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6955 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006956 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006957 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006958
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006959 // Handle the optional fourth argument: flags
6960 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961 if (dir == 0)
6962 goto theend;
6963
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006964 // Don't accept SP_END or SP_SUBPAT.
6965 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 if ((flags & (SP_END | SP_SUBPAT)) != 0
6967 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6968 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006969 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 goto theend;
6971 }
6972
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006973 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974 if (flags & SP_REPEAT)
6975 p_ws = FALSE;
6976
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006977 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006978 if (argvars[3].v_type == VAR_UNKNOWN
6979 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006980 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981 else
6982 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02006983 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01006984 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02006985
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986 if (argvars[5].v_type != VAR_UNKNOWN)
6987 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006988 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006989 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006990 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006991 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006992 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006993 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006994#ifdef FEAT_RELTIME
6995 if (argvars[6].v_type != VAR_UNKNOWN)
6996 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006997 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006998 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006999 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007000 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007001 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007002 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007003 }
7004#endif
7005 }
7006 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007007
7008 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
7009 match_pos, lnum_stop, time_limit);
7010
7011theend:
7012 p_ws = save_p_ws;
7013
7014 return retval;
7015}
7016
7017/*
7018 * "searchpair()" function
7019 */
7020 static void
7021f_searchpair(typval_T *argvars, typval_T *rettv)
7022{
7023 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
7024}
7025
7026/*
7027 * "searchpairpos()" function
7028 */
7029 static void
7030f_searchpairpos(typval_T *argvars, typval_T *rettv)
7031{
7032 pos_T match_pos;
7033 int lnum = 0;
7034 int col = 0;
7035
7036 if (rettv_list_alloc(rettv) == FAIL)
7037 return;
7038
7039 if (searchpair_cmn(argvars, &match_pos) > 0)
7040 {
7041 lnum = match_pos.lnum;
7042 col = match_pos.col;
7043 }
7044
7045 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7046 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7047}
7048
7049/*
7050 * Search for a start/middle/end thing.
7051 * Used by searchpair(), see its documentation for the details.
7052 * Returns 0 or -1 for no match,
7053 */
7054 long
7055do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007056 char_u *spat, // start pattern
7057 char_u *mpat, // middle pattern
7058 char_u *epat, // end pattern
7059 int dir, // BACKWARD or FORWARD
7060 typval_T *skip, // skip expression
7061 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007063 linenr_T lnum_stop, // stop at this line if not zero
7064 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007065{
7066 char_u *save_cpo;
7067 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7068 long retval = 0;
7069 pos_T pos;
7070 pos_T firstpos;
7071 pos_T foundpos;
7072 pos_T save_cursor;
7073 pos_T save_pos;
7074 int n;
7075 int r;
7076 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007077 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078 int err;
7079 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007080#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007081 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007082#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007083
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007084 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007085 save_cpo = p_cpo;
7086 p_cpo = empty_option;
7087
7088#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007089 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007090 profile_setlimit(time_limit, &tm);
7091#endif
7092
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007093 // Make two search patterns: start/end (pat2, for in nested pairs) and
7094 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02007095 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7096 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007097 if (pat2 == NULL || pat3 == NULL)
7098 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007099 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007100 if (*mpat == NUL)
7101 STRCPY(pat3, pat2);
7102 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007103 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007104 spat, epat, mpat);
7105 if (flags & SP_START)
7106 options |= SEARCH_START;
7107
Bram Moolenaar48570482017-10-30 21:48:41 +01007108 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02007109 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01007110
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007111 save_cursor = curwin->w_cursor;
7112 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007113 CLEAR_POS(&firstpos);
7114 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007115 pat = pat3;
7116 for (;;)
7117 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007118 searchit_arg_T sia;
7119
Bram Moolenaara80faa82020-04-12 19:37:17 +02007120 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007121 sia.sa_stop_lnum = lnum_stop;
7122#ifdef FEAT_RELTIME
7123 sia.sa_tm = &tm;
7124#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007125 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007126 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007127 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007128 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007129 break;
7130
7131 if (firstpos.lnum == 0)
7132 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007133 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007134 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007135 // Found the same position again. Can happen with a pattern that
7136 // has "\zs" at the end and searching backwards. Advance one
7137 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007138 if (dir == BACKWARD)
7139 decl(&pos);
7140 else
7141 incl(&pos);
7142 }
7143 foundpos = pos;
7144
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007145 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007146 options &= ~SEARCH_START;
7147
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007148 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007149 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150 {
7151 save_pos = curwin->w_cursor;
7152 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007153 err = FALSE;
7154 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007155 curwin->w_cursor = save_pos;
7156 if (err)
7157 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007158 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007159 curwin->w_cursor = save_cursor;
7160 retval = -1;
7161 break;
7162 }
7163 if (r)
7164 continue;
7165 }
7166
7167 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7168 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007169 // Found end when searching backwards or start when searching
7170 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007171 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007172 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007173 }
7174 else
7175 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007176 // Found end when searching forward or start when searching
7177 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007178 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007179 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007180 }
7181
7182 if (nest == 0)
7183 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007184 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007185 if (flags & SP_RETCOUNT)
7186 ++retval;
7187 else
7188 retval = pos.lnum;
7189 if (flags & SP_SETPCMARK)
7190 setpcmark();
7191 curwin->w_cursor = pos;
7192 if (!(flags & SP_REPEAT))
7193 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007194 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007195 }
7196 }
7197
7198 if (match_pos != NULL)
7199 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007200 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007201 match_pos->lnum = curwin->w_cursor.lnum;
7202 match_pos->col = curwin->w_cursor.col + 1;
7203 }
7204
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007205 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 if ((flags & SP_NOMOVE) || retval == 0)
7207 curwin->w_cursor = save_cursor;
7208
7209theend:
7210 vim_free(pat2);
7211 vim_free(pat3);
7212 if (p_cpo == empty_option)
7213 p_cpo = save_cpo;
7214 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007215 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007216 free_string_option(save_cpo);
7217
7218 return retval;
7219}
7220
7221/*
7222 * "searchpos()" function
7223 */
7224 static void
7225f_searchpos(typval_T *argvars, typval_T *rettv)
7226{
7227 pos_T match_pos;
7228 int lnum = 0;
7229 int col = 0;
7230 int n;
7231 int flags = 0;
7232
7233 if (rettv_list_alloc(rettv) == FAIL)
7234 return;
7235
7236 n = search_cmn(argvars, &match_pos, &flags);
7237 if (n > 0)
7238 {
7239 lnum = match_pos.lnum;
7240 col = match_pos.col;
7241 }
7242
7243 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7244 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7245 if (flags & SP_SUBPAT)
7246 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7247}
7248
7249 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7251{
7252 dict_T *d;
7253 dictitem_T *di;
7254 char_u *csearch;
7255
7256 if (argvars[0].v_type != VAR_DICT)
7257 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007258 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007259 return;
7260 }
7261
7262 if ((d = argvars[0].vval.v_dict) != NULL)
7263 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007264 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007265 if (csearch != NULL)
7266 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 if (enc_utf8)
7268 {
7269 int pcc[MAX_MCO];
7270 int c = utfc_ptr2char(csearch, pcc);
7271
7272 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7273 }
7274 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007275 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007276 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007277 }
7278
7279 di = dict_find(d, (char_u *)"forward", -1);
7280 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007281 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007282 ? FORWARD : BACKWARD);
7283
7284 di = dict_find(d, (char_u *)"until", -1);
7285 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007286 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007287 }
7288}
7289
7290/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007291 * "setenv()" function
7292 */
7293 static void
7294f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7295{
7296 char_u namebuf[NUMBUFLEN];
7297 char_u valbuf[NUMBUFLEN];
7298 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7299
7300 if (argvars[1].v_type == VAR_SPECIAL
7301 && argvars[1].vval.v_number == VVAL_NULL)
7302 vim_unsetenv(name);
7303 else
7304 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7305}
7306
7307/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007308 * "setfperm({fname}, {mode})" function
7309 */
7310 static void
7311f_setfperm(typval_T *argvars, typval_T *rettv)
7312{
7313 char_u *fname;
7314 char_u modebuf[NUMBUFLEN];
7315 char_u *mode_str;
7316 int i;
7317 int mask;
7318 int mode = 0;
7319
7320 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007321 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007322 if (fname == NULL)
7323 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007324 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 if (mode_str == NULL)
7326 return;
7327 if (STRLEN(mode_str) != 9)
7328 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007329 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007330 return;
7331 }
7332
7333 mask = 1;
7334 for (i = 8; i >= 0; --i)
7335 {
7336 if (mode_str[i] != '-')
7337 mode |= mask;
7338 mask = mask << 1;
7339 }
7340 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7341}
7342
7343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 * "setpos()" function
7345 */
7346 static void
7347f_setpos(typval_T *argvars, typval_T *rettv)
7348{
7349 pos_T pos;
7350 int fnum;
7351 char_u *name;
7352 colnr_T curswant = -1;
7353
7354 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007355 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 if (name != NULL)
7357 {
7358 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7359 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007360 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007361 pos.col = 0;
7362 if (name[0] == '.' && name[1] == NUL)
7363 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007364 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007365 curwin->w_cursor = pos;
7366 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007367 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007368 curwin->w_curswant = curswant - 1;
7369 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007370 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007371 check_cursor();
7372 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007373 }
7374 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7375 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007376 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 if (setmark_pos(name[1], &pos, fnum) == OK)
7378 rettv->vval.v_number = 0;
7379 }
7380 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007381 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 }
7383 }
7384}
7385
7386/*
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007387 * Translate a register type string to the yank type and block length
7388 */
7389 static int
7390get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
7391{
7392 char_u *stropt = *pp;
7393 switch (*stropt)
7394 {
7395 case 'v': case 'c': // character-wise selection
7396 *yank_type = MCHAR;
7397 break;
7398 case 'V': case 'l': // line-wise selection
7399 *yank_type = MLINE;
7400 break;
7401 case 'b': case Ctrl_V: // block-wise selection
7402 *yank_type = MBLOCK;
7403 if (VIM_ISDIGIT(stropt[1]))
7404 {
7405 ++stropt;
7406 *block_len = getdigits(&stropt) - 1;
7407 --stropt;
7408 }
7409 break;
7410 default:
7411 return FAIL;
7412 }
7413 *pp = stropt;
7414 return OK;
7415}
7416
7417/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418 * "setreg()" function
7419 */
7420 static void
7421f_setreg(typval_T *argvars, typval_T *rettv)
7422{
7423 int regname;
7424 char_u *strregname;
7425 char_u *stropt;
7426 char_u *strval;
7427 int append;
7428 char_u yank_type;
7429 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007430 typval_T *regcontents;
7431 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007433 pointreg = 0;
7434 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007435 block_len = -1;
7436 yank_type = MAUTO;
7437 append = FALSE;
7438
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007439 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007440 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441
7442 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007443 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007444 regname = *strregname;
7445 if (regname == 0 || regname == '@')
7446 regname = '"';
7447
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007448 if (argvars[1].v_type == VAR_DICT)
7449 {
7450 dict_T *d = argvars[1].vval.v_dict;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007451 dictitem_T *di;
7452
7453 if (d == NULL || d->dv_hashtab.ht_used == 0)
7454 {
7455 // Empty dict, clear the register (like setreg(0, []))
7456 char_u *lstval[2] = {NULL, NULL};
7457 write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
7458 return;
7459 }
7460
7461 di = dict_find(d, (char_u *)"regcontents", -1);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007462 if (di != NULL)
7463 regcontents = &di->di_tv;
7464
7465 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
7466 if (stropt != NULL)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007467 {
7468 int ret = get_yank_type(&stropt, &yank_type, &block_len);
7469
7470 if (ret == FAIL || *++stropt != NUL)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007471 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007472 semsg(_(e_invargval), "value");
7473 return;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007474 }
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007475 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007476
7477 if (regname == '"')
7478 {
7479 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
7480 if (stropt != NULL)
7481 {
7482 pointreg = *stropt;
7483 regname = pointreg;
7484 }
7485 }
Bram Moolenaar6a950582020-08-28 16:39:33 +02007486 else if (dict_get_bool(d, (char_u *)"isunnamed", -1) > 0)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007487 pointreg = regname;
7488 }
7489 else
7490 regcontents = &argvars[1];
7491
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492 if (argvars[2].v_type != VAR_UNKNOWN)
7493 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007494 if (yank_type != MAUTO)
7495 {
7496 semsg(_(e_toomanyarg), "setreg");
7497 return;
7498 }
7499
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007500 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007502 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503 for (; *stropt != NUL; ++stropt)
7504 switch (*stropt)
7505 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007506 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507 append = TRUE;
7508 break;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007509 default:
7510 get_yank_type(&stropt, &yank_type, &block_len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511 }
7512 }
7513
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007514 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 {
7516 char_u **lstval;
7517 char_u **allocval;
7518 char_u buf[NUMBUFLEN];
7519 char_u **curval;
7520 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007521 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 listitem_T *li;
7523 int len;
7524
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007525 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526 len = ll == NULL ? 0 : ll->lv_len;
7527
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007528 // First half: use for pointers to result lines; second half: use for
7529 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007530 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531 if (lstval == NULL)
7532 return;
7533 curval = lstval;
7534 allocval = lstval + len + 2;
7535 curallocval = allocval;
7536
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007537 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007538 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007539 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007540 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007541 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007542 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007543 if (strval == NULL)
7544 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007545 if (strval == buf)
7546 {
7547 // Need to make a copy, next tv_get_string_buf_chk() will
7548 // overwrite the string.
7549 strval = vim_strsave(buf);
7550 if (strval == NULL)
7551 goto free_lstval;
7552 *curallocval++ = strval;
7553 }
7554 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007555 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007556 }
7557 *curval++ = NULL;
7558
7559 write_reg_contents_lst(regname, lstval, -1,
7560 append, yank_type, block_len);
7561free_lstval:
7562 while (curallocval > allocval)
7563 vim_free(*--curallocval);
7564 vim_free(lstval);
7565 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007566 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007568 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007569 if (strval == NULL)
7570 return;
7571 write_reg_contents_ex(regname, strval, -1,
7572 append, yank_type, block_len);
7573 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007574 if (pointreg != 0)
7575 get_yank_register(pointreg, TRUE);
7576
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 rettv->vval.v_number = 0;
7578}
7579
7580/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007581 * "settagstack()" function
7582 */
7583 static void
7584f_settagstack(typval_T *argvars, typval_T *rettv)
7585{
7586 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7587 win_T *wp;
7588 dict_T *d;
7589 int action = 'r';
7590
7591 rettv->vval.v_number = -1;
7592
7593 // first argument: window number or id
7594 wp = find_win_by_nr_or_id(&argvars[0]);
7595 if (wp == NULL)
7596 return;
7597
7598 // second argument: dict with items to set in the tag stack
7599 if (argvars[1].v_type != VAR_DICT)
7600 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007601 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007602 return;
7603 }
7604 d = argvars[1].vval.v_dict;
7605 if (d == NULL)
7606 return;
7607
7608 // third argument: action - 'a' for append and 'r' for replace.
7609 // default is to replace the stack.
7610 if (argvars[2].v_type == VAR_UNKNOWN)
7611 action = 'r';
7612 else if (argvars[2].v_type == VAR_STRING)
7613 {
7614 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007615 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007616 if (actstr == NULL)
7617 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007618 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7619 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007620 action = *actstr;
7621 else
7622 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007623 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007624 return;
7625 }
7626 }
7627 else
7628 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007629 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007630 return;
7631 }
7632
7633 if (set_tagstack(wp, d, action) == OK)
7634 rettv->vval.v_number = 0;
7635}
7636
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007637#ifdef FEAT_CRYPT
7638/*
7639 * "sha256({string})" function
7640 */
7641 static void
7642f_sha256(typval_T *argvars, typval_T *rettv)
7643{
7644 char_u *p;
7645
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007646 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 rettv->vval.v_string = vim_strsave(
7648 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7649 rettv->v_type = VAR_STRING;
7650}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007651#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652
7653/*
7654 * "shellescape({string})" function
7655 */
7656 static void
7657f_shellescape(typval_T *argvars, typval_T *rettv)
7658{
Bram Moolenaar20615522017-06-05 18:46:26 +02007659 int do_special = non_zero_arg(&argvars[1]);
7660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007661 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007662 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007663 rettv->v_type = VAR_STRING;
7664}
7665
7666/*
7667 * shiftwidth() function
7668 */
7669 static void
7670f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7671{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007672 rettv->vval.v_number = 0;
7673
7674 if (argvars[0].v_type != VAR_UNKNOWN)
7675 {
7676 long col;
7677
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007678 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007679 if (col < 0)
7680 return; // type error; errmsg already given
7681#ifdef FEAT_VARTABS
7682 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7683 return;
7684#endif
7685 }
7686
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007687 rettv->vval.v_number = get_sw_value(curbuf);
7688}
7689
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007690#ifdef FEAT_FLOAT
7691/*
7692 * "sin()" function
7693 */
7694 static void
7695f_sin(typval_T *argvars, typval_T *rettv)
7696{
7697 float_T f = 0.0;
7698
7699 rettv->v_type = VAR_FLOAT;
7700 if (get_float_arg(argvars, &f) == OK)
7701 rettv->vval.v_float = sin(f);
7702 else
7703 rettv->vval.v_float = 0.0;
7704}
7705
7706/*
7707 * "sinh()" function
7708 */
7709 static void
7710f_sinh(typval_T *argvars, typval_T *rettv)
7711{
7712 float_T f = 0.0;
7713
7714 rettv->v_type = VAR_FLOAT;
7715 if (get_float_arg(argvars, &f) == OK)
7716 rettv->vval.v_float = sinh(f);
7717 else
7718 rettv->vval.v_float = 0.0;
7719}
7720#endif
7721
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722/*
7723 * "soundfold({word})" function
7724 */
7725 static void
7726f_soundfold(typval_T *argvars, typval_T *rettv)
7727{
7728 char_u *s;
7729
7730 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007731 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007732#ifdef FEAT_SPELL
7733 rettv->vval.v_string = eval_soundfold(s);
7734#else
7735 rettv->vval.v_string = vim_strsave(s);
7736#endif
7737}
7738
7739/*
7740 * "spellbadword()" function
7741 */
7742 static void
7743f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7744{
7745 char_u *word = (char_u *)"";
7746 hlf_T attr = HLF_COUNT;
7747 int len = 0;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007748#ifdef FEAT_SPELL
7749 int wo_spell_save = curwin->w_p_spell;
7750
7751 if (!curwin->w_p_spell)
7752 {
7753 did_set_spelllang(curwin);
7754 curwin->w_p_spell = TRUE;
7755 }
7756
7757 if (*curwin->w_s->b_p_spl == NUL)
7758 {
7759 emsg(_(e_no_spell));
7760 curwin->w_p_spell = wo_spell_save;
7761 return;
7762 }
7763#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007764
7765 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007766 {
7767#ifdef FEAT_SPELL
7768 curwin->w_p_spell = wo_spell_save;
7769#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007771 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007772
7773#ifdef FEAT_SPELL
7774 if (argvars[0].v_type == VAR_UNKNOWN)
7775 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007776 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7778 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007779 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007781 curwin->w_set_curswant = TRUE;
7782 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007783 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007784 else if (*curbuf->b_s.b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007785 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007786 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007787 int capcol = -1;
7788
7789 if (str != NULL)
7790 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007791 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007792 while (*str != NUL)
7793 {
7794 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7795 if (attr != HLF_COUNT)
7796 {
7797 word = str;
7798 break;
7799 }
7800 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007801 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007802 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007803 }
7804 }
7805 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007806 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807#endif
7808
7809 list_append_string(rettv->vval.v_list, word, len);
7810 list_append_string(rettv->vval.v_list, (char_u *)(
7811 attr == HLF_SPB ? "bad" :
7812 attr == HLF_SPR ? "rare" :
7813 attr == HLF_SPL ? "local" :
7814 attr == HLF_SPC ? "caps" :
7815 ""), -1);
7816}
7817
7818/*
7819 * "spellsuggest()" function
7820 */
7821 static void
7822f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7823{
7824#ifdef FEAT_SPELL
7825 char_u *str;
7826 int typeerr = FALSE;
7827 int maxcount;
7828 garray_T ga;
7829 int i;
7830 listitem_T *li;
7831 int need_capital = FALSE;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007832 int wo_spell_save = curwin->w_p_spell;
7833
7834 if (!curwin->w_p_spell)
7835 {
7836 did_set_spelllang(curwin);
7837 curwin->w_p_spell = TRUE;
7838 }
7839
7840 if (*curwin->w_s->b_p_spl == NUL)
7841 {
7842 emsg(_(e_no_spell));
7843 curwin->w_p_spell = wo_spell_save;
7844 return;
7845 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846#endif
7847
7848 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007849 {
7850#ifdef FEAT_SPELL
7851 curwin->w_p_spell = wo_spell_save;
7852#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007854 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007855
7856#ifdef FEAT_SPELL
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007857 if (*curwin->w_s->b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007859 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007860 if (argvars[1].v_type != VAR_UNKNOWN)
7861 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007862 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007863 if (maxcount <= 0)
7864 return;
7865 if (argvars[2].v_type != VAR_UNKNOWN)
7866 {
Bram Moolenaar7c27f332020-09-05 22:45:55 +02007867 need_capital = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 if (typeerr)
7869 return;
7870 }
7871 }
7872 else
7873 maxcount = 25;
7874
7875 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7876
7877 for (i = 0; i < ga.ga_len; ++i)
7878 {
7879 str = ((char_u **)ga.ga_data)[i];
7880
7881 li = listitem_alloc();
7882 if (li == NULL)
7883 vim_free(str);
7884 else
7885 {
7886 li->li_tv.v_type = VAR_STRING;
7887 li->li_tv.v_lock = 0;
7888 li->li_tv.vval.v_string = str;
7889 list_append(rettv->vval.v_list, li);
7890 }
7891 }
7892 ga_clear(&ga);
7893 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007894 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007895#endif
7896}
7897
7898 static void
7899f_split(typval_T *argvars, typval_T *rettv)
7900{
7901 char_u *str;
7902 char_u *end;
7903 char_u *pat = NULL;
7904 regmatch_T regmatch;
7905 char_u patbuf[NUMBUFLEN];
7906 char_u *save_cpo;
7907 int match;
7908 colnr_T col = 0;
7909 int keepempty = FALSE;
7910 int typeerr = FALSE;
7911
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007912 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007913 save_cpo = p_cpo;
7914 p_cpo = (char_u *)"";
7915
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007916 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007917 if (argvars[1].v_type != VAR_UNKNOWN)
7918 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007919 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007920 if (pat == NULL)
7921 typeerr = TRUE;
7922 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar3986b942020-09-06 16:09:04 +02007923 keepempty = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924 }
7925 if (pat == NULL || *pat == NUL)
7926 pat = (char_u *)"[\\x01- ]\\+";
7927
7928 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007929 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007930 if (typeerr)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007931 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007932
7933 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7934 if (regmatch.regprog != NULL)
7935 {
7936 regmatch.rm_ic = FALSE;
7937 while (*str != NUL || keepempty)
7938 {
7939 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007940 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007941 else
7942 match = vim_regexec_nl(&regmatch, str, col);
7943 if (match)
7944 end = regmatch.startp[0];
7945 else
7946 end = str + STRLEN(str);
7947 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7948 && *str != NUL && match && end < regmatch.endp[0]))
7949 {
7950 if (list_append_string(rettv->vval.v_list, str,
7951 (int)(end - str)) == FAIL)
7952 break;
7953 }
7954 if (!match)
7955 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007956 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007957 if (regmatch.endp[0] > str)
7958 col = 0;
7959 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007960 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007961 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007962 str = regmatch.endp[0];
7963 }
7964
7965 vim_regfree(regmatch.regprog);
7966 }
7967
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007968theend:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007969 p_cpo = save_cpo;
7970}
7971
7972#ifdef FEAT_FLOAT
7973/*
7974 * "sqrt()" function
7975 */
7976 static void
7977f_sqrt(typval_T *argvars, typval_T *rettv)
7978{
7979 float_T f = 0.0;
7980
7981 rettv->v_type = VAR_FLOAT;
7982 if (get_float_arg(argvars, &f) == OK)
7983 rettv->vval.v_float = sqrt(f);
7984 else
7985 rettv->vval.v_float = 0.0;
7986}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007987#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007988
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007989#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007990/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991 * "str2float()" function
7992 */
7993 static void
7994f_str2float(typval_T *argvars, typval_T *rettv)
7995{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007996 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007997 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007998
Bram Moolenaar08243d22017-01-10 16:12:29 +01007999 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008000 p = skipwhite(p + 1);
8001 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01008002 if (isneg)
8003 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 rettv->v_type = VAR_FLOAT;
8005}
8006#endif
8007
8008/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02008009 * "str2list()" function
8010 */
8011 static void
8012f_str2list(typval_T *argvars, typval_T *rettv)
8013{
8014 char_u *p;
8015 int utf8 = FALSE;
8016
8017 if (rettv_list_alloc(rettv) == FAIL)
8018 return;
8019
8020 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaara48f7862020-09-05 20:16:57 +02008021 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar9d401282019-04-06 13:18:12 +02008022
8023 p = tv_get_string(&argvars[0]);
8024
8025 if (has_mbyte || utf8)
8026 {
8027 int (*ptr2len)(char_u *);
8028 int (*ptr2char)(char_u *);
8029
8030 if (utf8 || enc_utf8)
8031 {
8032 ptr2len = utf_ptr2len;
8033 ptr2char = utf_ptr2char;
8034 }
8035 else
8036 {
8037 ptr2len = mb_ptr2len;
8038 ptr2char = mb_ptr2char;
8039 }
8040
8041 for ( ; *p != NUL; p += (*ptr2len)(p))
8042 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8043 }
8044 else
8045 for ( ; *p != NUL; ++p)
8046 list_append_number(rettv->vval.v_list, *p);
8047}
8048
8049/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050 * "str2nr()" function
8051 */
8052 static void
8053f_str2nr(typval_T *argvars, typval_T *rettv)
8054{
8055 int base = 10;
8056 char_u *p;
8057 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008058 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008059 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008060
8061 if (argvars[1].v_type != VAR_UNKNOWN)
8062 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008063 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008064 if (base != 2 && base != 8 && base != 10 && base != 16)
8065 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008066 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008067 return;
8068 }
Bram Moolenaar3986b942020-09-06 16:09:04 +02008069 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2]))
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008070 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008071 }
8072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008073 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008074 isneg = (*p == '-');
8075 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008076 p = skipwhite(p + 1);
8077 switch (base)
8078 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008079 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02008080 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008081 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008083 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8084 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008085 if (isneg)
8086 rettv->vval.v_number = -n;
8087 else
8088 rettv->vval.v_number = n;
8089
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008090}
8091
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008092/*
8093 * "strgetchar()" function
8094 */
8095 static void
8096f_strgetchar(typval_T *argvars, typval_T *rettv)
8097{
8098 char_u *str;
8099 int len;
8100 int error = FALSE;
8101 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008102 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008103
8104 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008105 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106 if (str == NULL)
8107 return;
8108 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008109 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008110 if (error)
8111 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008112
Bram Moolenaar13505972019-01-24 15:04:48 +01008113 while (charidx >= 0 && byteidx < len)
8114 {
8115 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008117 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8118 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008120 --charidx;
8121 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008123}
8124
8125/*
8126 * "stridx()" function
8127 */
8128 static void
8129f_stridx(typval_T *argvars, typval_T *rettv)
8130{
8131 char_u buf[NUMBUFLEN];
8132 char_u *needle;
8133 char_u *haystack;
8134 char_u *save_haystack;
8135 char_u *pos;
8136 int start_idx;
8137
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008138 needle = tv_get_string_chk(&argvars[1]);
8139 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140 rettv->vval.v_number = -1;
8141 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008142 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008143
8144 if (argvars[2].v_type != VAR_UNKNOWN)
8145 {
8146 int error = FALSE;
8147
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008148 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008149 if (error || start_idx >= (int)STRLEN(haystack))
8150 return;
8151 if (start_idx >= 0)
8152 haystack += start_idx;
8153 }
8154
8155 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8156 if (pos != NULL)
8157 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8158}
8159
8160/*
8161 * "string()" function
8162 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008163 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164f_string(typval_T *argvars, typval_T *rettv)
8165{
8166 char_u *tofree;
8167 char_u numbuf[NUMBUFLEN];
8168
8169 rettv->v_type = VAR_STRING;
8170 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8171 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008172 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008173 if (rettv->vval.v_string != NULL && tofree == NULL)
8174 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8175}
8176
8177/*
8178 * "strlen()" function
8179 */
8180 static void
8181f_strlen(typval_T *argvars, typval_T *rettv)
8182{
8183 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008184 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008185}
8186
8187/*
8188 * "strchars()" function
8189 */
8190 static void
8191f_strchars(typval_T *argvars, typval_T *rettv)
8192{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008193 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar3986b942020-09-06 16:09:04 +02008194 int skipcc = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 varnumber_T len = 0;
8196 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008197
8198 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar3986b942020-09-06 16:09:04 +02008199 skipcc = (int)tv_get_bool(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008200 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarbade44e2020-09-26 22:39:24 +02008201 semsg(_(e_using_number_as_bool_nr), skipcc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008202 else
8203 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008204 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8205 while (*s != NUL)
8206 {
8207 func_mb_ptr2char_adv(&s);
8208 ++len;
8209 }
8210 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 }
8212}
8213
8214/*
8215 * "strdisplaywidth()" function
8216 */
8217 static void
8218f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8219{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008220 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008221 int col = 0;
8222
8223 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008224 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225
8226 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8227}
8228
8229/*
8230 * "strwidth()" function
8231 */
8232 static void
8233f_strwidth(typval_T *argvars, typval_T *rettv)
8234{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008235 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008236
Bram Moolenaar13505972019-01-24 15:04:48 +01008237 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238}
8239
8240/*
8241 * "strcharpart()" function
8242 */
8243 static void
8244f_strcharpart(typval_T *argvars, typval_T *rettv)
8245{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008246 char_u *p;
8247 int nchar;
8248 int nbyte = 0;
8249 int charlen;
8250 int len = 0;
8251 int slen;
8252 int error = FALSE;
8253
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008254 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008255 slen = (int)STRLEN(p);
8256
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008257 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008258 if (!error)
8259 {
8260 if (nchar > 0)
8261 while (nchar > 0 && nbyte < slen)
8262 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008263 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008264 --nchar;
8265 }
8266 else
8267 nbyte = nchar;
8268 if (argvars[2].v_type != VAR_UNKNOWN)
8269 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008270 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008271 while (charlen > 0 && nbyte + len < slen)
8272 {
8273 int off = nbyte + len;
8274
8275 if (off < 0)
8276 len += 1;
8277 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008278 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008279 --charlen;
8280 }
8281 }
8282 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008283 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008284 }
8285
8286 /*
8287 * Only return the overlap between the specified part and the actual
8288 * string.
8289 */
8290 if (nbyte < 0)
8291 {
8292 len += nbyte;
8293 nbyte = 0;
8294 }
8295 else if (nbyte > slen)
8296 nbyte = slen;
8297 if (len < 0)
8298 len = 0;
8299 else if (nbyte + len > slen)
8300 len = slen - nbyte;
8301
8302 rettv->v_type = VAR_STRING;
8303 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304}
8305
8306/*
8307 * "strpart()" function
8308 */
8309 static void
8310f_strpart(typval_T *argvars, typval_T *rettv)
8311{
8312 char_u *p;
8313 int n;
8314 int len;
8315 int slen;
8316 int error = FALSE;
8317
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008318 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008319 slen = (int)STRLEN(p);
8320
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008321 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008322 if (error)
8323 len = 0;
8324 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008325 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008326 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008327 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008328
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02008329 // Only return the overlap between the specified part and the actual
8330 // string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008331 if (n < 0)
8332 {
8333 len += n;
8334 n = 0;
8335 }
8336 else if (n > slen)
8337 n = slen;
8338 if (len < 0)
8339 len = 0;
8340 else if (n + len > slen)
8341 len = slen - n;
8342
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02008343 if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN)
8344 {
8345 int off;
8346
8347 // length in characters
8348 for (off = n; off < slen && len > 0; --len)
8349 off += mb_ptr2len(p + off);
8350 len = off - n;
8351 }
8352
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 rettv->v_type = VAR_STRING;
8354 rettv->vval.v_string = vim_strnsave(p + n, len);
8355}
8356
8357/*
8358 * "strridx()" function
8359 */
8360 static void
8361f_strridx(typval_T *argvars, typval_T *rettv)
8362{
8363 char_u buf[NUMBUFLEN];
8364 char_u *needle;
8365 char_u *haystack;
8366 char_u *rest;
8367 char_u *lastmatch = NULL;
8368 int haystack_len, end_idx;
8369
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008370 needle = tv_get_string_chk(&argvars[1]);
8371 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008372
8373 rettv->vval.v_number = -1;
8374 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008375 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376
8377 haystack_len = (int)STRLEN(haystack);
8378 if (argvars[2].v_type != VAR_UNKNOWN)
8379 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008380 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008381 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008382 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008383 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384 }
8385 else
8386 end_idx = haystack_len;
8387
8388 if (*needle == NUL)
8389 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008390 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008391 lastmatch = haystack + end_idx;
8392 }
8393 else
8394 {
8395 for (rest = haystack; *rest != '\0'; ++rest)
8396 {
8397 rest = (char_u *)strstr((char *)rest, (char *)needle);
8398 if (rest == NULL || rest > haystack + end_idx)
8399 break;
8400 lastmatch = rest;
8401 }
8402 }
8403
8404 if (lastmatch == NULL)
8405 rettv->vval.v_number = -1;
8406 else
8407 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8408}
8409
8410/*
8411 * "strtrans()" function
8412 */
8413 static void
8414f_strtrans(typval_T *argvars, typval_T *rettv)
8415{
8416 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008417 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008418}
8419
8420/*
8421 * "submatch()" function
8422 */
8423 static void
8424f_submatch(typval_T *argvars, typval_T *rettv)
8425{
8426 int error = FALSE;
8427 int no;
8428 int retList = 0;
8429
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008430 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008431 if (error)
8432 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008433 if (no < 0 || no >= NSUBEXP)
8434 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008435 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008436 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008437 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008438 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaarad304702020-09-06 18:22:53 +02008439 retList = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008440 if (error)
8441 return;
8442
8443 if (retList == 0)
8444 {
8445 rettv->v_type = VAR_STRING;
8446 rettv->vval.v_string = reg_submatch(no);
8447 }
8448 else
8449 {
8450 rettv->v_type = VAR_LIST;
8451 rettv->vval.v_list = reg_submatch_list(no);
8452 }
8453}
8454
8455/*
8456 * "substitute()" function
8457 */
8458 static void
8459f_substitute(typval_T *argvars, typval_T *rettv)
8460{
8461 char_u patbuf[NUMBUFLEN];
8462 char_u subbuf[NUMBUFLEN];
8463 char_u flagsbuf[NUMBUFLEN];
8464
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008465 char_u *str = tv_get_string_chk(&argvars[0]);
8466 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008467 char_u *sub = NULL;
8468 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008469 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008471 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8472 expr = &argvars[2];
8473 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008474 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008475
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008476 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008477 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8478 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008479 rettv->vval.v_string = NULL;
8480 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008481 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008482}
8483
8484/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008485 * "swapinfo(swap_filename)" function
8486 */
8487 static void
8488f_swapinfo(typval_T *argvars, typval_T *rettv)
8489{
8490 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008491 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008492}
8493
8494/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008495 * "swapname(expr)" function
8496 */
8497 static void
8498f_swapname(typval_T *argvars, typval_T *rettv)
8499{
8500 buf_T *buf;
8501
8502 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008503 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008504 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8505 || buf->b_ml.ml_mfp->mf_fname == NULL)
8506 rettv->vval.v_string = NULL;
8507 else
8508 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8509}
8510
8511/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008512 * "synID(lnum, col, trans)" function
8513 */
8514 static void
8515f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8516{
8517 int id = 0;
8518#ifdef FEAT_SYN_HL
8519 linenr_T lnum;
8520 colnr_T col;
8521 int trans;
8522 int transerr = FALSE;
8523
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008524 lnum = tv_get_lnum(argvars); // -1 on type error
8525 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaarfcb6d702020-09-05 21:41:56 +02008526 trans = (int)tv_get_bool_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008527
8528 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8529 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8530 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8531#endif
8532
8533 rettv->vval.v_number = id;
8534}
8535
8536/*
8537 * "synIDattr(id, what [, mode])" function
8538 */
8539 static void
8540f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8541{
8542 char_u *p = NULL;
8543#ifdef FEAT_SYN_HL
8544 int id;
8545 char_u *what;
8546 char_u *mode;
8547 char_u modebuf[NUMBUFLEN];
8548 int modec;
8549
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008550 id = (int)tv_get_number(&argvars[0]);
8551 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008552 if (argvars[2].v_type != VAR_UNKNOWN)
8553 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008554 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008555 modec = TOLOWER_ASC(mode[0]);
8556 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008557 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 }
8559 else
8560 {
8561#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8562 if (USE_24BIT)
8563 modec = 'g';
8564 else
8565#endif
8566 if (t_colors > 1)
8567 modec = 'c';
8568 else
8569 modec = 't';
8570 }
8571
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008572 switch (TOLOWER_ASC(what[0]))
8573 {
8574 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008575 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008576 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008577 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008578 p = highlight_has_attr(id, HL_BOLD, modec);
8579 break;
8580
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008581 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008582 p = highlight_color(id, what, modec);
8583 break;
8584
8585 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008586 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008587 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008588 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008589 p = highlight_has_attr(id, HL_ITALIC, modec);
8590 break;
8591
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008592 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008593 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008594 break;
8595
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008596 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008597 p = highlight_has_attr(id, HL_INVERSE, modec);
8598 break;
8599
8600 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008601 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008602 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008603 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008604 else if (TOLOWER_ASC(what[1]) == 't' &&
8605 TOLOWER_ASC(what[2]) == 'r')
8606 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008607 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608 p = highlight_has_attr(id, HL_STANDOUT, modec);
8609 break;
8610
8611 case 'u':
Bram Moolenaar391c3622020-09-29 20:59:17 +02008612 if (TOLOWER_ASC(what[1]) == 'l') // ul
8613 p = highlight_color(id, what, modec);
8614 else if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008615 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008616 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8617 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008618 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008619 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8620 break;
8621 }
8622
8623 if (p != NULL)
8624 p = vim_strsave(p);
8625#endif
8626 rettv->v_type = VAR_STRING;
8627 rettv->vval.v_string = p;
8628}
8629
8630/*
8631 * "synIDtrans(id)" function
8632 */
8633 static void
8634f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8635{
8636 int id;
8637
8638#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008639 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008640
8641 if (id > 0)
8642 id = syn_get_final_id(id);
8643 else
8644#endif
8645 id = 0;
8646
8647 rettv->vval.v_number = id;
8648}
8649
8650/*
8651 * "synconcealed(lnum, col)" function
8652 */
8653 static void
8654f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8655{
8656#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8657 linenr_T lnum;
8658 colnr_T col;
8659 int syntax_flags = 0;
8660 int cchar;
8661 int matchid = 0;
8662 char_u str[NUMBUFLEN];
8663#endif
8664
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008665 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008666
8667#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008668 lnum = tv_get_lnum(argvars); // -1 on type error
8669 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008670
Bram Moolenaara80faa82020-04-12 19:37:17 +02008671 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008672
8673 if (rettv_list_alloc(rettv) != FAIL)
8674 {
8675 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8676 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8677 && curwin->w_p_cole > 0)
8678 {
8679 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8680 syntax_flags = get_syntax_info(&matchid);
8681
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008682 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008683 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8684 {
8685 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008686 if (cchar == NUL && curwin->w_p_cole == 1)
8687 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008688 if (cchar != NUL)
8689 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008690 if (has_mbyte)
8691 (*mb_char2bytes)(cchar, str);
8692 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008693 str[0] = cchar;
8694 }
8695 }
8696 }
8697
8698 list_append_number(rettv->vval.v_list,
8699 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008700 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008701 list_append_string(rettv->vval.v_list, str, -1);
8702 list_append_number(rettv->vval.v_list, matchid);
8703 }
8704#endif
8705}
8706
8707/*
8708 * "synstack(lnum, col)" function
8709 */
8710 static void
8711f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8712{
8713#ifdef FEAT_SYN_HL
8714 linenr_T lnum;
8715 colnr_T col;
8716 int i;
8717 int id;
8718#endif
8719
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008720 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721
8722#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008723 lnum = tv_get_lnum(argvars); // -1 on type error
8724 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725
8726 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8727 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8728 && rettv_list_alloc(rettv) != FAIL)
8729 {
8730 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8731 for (i = 0; ; ++i)
8732 {
8733 id = syn_get_stack_item(i);
8734 if (id < 0)
8735 break;
8736 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8737 break;
8738 }
8739 }
8740#endif
8741}
8742
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008743/*
8744 * "tabpagebuflist()" function
8745 */
8746 static void
8747f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8748{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008749 tabpage_T *tp;
8750 win_T *wp = NULL;
8751
8752 if (argvars[0].v_type == VAR_UNKNOWN)
8753 wp = firstwin;
8754 else
8755 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008756 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008757 if (tp != NULL)
8758 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8759 }
8760 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8761 {
8762 for (; wp != NULL; wp = wp->w_next)
8763 if (list_append_number(rettv->vval.v_list,
8764 wp->w_buffer->b_fnum) == FAIL)
8765 break;
8766 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008767}
8768
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008769/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008770 * "tagfiles()" function
8771 */
8772 static void
8773f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8774{
8775 char_u *fname;
8776 tagname_T tn;
8777 int first;
8778
8779 if (rettv_list_alloc(rettv) == FAIL)
8780 return;
8781 fname = alloc(MAXPATHL);
8782 if (fname == NULL)
8783 return;
8784
8785 for (first = TRUE; ; first = FALSE)
8786 if (get_tagfname(&tn, first, fname) == FAIL
8787 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8788 break;
8789 tagname_free(&tn);
8790 vim_free(fname);
8791}
8792
8793/*
8794 * "taglist()" function
8795 */
8796 static void
8797f_taglist(typval_T *argvars, typval_T *rettv)
8798{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008799 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008800 char_u *tag_pattern;
8801
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008802 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008803
8804 rettv->vval.v_number = FALSE;
8805 if (*tag_pattern == NUL)
8806 return;
8807
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008808 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008809 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008810 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008811 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008812}
8813
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008814#ifdef FEAT_FLOAT
8815/*
8816 * "tan()" function
8817 */
8818 static void
8819f_tan(typval_T *argvars, typval_T *rettv)
8820{
8821 float_T f = 0.0;
8822
8823 rettv->v_type = VAR_FLOAT;
8824 if (get_float_arg(argvars, &f) == OK)
8825 rettv->vval.v_float = tan(f);
8826 else
8827 rettv->vval.v_float = 0.0;
8828}
8829
8830/*
8831 * "tanh()" function
8832 */
8833 static void
8834f_tanh(typval_T *argvars, typval_T *rettv)
8835{
8836 float_T f = 0.0;
8837
8838 rettv->v_type = VAR_FLOAT;
8839 if (get_float_arg(argvars, &f) == OK)
8840 rettv->vval.v_float = tanh(f);
8841 else
8842 rettv->vval.v_float = 0.0;
8843}
8844#endif
8845
8846/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008847 * "tolower(string)" function
8848 */
8849 static void
8850f_tolower(typval_T *argvars, typval_T *rettv)
8851{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008852 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008853 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008854}
8855
8856/*
8857 * "toupper(string)" function
8858 */
8859 static void
8860f_toupper(typval_T *argvars, typval_T *rettv)
8861{
8862 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008863 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008864}
8865
8866/*
8867 * "tr(string, fromstr, tostr)" function
8868 */
8869 static void
8870f_tr(typval_T *argvars, typval_T *rettv)
8871{
8872 char_u *in_str;
8873 char_u *fromstr;
8874 char_u *tostr;
8875 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008876 int inlen;
8877 int fromlen;
8878 int tolen;
8879 int idx;
8880 char_u *cpstr;
8881 int cplen;
8882 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008883 char_u buf[NUMBUFLEN];
8884 char_u buf2[NUMBUFLEN];
8885 garray_T ga;
8886
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008887 in_str = tv_get_string(&argvars[0]);
8888 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8889 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008890
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008891 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008892 rettv->v_type = VAR_STRING;
8893 rettv->vval.v_string = NULL;
8894 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008895 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008896 ga_init2(&ga, (int)sizeof(char), 80);
8897
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008898 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008899 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008900 if (STRLEN(fromstr) != STRLEN(tostr))
8901 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008903 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008904 ga_clear(&ga);
8905 return;
8906 }
8907
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008908 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008909 while (*in_str != NUL)
8910 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008911 if (has_mbyte)
8912 {
8913 inlen = (*mb_ptr2len)(in_str);
8914 cpstr = in_str;
8915 cplen = inlen;
8916 idx = 0;
8917 for (p = fromstr; *p != NUL; p += fromlen)
8918 {
8919 fromlen = (*mb_ptr2len)(p);
8920 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8921 {
8922 for (p = tostr; *p != NUL; p += tolen)
8923 {
8924 tolen = (*mb_ptr2len)(p);
8925 if (idx-- == 0)
8926 {
8927 cplen = tolen;
8928 cpstr = p;
8929 break;
8930 }
8931 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008932 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008933 goto error;
8934 break;
8935 }
8936 ++idx;
8937 }
8938
8939 if (first && cpstr == in_str)
8940 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008941 // Check that fromstr and tostr have the same number of
8942 // (multi-byte) characters. Done only once when a character
8943 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008944 first = FALSE;
8945 for (p = tostr; *p != NUL; p += tolen)
8946 {
8947 tolen = (*mb_ptr2len)(p);
8948 --idx;
8949 }
8950 if (idx != 0)
8951 goto error;
8952 }
8953
8954 (void)ga_grow(&ga, cplen);
8955 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8956 ga.ga_len += cplen;
8957
8958 in_str += inlen;
8959 }
8960 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008961 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008962 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008963 p = vim_strchr(fromstr, *in_str);
8964 if (p != NULL)
8965 ga_append(&ga, tostr[p - fromstr]);
8966 else
8967 ga_append(&ga, *in_str);
8968 ++in_str;
8969 }
8970 }
8971
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008972 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008973 (void)ga_grow(&ga, 1);
8974 ga_append(&ga, NUL);
8975
8976 rettv->vval.v_string = ga.ga_data;
8977}
8978
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008979/*
8980 * "trim({expr})" function
8981 */
8982 static void
8983f_trim(typval_T *argvars, typval_T *rettv)
8984{
8985 char_u buf1[NUMBUFLEN];
8986 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008987 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008988 char_u *mask = NULL;
8989 char_u *tail;
8990 char_u *prev;
8991 char_u *p;
8992 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008993 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008994
8995 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008996 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008997 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008998 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008999
9000 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009001 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009002 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009003
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009004 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009005 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009006 int error = 0;
9007
9008 // leading or trailing characters to trim
9009 dir = (int)tv_get_number_chk(&argvars[2], &error);
9010 if (error)
9011 return;
9012 if (dir < 0 || dir > 2)
9013 {
9014 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
9015 return;
9016 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009017 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009018 }
9019
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009020 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009021 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009022 // Trim leading characters
9023 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009024 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009025 c1 = PTR2CHAR(head);
9026 if (mask == NULL)
9027 {
9028 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009029 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02009030 }
9031 else
9032 {
9033 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9034 if (c1 == PTR2CHAR(p))
9035 break;
9036 if (*p == NUL)
9037 break;
9038 }
9039 MB_PTR_ADV(head);
9040 }
9041 }
9042
9043 tail = head + STRLEN(head);
9044 if (dir == 0 || dir == 2)
9045 {
9046 // Trim trailing characters
9047 for (; tail > head; tail = prev)
9048 {
9049 prev = tail;
9050 MB_PTR_BACK(head, prev);
9051 c1 = PTR2CHAR(prev);
9052 if (mask == NULL)
9053 {
9054 if (c1 > ' ' && c1 != 0xa0)
9055 break;
9056 }
9057 else
9058 {
9059 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9060 if (c1 == PTR2CHAR(p))
9061 break;
9062 if (*p == NUL)
9063 break;
9064 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009065 }
9066 }
Bram Moolenaardf44a272020-06-07 20:49:05 +02009067 rettv->vval.v_string = vim_strnsave(head, tail - head);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009068}
9069
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009070#ifdef FEAT_FLOAT
9071/*
9072 * "trunc({float})" function
9073 */
9074 static void
9075f_trunc(typval_T *argvars, typval_T *rettv)
9076{
9077 float_T f = 0.0;
9078
9079 rettv->v_type = VAR_FLOAT;
9080 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009081 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009082 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
9083 else
9084 rettv->vval.v_float = 0.0;
9085}
9086#endif
9087
9088/*
9089 * "type(expr)" function
9090 */
9091 static void
9092f_type(typval_T *argvars, typval_T *rettv)
9093{
9094 int n = -1;
9095
9096 switch (argvars[0].v_type)
9097 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009098 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
9099 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009100 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009101 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
9102 case VAR_LIST: n = VAR_TYPE_LIST; break;
9103 case VAR_DICT: n = VAR_TYPE_DICT; break;
9104 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
9105 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
9106 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02009107 case VAR_JOB: n = VAR_TYPE_JOB; break;
9108 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009109 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009110 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02009111 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01009112 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01009113 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009114 n = -1;
9115 break;
9116 }
9117 rettv->vval.v_number = n;
9118}
9119
9120/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009121 * "virtcol(string)" function
9122 */
9123 static void
9124f_virtcol(typval_T *argvars, typval_T *rettv)
9125{
9126 colnr_T vcol = 0;
9127 pos_T *fp;
9128 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009129 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009130
9131 fp = var2fpos(&argvars[0], FALSE, &fnum);
9132 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9133 && fnum == curbuf->b_fnum)
9134 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009135 // Limit the column to a valid value, getvvcol() doesn't check.
9136 if (fp->col < 0)
9137 fp->col = 0;
9138 else
9139 {
9140 len = (int)STRLEN(ml_get(fp->lnum));
9141 if (fp->col > len)
9142 fp->col = len;
9143 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009144 getvvcol(curwin, fp, NULL, NULL, &vcol);
9145 ++vcol;
9146 }
9147
9148 rettv->vval.v_number = vcol;
9149}
9150
9151/*
9152 * "visualmode()" function
9153 */
9154 static void
9155f_visualmode(typval_T *argvars, typval_T *rettv)
9156{
9157 char_u str[2];
9158
9159 rettv->v_type = VAR_STRING;
9160 str[0] = curbuf->b_visual_mode_eval;
9161 str[1] = NUL;
9162 rettv->vval.v_string = vim_strsave(str);
9163
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009164 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009165 if (non_zero_arg(&argvars[0]))
9166 curbuf->b_visual_mode_eval = NUL;
9167}
9168
9169/*
9170 * "wildmenumode()" function
9171 */
9172 static void
9173f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9174{
9175#ifdef FEAT_WILDMENU
9176 if (wild_menu_showing)
9177 rettv->vval.v_number = 1;
9178#endif
9179}
9180
9181/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01009182 * "windowsversion()" function
9183 */
9184 static void
9185f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9186{
9187 rettv->v_type = VAR_STRING;
9188 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
9189}
9190
9191/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009192 * "wordcount()" function
9193 */
9194 static void
9195f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
9196{
9197 if (rettv_dict_alloc(rettv) == FAIL)
9198 return;
9199 cursor_pos_info(rettv->vval.v_dict);
9200}
9201
9202/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009203 * "xor(expr, expr)" function
9204 */
9205 static void
9206f_xor(typval_T *argvars, typval_T *rettv)
9207{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009208 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9209 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009210}
9211
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009212#endif // FEAT_EVAL