blob: e67aa584867d6667bf973fd479d382d9ccf742e0 [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 Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
101static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200102static void f_hlID(typval_T *argvars, typval_T *rettv);
103static void f_hlexists(typval_T *argvars, typval_T *rettv);
104static void f_hostname(typval_T *argvars, typval_T *rettv);
105static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_index(typval_T *argvars, typval_T *rettv);
107static void f_input(typval_T *argvars, typval_T *rettv);
108static void f_inputdialog(typval_T *argvars, typval_T *rettv);
109static void f_inputlist(typval_T *argvars, typval_T *rettv);
110static void f_inputrestore(typval_T *argvars, typval_T *rettv);
111static void f_inputsave(typval_T *argvars, typval_T *rettv);
112static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100113static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200115static void f_islocked(typval_T *argvars, typval_T *rettv);
116#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200117static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_isnan(typval_T *argvars, typval_T *rettv);
119#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200120static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
121static void f_len(typval_T *argvars, typval_T *rettv);
122static void f_libcall(typval_T *argvars, typval_T *rettv);
123static void f_libcallnr(typval_T *argvars, typval_T *rettv);
124static void f_line(typval_T *argvars, typval_T *rettv);
125static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200126#ifdef FEAT_FLOAT
127static void f_log(typval_T *argvars, typval_T *rettv);
128static void f_log10(typval_T *argvars, typval_T *rettv);
129#endif
130#ifdef FEAT_LUA
131static void f_luaeval(typval_T *argvars, typval_T *rettv);
132#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200133static void f_maparg(typval_T *argvars, typval_T *rettv);
134static void f_mapcheck(typval_T *argvars, typval_T *rettv);
135static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200136static void f_matchend(typval_T *argvars, typval_T *rettv);
137static void f_matchlist(typval_T *argvars, typval_T *rettv);
138static void f_matchstr(typval_T *argvars, typval_T *rettv);
139static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
140static void f_max(typval_T *argvars, typval_T *rettv);
141static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200142#ifdef FEAT_MZSCHEME
143static void f_mzeval(typval_T *argvars, typval_T *rettv);
144#endif
145static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
146static void f_nr2char(typval_T *argvars, typval_T *rettv);
147static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200148#ifdef FEAT_PERL
149static void f_perleval(typval_T *argvars, typval_T *rettv);
150#endif
151#ifdef FEAT_FLOAT
152static void f_pow(typval_T *argvars, typval_T *rettv);
153#endif
154static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
155static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200156static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200157static void f_pumvisible(typval_T *argvars, typval_T *rettv);
158#ifdef FEAT_PYTHON3
159static void f_py3eval(typval_T *argvars, typval_T *rettv);
160#endif
161#ifdef FEAT_PYTHON
162static void f_pyeval(typval_T *argvars, typval_T *rettv);
163#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100164#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
165static void f_pyxeval(typval_T *argvars, typval_T *rettv);
166#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100167static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100168static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200169static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200170static void f_reg_executing(typval_T *argvars, typval_T *rettv);
171static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_rename(typval_T *argvars, typval_T *rettv);
173static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174#ifdef FEAT_FLOAT
175static void f_round(typval_T *argvars, typval_T *rettv);
176#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100177#ifdef FEAT_RUBY
178static void f_rubyeval(typval_T *argvars, typval_T *rettv);
179#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200180static void f_screenattr(typval_T *argvars, typval_T *rettv);
181static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100182static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200183static void f_screencol(typval_T *argvars, typval_T *rettv);
184static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100185static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200186static void f_search(typval_T *argvars, typval_T *rettv);
187static void f_searchdecl(typval_T *argvars, typval_T *rettv);
188static void f_searchpair(typval_T *argvars, typval_T *rettv);
189static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
190static void f_searchpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200192static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100196static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197#ifdef FEAT_CRYPT
198static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200199#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_shellescape(typval_T *argvars, typval_T *rettv);
201static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202#ifdef FEAT_FLOAT
203static void f_sin(typval_T *argvars, typval_T *rettv);
204static void f_sinh(typval_T *argvars, typval_T *rettv);
205#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200206static void f_soundfold(typval_T *argvars, typval_T *rettv);
207static void f_spellbadword(typval_T *argvars, typval_T *rettv);
208static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
209static void f_split(typval_T *argvars, typval_T *rettv);
210#ifdef FEAT_FLOAT
211static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100212#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100213static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100214#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200215static void f_str2float(typval_T *argvars, typval_T *rettv);
216#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200217static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200218static void f_str2nr(typval_T *argvars, typval_T *rettv);
219static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200220static void f_strgetchar(typval_T *argvars, typval_T *rettv);
221static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_strlen(typval_T *argvars, typval_T *rettv);
223static void f_strcharpart(typval_T *argvars, typval_T *rettv);
224static void f_strpart(typval_T *argvars, typval_T *rettv);
225static void f_strridx(typval_T *argvars, typval_T *rettv);
226static void f_strtrans(typval_T *argvars, typval_T *rettv);
227static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
228static void f_strwidth(typval_T *argvars, typval_T *rettv);
229static void f_submatch(typval_T *argvars, typval_T *rettv);
230static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200231static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200232static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200233static void f_synID(typval_T *argvars, typval_T *rettv);
234static void f_synIDattr(typval_T *argvars, typval_T *rettv);
235static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
236static void f_synstack(typval_T *argvars, typval_T *rettv);
237static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200238static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200239static void f_taglist(typval_T *argvars, typval_T *rettv);
240static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200241#ifdef FEAT_FLOAT
242static void f_tan(typval_T *argvars, typval_T *rettv);
243static void f_tanh(typval_T *argvars, typval_T *rettv);
244#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_tolower(typval_T *argvars, typval_T *rettv);
246static void f_toupper(typval_T *argvars, typval_T *rettv);
247static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100248static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200249#ifdef FEAT_FLOAT
250static void f_trunc(typval_T *argvars, typval_T *rettv);
251#endif
252static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200253static void f_virtcol(typval_T *argvars, typval_T *rettv);
254static void f_visualmode(typval_T *argvars, typval_T *rettv);
255static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100256static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200257static void f_wordcount(typval_T *argvars, typval_T *rettv);
258static void f_xor(typval_T *argvars, typval_T *rettv);
259
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100260
261 static type_T *
262ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
263{
264 return &t_void;
265}
266 static type_T *
267ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
268{
269 return &t_any;
270}
271 static type_T *
272ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
273{
274 return &t_number;
275}
276 static type_T *
277ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
278{
279 return &t_float;
280}
281 static type_T *
282ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
283{
284 return &t_string;
285}
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200286 static type_T *
287ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100288{
289 return &t_list_any;
290}
291 static type_T *
292ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
293{
294 return &t_list_number;
295}
296 static type_T *
297ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
298{
299 return &t_list_string;
300}
301 static type_T *
302ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
303{
304 return &t_list_dict_any;
305}
306 static type_T *
307ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
308{
309 return &t_dict_any;
310}
311 static type_T *
312ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
313{
314 return &t_dict_number;
315}
316 static type_T *
317ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
318{
319 return &t_dict_string;
320}
321 static type_T *
322ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
323{
324 return &t_blob;
325}
326 static type_T *
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200327ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100328{
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200329 return &t_func_any;
330}
331 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100332ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
333{
334 return &t_channel;
335}
336 static type_T *
337ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
338{
339 return &t_job;
340}
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100341
342static type_T *ret_f_function(int argcount, type_T **argtypes);
343
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200344/*
345 * Array with names and number of arguments of all internal functions
346 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
347 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200348typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200349{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200350 char *f_name; // function name
351 char f_min_argc; // minimal number of arguments
352 char f_max_argc; // maximal number of arguments
353 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100354 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
355 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200356 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200357 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200358} funcentry_T;
359
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200360// values for f_argtype; zero means it cannot be used as a method
361#define FEARG_1 1 // base is the first argument
362#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200363#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200364#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200365#define FEARG_LAST 9 // base is the last argument
366
Bram Moolenaar15c47602020-03-26 22:16:48 +0100367#ifdef FEAT_FLOAT
368# define FLOAT_FUNC(name) name
369#else
370# define FLOAT_FUNC(name) NULL
371#endif
372#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
373# define MATH_FUNC(name) name
374#else
375# define MATH_FUNC(name) NULL
376#endif
377#ifdef FEAT_TIMERS
378# define TIMER_FUNC(name) name
379#else
380# define TIMER_FUNC(name) NULL
381#endif
382#ifdef FEAT_JOB_CHANNEL
383# define JOB_FUNC(name) name
384#else
385# define JOB_FUNC(name) NULL
386#endif
387#ifdef FEAT_PROP_POPUP
388# define PROP_FUNC(name) name
389#else
390# define PROP_FUNC(name) NULL
391#endif
392#ifdef FEAT_SIGNS
393# define SIGN_FUNC(name) name
394#else
395# define SIGN_FUNC(name) NULL
396#endif
397#ifdef FEAT_SOUND
398# define SOUND_FUNC(name) name
399#else
400# define SOUND_FUNC(name) NULL
401#endif
402#ifdef FEAT_TERMINAL
403# define TERM_FUNC(name) name
404#else
405# define TERM_FUNC(name) NULL
406#endif
407
Bram Moolenaarac92e252019-08-03 21:58:38 +0200408static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409{
Bram Moolenaar15c47602020-03-26 22:16:48 +0100410 {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)},
411 {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100412 {"add", 2, 2, FEARG_1, ret_any, f_add},
413 {"and", 2, 2, FEARG_1, ret_number, f_and},
414 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
415 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
416 {"argc", 0, 1, 0, ret_number, f_argc},
417 {"argidx", 0, 0, 0, ret_number, f_argidx},
418 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
419 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100420 {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100421 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
422 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
Bram Moolenaarfb517ba2020-06-03 19:55:35 +0200423 {"assert_equalfile", 2, 3, FEARG_1, ret_number, f_assert_equalfile},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100424 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
425 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
426 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
427 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
428 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
429 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
430 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
431 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
432 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100433 {"atan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_atan)},
434 {"atan2", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_atan2)},
435 {"balloon_gettext", 0, 0, 0, ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100436#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100437 f_balloon_gettext
438#else
439 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100440#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100441 },
442 {"balloon_show", 1, 1, FEARG_1, ret_void,
443#ifdef FEAT_BEVAL
444 f_balloon_show
445#else
446 NULL
447#endif
448 },
449 {"balloon_split", 1, 1, FEARG_1, ret_list_string,
450#if defined(FEAT_BEVAL_TERM)
451 f_balloon_split
452#else
453 NULL
454#endif
455 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100456 {"browse", 4, 4, 0, ret_string, f_browse},
457 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
458 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
459 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
460 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
461 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
462 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
463 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
464 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
465 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
466 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
467 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
468 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
469 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
470 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
471 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
472 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
473 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100474 {"ceil", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_ceil)},
475 {"ch_canread", 1, 1, FEARG_1, ret_number, JOB_FUNC(f_ch_canread)},
476 {"ch_close", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close)},
477 {"ch_close_in", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close_in)},
478 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalexpr)},
479 {"ch_evalraw", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalraw)},
480 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, JOB_FUNC(f_ch_getbufnr)},
481 {"ch_getjob", 1, 1, FEARG_1, ret_job, JOB_FUNC(f_ch_getjob)},
482 {"ch_info", 1, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_ch_info)},
483 {"ch_log", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_log)},
484 {"ch_logfile", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_logfile)},
485 {"ch_open", 1, 2, FEARG_1, ret_channel, JOB_FUNC(f_ch_open)},
486 {"ch_read", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_read)},
487 {"ch_readblob", 1, 2, FEARG_1, ret_blob, JOB_FUNC(f_ch_readblob)},
488 {"ch_readraw", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_readraw)},
489 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendexpr)},
490 {"ch_sendraw", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendraw)},
491 {"ch_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_setoptions)},
492 {"ch_status", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_status)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100493 {"changenr", 0, 0, 0, ret_number, f_changenr},
494 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
495 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
496 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
497 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
498 {"col", 1, 1, FEARG_1, ret_number, f_col},
499 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
500 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
501 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
502 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
503 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
504 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100505 {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)},
506 {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100507 {"count", 2, 4, FEARG_1, ret_number, f_count},
508 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
509 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100510 {"debugbreak", 1, 1, FEARG_1, ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100511#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100512 f_debugbreak
513#else
514 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200515#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100516 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100517 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
518 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
519 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
520 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
521 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
522 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
523 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
524 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
525 {"environ", 0, 0, 0, ret_dict_string, f_environ},
526 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
527 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
528 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
529 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
530 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
531 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
532 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100533 {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100534 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
535 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
536 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
537 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
538 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
539 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
540 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
541 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
542 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
543 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar077a1e62020-06-08 20:50:43 +0200544 {"flatten", 1, 2, FEARG_1, ret_list_any, f_flatten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100545 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)},
546 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)},
547 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100548 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
549 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
550 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
551 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
552 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
553 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
554 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
555 {"foreground", 0, 0, 0, ret_void, f_foreground},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200556 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100557 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
558 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
559 {"get", 2, 3, FEARG_1, ret_any, f_get},
560 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
561 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
562 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
563 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
564 {"getchar", 0, 1, 0, ret_number, f_getchar},
565 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
566 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
567 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
568 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
569 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
570 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
571 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
572 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
573 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
574 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
575 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
576 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
577 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
578 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
579 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
580 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
581 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
582 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
583 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +0200584 {"getmarklist", 0, 1, FEARG_1, ret_list_dict_any, f_getmarklist},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100585 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
586 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
587 {"getpid", 0, 0, 0, ret_number, f_getpid},
588 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
589 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
590 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
Bram Moolenaarbb861e22020-06-07 18:16:36 +0200591 {"getreginfo", 0, 1, FEARG_1, ret_dict_any, f_getreginfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100592 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
593 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
594 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
595 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
596 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
597 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
598 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
599 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
600 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
601 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
602 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
603 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
604 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100605 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100606 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
607 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
608 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
609 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
610 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
611 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
612 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
613 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
614 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
615 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
616 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
617 {"hostname", 0, 0, 0, ret_string, f_hostname},
618 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
619 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
620 {"index", 2, 4, FEARG_1, ret_number, f_index},
621 {"input", 1, 3, FEARG_1, ret_string, f_input},
622 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
623 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
624 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
625 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
626 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
627 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
628 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
629 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
630 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100631 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100632 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100633 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100635 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
636 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
637 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
638 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
639 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
640 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100641 {"join", 1, 2, FEARG_1, ret_string, f_join},
642 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
643 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
644 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
645 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
646 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
647 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
648 {"len", 1, 1, FEARG_1, ret_number, f_len},
649 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
650 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
651 {"line", 1, 2, FEARG_1, ret_number, f_line},
652 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
653 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
654 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
655 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
656 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
657 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
658 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100659 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
660 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
661 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100663 f_luaeval
664#else
665 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100667 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100668 {"map", 2, 2, FEARG_1, ret_any, f_map},
669 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
670 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200671 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100672 {"match", 2, 4, FEARG_1, ret_any, f_match},
673 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
674 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
675 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
676 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
677 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
678 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
679 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
680 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
681 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100682 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100683#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100684 f_menu_info
685#else
686 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100687#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100688 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100689 {"min", 1, 1, FEARG_1, ret_any, f_min},
690 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
691 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100692 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100694 f_mzeval
695#else
696 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200697#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100698 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100699 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
700 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
701 {"or", 2, 2, FEARG_1, ret_number, f_or},
702 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100703 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200704#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100705 f_perleval
706#else
707 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200708#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100709 },
710 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
711 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200712 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100713 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
714 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
715 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
716 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)},
717 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)},
718 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
719 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
720 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
721 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
722 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200723 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100724 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
725 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
726 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
727 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
728 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
729 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
730 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
731 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100732 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
733 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100734 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
735 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
736 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
737 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
738 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
739 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
740 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
741 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
742 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
743 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
744 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
745 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
746 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100747 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
748 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100749 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200750#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100751 f_py3eval
752#else
753 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200754#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100755 },
756 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200757#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100758 f_pyeval
759#else
760 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200761#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100762 },
763 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100764#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100765 f_pyxeval
766#else
767 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100768#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100769 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100770 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
771 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
772 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
Bram Moolenaar6c9ba042020-06-01 16:09:41 +0200773 {"readdirex", 1, 2, FEARG_1, ret_list_dict_any, f_readdirex},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100774 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
Bram Moolenaar85629982020-06-01 18:39:20 +0200775 {"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100776 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
777 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
778 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100779 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100780 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
781 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
782 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
783 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
784 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
785 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
786 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
787 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
788 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
789 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
790 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
791 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100792 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
793 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100794#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100795 f_rubyeval
796#else
797 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100798#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100799 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100800 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
801 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
802 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
803 {"screencol", 0, 0, 0, ret_number, f_screencol},
804 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
805 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
806 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200807 {"search", 1, 5, FEARG_1, ret_number, f_search},
Bram Moolenaare8f5ec02020-06-01 17:28:35 +0200808 {"searchcount", 0, 1, FEARG_1, ret_dict_any, f_searchcount},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100809 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
810 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
811 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200812 {"searchpos", 1, 5, FEARG_1, ret_list_number, f_searchpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100813 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
814 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
815 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
816 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
817 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
818 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
819 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
820 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
821 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
822 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
823 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
824 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
825 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
826 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
827 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
828 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
829 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
830 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100831 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200832#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100833 f_sha256
834#else
835 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100837 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100838 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
839 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100840 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
841 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
842 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
843 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
844 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
845 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
846 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
847 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
848 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200849 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100850 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
851 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100852 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100853 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
854 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
855 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
856 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100857 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
858 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
859 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
860 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100861 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100862 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
863 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100864 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100865 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
866 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
867 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
868 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
869 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100870 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200871#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100872 f_strftime
873#else
874 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200875#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100876 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100877 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
878 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
879 {"string", 1, 1, FEARG_1, ret_string, f_string},
880 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
881 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100882 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100883#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100884 f_strptime
885#else
886 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100887#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100888 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100889 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
890 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
891 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
892 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
893 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
894 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
895 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
896 {"synID", 3, 3, 0, ret_number, f_synID},
897 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
898 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
899 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
900 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
901 {"system", 1, 2, FEARG_1, ret_string, f_system},
902 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
903 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
904 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
905 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
906 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
907 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100908 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
909 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100910 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100911 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
912 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
913 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
914 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
915 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100916#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100917 f_term_getansicolors
918#else
919 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200920#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100921 },
922 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
923 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
924 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
925 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
926 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
927 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
928 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
929 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
930 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
931 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
932 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
933 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
934 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100935#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100936 f_term_setansicolors
937#else
938 NULL
939#endif
940 },
941 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
942 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
943 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
944 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
945 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
946 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100947 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
948 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
949 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
950 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
951 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
952 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
953 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
954 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100955 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100956 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200957 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100958 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100959 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200960 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100961 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
962 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
963 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
964 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100965 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +0200966#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +0100967 f_test_scrollbar
968#else
969 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +0200970#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100971 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100972 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
973 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
974 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
975 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
976 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100977 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
978 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
979 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
980 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
981 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100982 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
983 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
984 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +0200985 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100986 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100987 {"type", 1, 1, FEARG_1, ret_number, f_type},
988 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
989 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
990 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
991 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
992 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
993 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
994 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
995 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
996 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
997 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
998 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
999 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
1000 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
1001 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
1002 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
1003 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
1004 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
1005 {"wincol", 0, 0, 0, ret_number, f_wincol},
1006 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1007 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1008 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1009 {"winline", 0, 0, 0, ret_number, f_winline},
1010 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1011 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1012 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1013 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1014 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1015 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1016 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1017 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001018};
1019
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001020/*
1021 * Function given to ExpandGeneric() to obtain the list of internal
1022 * or user defined function names.
1023 */
1024 char_u *
1025get_function_name(expand_T *xp, int idx)
1026{
1027 static int intidx = -1;
1028 char_u *name;
1029
1030 if (idx == 0)
1031 intidx = -1;
1032 if (intidx < 0)
1033 {
1034 name = get_user_func_name(xp, idx);
1035 if (name != NULL)
1036 return name;
1037 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001038 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001039 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001040 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001041 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001043 STRCAT(IObuff, ")");
1044 return IObuff;
1045 }
1046
1047 return NULL;
1048}
1049
1050/*
1051 * Function given to ExpandGeneric() to obtain the list of internal or
1052 * user defined variable or function names.
1053 */
1054 char_u *
1055get_expr_name(expand_T *xp, int idx)
1056{
1057 static int intidx = -1;
1058 char_u *name;
1059
1060 if (idx == 0)
1061 intidx = -1;
1062 if (intidx < 0)
1063 {
1064 name = get_function_name(xp, idx);
1065 if (name != NULL)
1066 return name;
1067 }
1068 return get_user_var_name(xp, ++intidx);
1069}
1070
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001071/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001072 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001073 * Return index, or -1 if not found or "implemented" is TRUE and the function
1074 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001075 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001076 static int
1077find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001078{
1079 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001080 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001081 int cmp;
1082 int x;
1083
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001084 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001085
1086 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001087 while (first <= last)
1088 {
1089 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001090 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001091 if (cmp < 0)
1092 last = x - 1;
1093 else if (cmp > 0)
1094 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001095 else if (implemented && global_functions[x].f_func == NULL)
1096 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001097 else
1098 return x;
1099 }
1100 return -1;
1101}
1102
Bram Moolenaar15c47602020-03-26 22:16:48 +01001103/*
1104 * Find internal function "name" in table "global_functions".
1105 * Return index, or -1 if not found or the function is not implemented.
1106 */
1107 int
1108find_internal_func(char_u *name)
1109{
1110 return find_internal_func_opt(name, TRUE);
1111}
1112
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001113 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001114has_internal_func(char_u *name)
1115{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001116 return find_internal_func_opt(name, TRUE) >= 0;
1117}
1118
1119 static int
1120has_internal_func_name(char_u *name)
1121{
1122 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001123}
1124
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001125 char *
1126internal_func_name(int idx)
1127{
1128 return global_functions[idx].f_name;
1129}
1130
1131 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001132internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001133{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001134 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001135}
1136
1137/*
1138 * Check the argument count to use for internal function "idx".
1139 * Returns OK or FAIL;
1140 */
1141 int
1142check_internal_func(int idx, int argcount)
1143{
1144 int res;
1145 char *name;
1146
1147 if (argcount < global_functions[idx].f_min_argc)
1148 res = FCERR_TOOFEW;
1149 else if (argcount > global_functions[idx].f_max_argc)
1150 res = FCERR_TOOMANY;
1151 else
1152 return OK;
1153
1154 name = internal_func_name(idx);
1155 if (res == FCERR_TOOMANY)
1156 semsg(_(e_toomanyarg), name);
1157 else
1158 semsg(_(e_toofewarg), name);
1159 return FAIL;
1160}
1161
Bram Moolenaarac92e252019-08-03 21:58:38 +02001162 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001163call_internal_func(
1164 char_u *name,
1165 int argcount,
1166 typval_T *argvars,
1167 typval_T *rettv)
1168{
1169 int i;
1170
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001171 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001172 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001173 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001174 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001175 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001176 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001177 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001178 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001179 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001180 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001181}
1182
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001183 void
1184call_internal_func_by_idx(
1185 int idx,
1186 typval_T *argvars,
1187 typval_T *rettv)
1188{
1189 global_functions[idx].f_func(argvars, rettv);
1190}
1191
Bram Moolenaarac92e252019-08-03 21:58:38 +02001192/*
1193 * Invoke a method for base->method().
1194 */
1195 int
1196call_internal_method(
1197 char_u *name,
1198 int argcount,
1199 typval_T *argvars,
1200 typval_T *rettv,
1201 typval_T *basetv)
1202{
1203 int i;
1204 int fi;
1205 typval_T argv[MAX_FUNC_ARGS + 1];
1206
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001207 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001208 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001209 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001210 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001211 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001212 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001213 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001214 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001215 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001216
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001217 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001218 {
1219 // base value goes last
1220 for (i = 0; i < argcount; ++i)
1221 argv[i] = argvars[i];
1222 argv[argcount] = *basetv;
1223 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001224 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001225 {
1226 // base value goes second
1227 argv[0] = argvars[0];
1228 argv[1] = *basetv;
1229 for (i = 1; i < argcount; ++i)
1230 argv[i + 1] = argvars[i];
1231 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001232 else if (global_functions[fi].f_argtype == FEARG_3)
1233 {
1234 // base value goes third
1235 argv[0] = argvars[0];
1236 argv[1] = argvars[1];
1237 argv[2] = *basetv;
1238 for (i = 2; i < argcount; ++i)
1239 argv[i + 1] = argvars[i];
1240 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001241 else if (global_functions[fi].f_argtype == FEARG_4)
1242 {
1243 // base value goes fourth
1244 argv[0] = argvars[0];
1245 argv[1] = argvars[1];
1246 argv[2] = argvars[2];
1247 argv[3] = *basetv;
1248 for (i = 3; i < argcount; ++i)
1249 argv[i + 1] = argvars[i];
1250 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001251 else
1252 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001253 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001254 argv[0] = *basetv;
1255 for (i = 0; i < argcount; ++i)
1256 argv[i + 1] = argvars[i];
1257 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001258 argv[argcount + 1].v_type = VAR_UNKNOWN;
1259
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001260 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001261 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001262}
1263
1264/*
1265 * Return TRUE for a non-zero Number and a non-empty String.
1266 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001267 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001268non_zero_arg(typval_T *argvars)
1269{
1270 return ((argvars[0].v_type == VAR_NUMBER
1271 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001272 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001273 && argvars[0].vval.v_number == VVAL_TRUE)
1274 || (argvars[0].v_type == VAR_STRING
1275 && argvars[0].vval.v_string != NULL
1276 && *argvars[0].vval.v_string != NUL));
1277}
1278
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001279#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001280/*
1281 * Get the float value of "argvars[0]" into "f".
1282 * Returns FAIL when the argument is not a Number or Float.
1283 */
1284 static int
1285get_float_arg(typval_T *argvars, float_T *f)
1286{
1287 if (argvars[0].v_type == VAR_FLOAT)
1288 {
1289 *f = argvars[0].vval.v_float;
1290 return OK;
1291 }
1292 if (argvars[0].v_type == VAR_NUMBER)
1293 {
1294 *f = (float_T)argvars[0].vval.v_number;
1295 return OK;
1296 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001297 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001298 return FAIL;
1299}
1300
1301/*
1302 * "abs(expr)" function
1303 */
1304 static void
1305f_abs(typval_T *argvars, typval_T *rettv)
1306{
1307 if (argvars[0].v_type == VAR_FLOAT)
1308 {
1309 rettv->v_type = VAR_FLOAT;
1310 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1311 }
1312 else
1313 {
1314 varnumber_T n;
1315 int error = FALSE;
1316
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001317 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001318 if (error)
1319 rettv->vval.v_number = -1;
1320 else if (n > 0)
1321 rettv->vval.v_number = n;
1322 else
1323 rettv->vval.v_number = -n;
1324 }
1325}
1326
1327/*
1328 * "acos()" function
1329 */
1330 static void
1331f_acos(typval_T *argvars, typval_T *rettv)
1332{
1333 float_T f = 0.0;
1334
1335 rettv->v_type = VAR_FLOAT;
1336 if (get_float_arg(argvars, &f) == OK)
1337 rettv->vval.v_float = acos(f);
1338 else
1339 rettv->vval.v_float = 0.0;
1340}
1341#endif
1342
1343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344 * "and(expr, expr)" function
1345 */
1346 static void
1347f_and(typval_T *argvars, typval_T *rettv)
1348{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001349 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1350 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001351}
1352
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353#ifdef FEAT_FLOAT
1354/*
1355 * "asin()" function
1356 */
1357 static void
1358f_asin(typval_T *argvars, typval_T *rettv)
1359{
1360 float_T f = 0.0;
1361
1362 rettv->v_type = VAR_FLOAT;
1363 if (get_float_arg(argvars, &f) == OK)
1364 rettv->vval.v_float = asin(f);
1365 else
1366 rettv->vval.v_float = 0.0;
1367}
1368
1369/*
1370 * "atan()" function
1371 */
1372 static void
1373f_atan(typval_T *argvars, typval_T *rettv)
1374{
1375 float_T f = 0.0;
1376
1377 rettv->v_type = VAR_FLOAT;
1378 if (get_float_arg(argvars, &f) == OK)
1379 rettv->vval.v_float = atan(f);
1380 else
1381 rettv->vval.v_float = 0.0;
1382}
1383
1384/*
1385 * "atan2()" function
1386 */
1387 static void
1388f_atan2(typval_T *argvars, typval_T *rettv)
1389{
1390 float_T fx = 0.0, fy = 0.0;
1391
1392 rettv->v_type = VAR_FLOAT;
1393 if (get_float_arg(argvars, &fx) == OK
1394 && get_float_arg(&argvars[1], &fy) == OK)
1395 rettv->vval.v_float = atan2(fx, fy);
1396 else
1397 rettv->vval.v_float = 0.0;
1398}
1399#endif
1400
1401/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001402 * "balloon_show()" function
1403 */
1404#ifdef FEAT_BEVAL
1405 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001406f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1407{
1408 rettv->v_type = VAR_STRING;
1409 if (balloonEval != NULL)
1410 {
1411 if (balloonEval->msg == NULL)
1412 rettv->vval.v_string = NULL;
1413 else
1414 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1415 }
1416}
1417
1418 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001419f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1420{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001421 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001422 {
1423 if (argvars[0].v_type == VAR_LIST
1424# ifdef FEAT_GUI
1425 && !gui.in_use
1426# endif
1427 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001428 {
1429 list_T *l = argvars[0].vval.v_list;
1430
1431 // empty list removes the balloon
1432 post_balloon(balloonEval, NULL,
1433 l == NULL || l->lv_len == 0 ? NULL : l);
1434 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001435 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001436 {
1437 char_u *mesg = tv_get_string_chk(&argvars[0]);
1438
1439 if (mesg != NULL)
1440 // empty string removes the balloon
1441 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1442 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001443 }
1444}
1445
Bram Moolenaar669a8282017-11-19 20:13:05 +01001446# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001447 static void
1448f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1449{
1450 if (rettv_list_alloc(rettv) == OK)
1451 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001452 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001453
1454 if (msg != NULL)
1455 {
1456 pumitem_T *array;
1457 int size = split_message(msg, &array);
1458 int i;
1459
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001460 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001461 for (i = 1; i < size - 1; ++i)
1462 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001463 while (size > 0)
1464 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001465 vim_free(array);
1466 }
1467 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001468}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001469# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001470#endif
1471
1472/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001473 * Get the buffer from "arg" and give an error and return NULL if it is not
1474 * valid.
1475 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001476 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001477get_buf_arg(typval_T *arg)
1478{
1479 buf_T *buf;
1480
1481 ++emsg_off;
1482 buf = tv_get_buf(arg, FALSE);
1483 --emsg_off;
1484 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001485 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001486 return buf;
1487}
1488
1489/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001490 * "byte2line(byte)" function
1491 */
1492 static void
1493f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1494{
1495#ifndef FEAT_BYTEOFF
1496 rettv->vval.v_number = -1;
1497#else
1498 long boff = 0;
1499
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001500 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 if (boff < 0)
1502 rettv->vval.v_number = -1;
1503 else
1504 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1505 (linenr_T)0, &boff);
1506#endif
1507}
1508
1509 static void
1510byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1511{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001513 char_u *str;
1514 varnumber_T idx;
1515
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001516 str = tv_get_string_chk(&argvars[0]);
1517 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001518 rettv->vval.v_number = -1;
1519 if (str == NULL || idx < 0)
1520 return;
1521
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001522 t = str;
1523 for ( ; idx > 0; idx--)
1524 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001525 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001526 return;
1527 if (enc_utf8 && comp)
1528 t += utf_ptr2len(t);
1529 else
1530 t += (*mb_ptr2len)(t);
1531 }
1532 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533}
1534
1535/*
1536 * "byteidx()" function
1537 */
1538 static void
1539f_byteidx(typval_T *argvars, typval_T *rettv)
1540{
1541 byteidx(argvars, rettv, FALSE);
1542}
1543
1544/*
1545 * "byteidxcomp()" function
1546 */
1547 static void
1548f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1549{
1550 byteidx(argvars, rettv, TRUE);
1551}
1552
1553/*
1554 * "call(func, arglist [, dict])" function
1555 */
1556 static void
1557f_call(typval_T *argvars, typval_T *rettv)
1558{
1559 char_u *func;
1560 partial_T *partial = NULL;
1561 dict_T *selfdict = NULL;
1562
1563 if (argvars[1].v_type != VAR_LIST)
1564 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001565 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001566 return;
1567 }
1568 if (argvars[1].vval.v_list == NULL)
1569 return;
1570
1571 if (argvars[0].v_type == VAR_FUNC)
1572 func = argvars[0].vval.v_string;
1573 else if (argvars[0].v_type == VAR_PARTIAL)
1574 {
1575 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001576 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001577 }
1578 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001579 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001581 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001582
1583 if (argvars[2].v_type != VAR_UNKNOWN)
1584 {
1585 if (argvars[2].v_type != VAR_DICT)
1586 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001587 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001588 return;
1589 }
1590 selfdict = argvars[2].vval.v_dict;
1591 }
1592
1593 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1594}
1595
1596#ifdef FEAT_FLOAT
1597/*
1598 * "ceil({float})" function
1599 */
1600 static void
1601f_ceil(typval_T *argvars, typval_T *rettv)
1602{
1603 float_T f = 0.0;
1604
1605 rettv->v_type = VAR_FLOAT;
1606 if (get_float_arg(argvars, &f) == OK)
1607 rettv->vval.v_float = ceil(f);
1608 else
1609 rettv->vval.v_float = 0.0;
1610}
1611#endif
1612
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001613/*
1614 * "changenr()" function
1615 */
1616 static void
1617f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1618{
1619 rettv->vval.v_number = curbuf->b_u_seq_cur;
1620}
1621
1622/*
1623 * "char2nr(string)" function
1624 */
1625 static void
1626f_char2nr(typval_T *argvars, typval_T *rettv)
1627{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001628 if (has_mbyte)
1629 {
1630 int utf8 = 0;
1631
1632 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001633 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001634
1635 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001636 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001637 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001638 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001639 }
1640 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001641 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001642}
1643
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001644 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001645get_optional_window(typval_T *argvars, int idx)
1646{
1647 win_T *win = curwin;
1648
1649 if (argvars[idx].v_type != VAR_UNKNOWN)
1650 {
1651 win = find_win_by_nr_or_id(&argvars[idx]);
1652 if (win == NULL)
1653 {
1654 emsg(_(e_invalwindow));
1655 return NULL;
1656 }
1657 }
1658 return win;
1659}
1660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001662 * "col(string)" function
1663 */
1664 static void
1665f_col(typval_T *argvars, typval_T *rettv)
1666{
1667 colnr_T col = 0;
1668 pos_T *fp;
1669 int fnum = curbuf->b_fnum;
1670
1671 fp = var2fpos(&argvars[0], FALSE, &fnum);
1672 if (fp != NULL && fnum == curbuf->b_fnum)
1673 {
1674 if (fp->col == MAXCOL)
1675 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001676 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001677 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1678 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1679 else
1680 col = MAXCOL;
1681 }
1682 else
1683 {
1684 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001685 // col(".") when the cursor is on the NUL at the end of the line
1686 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 if (virtual_active() && fp == &curwin->w_cursor)
1688 {
1689 char_u *p = ml_get_cursor();
1690
1691 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1692 curwin->w_virtcol - curwin->w_cursor.coladd))
1693 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001694 int l;
1695
1696 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1697 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001698 }
1699 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001700 }
1701 }
1702 rettv->vval.v_number = col;
1703}
1704
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001705/*
1706 * "confirm(message, buttons[, default [, type]])" function
1707 */
1708 static void
1709f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1710{
1711#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1712 char_u *message;
1713 char_u *buttons = NULL;
1714 char_u buf[NUMBUFLEN];
1715 char_u buf2[NUMBUFLEN];
1716 int def = 1;
1717 int type = VIM_GENERIC;
1718 char_u *typestr;
1719 int error = FALSE;
1720
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001721 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722 if (message == NULL)
1723 error = TRUE;
1724 if (argvars[1].v_type != VAR_UNKNOWN)
1725 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001726 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727 if (buttons == NULL)
1728 error = TRUE;
1729 if (argvars[2].v_type != VAR_UNKNOWN)
1730 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001731 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001732 if (argvars[3].v_type != VAR_UNKNOWN)
1733 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001734 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001735 if (typestr == NULL)
1736 error = TRUE;
1737 else
1738 {
1739 switch (TOUPPER_ASC(*typestr))
1740 {
1741 case 'E': type = VIM_ERROR; break;
1742 case 'Q': type = VIM_QUESTION; break;
1743 case 'I': type = VIM_INFO; break;
1744 case 'W': type = VIM_WARNING; break;
1745 case 'G': type = VIM_GENERIC; break;
1746 }
1747 }
1748 }
1749 }
1750 }
1751
1752 if (buttons == NULL || *buttons == NUL)
1753 buttons = (char_u *)_("&Ok");
1754
1755 if (!error)
1756 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1757 def, NULL, FALSE);
1758#endif
1759}
1760
1761/*
1762 * "copy()" function
1763 */
1764 static void
1765f_copy(typval_T *argvars, typval_T *rettv)
1766{
1767 item_copy(&argvars[0], rettv, FALSE, 0);
1768}
1769
1770#ifdef FEAT_FLOAT
1771/*
1772 * "cos()" function
1773 */
1774 static void
1775f_cos(typval_T *argvars, typval_T *rettv)
1776{
1777 float_T f = 0.0;
1778
1779 rettv->v_type = VAR_FLOAT;
1780 if (get_float_arg(argvars, &f) == OK)
1781 rettv->vval.v_float = cos(f);
1782 else
1783 rettv->vval.v_float = 0.0;
1784}
1785
1786/*
1787 * "cosh()" function
1788 */
1789 static void
1790f_cosh(typval_T *argvars, typval_T *rettv)
1791{
1792 float_T f = 0.0;
1793
1794 rettv->v_type = VAR_FLOAT;
1795 if (get_float_arg(argvars, &f) == OK)
1796 rettv->vval.v_float = cosh(f);
1797 else
1798 rettv->vval.v_float = 0.0;
1799}
1800#endif
1801
1802/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001803 * "cursor(lnum, col)" function, or
1804 * "cursor(list)"
1805 *
1806 * Moves the cursor to the specified line and column.
1807 * Returns 0 when the position could be set, -1 otherwise.
1808 */
1809 static void
1810f_cursor(typval_T *argvars, typval_T *rettv)
1811{
1812 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001814 int set_curswant = TRUE;
1815
1816 rettv->vval.v_number = -1;
1817 if (argvars[1].v_type == VAR_UNKNOWN)
1818 {
1819 pos_T pos;
1820 colnr_T curswant = -1;
1821
1822 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1823 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001824 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 return;
1826 }
1827 line = pos.lnum;
1828 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001829 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 if (curswant >= 0)
1831 {
1832 curwin->w_curswant = curswant - 1;
1833 set_curswant = FALSE;
1834 }
1835 }
1836 else
1837 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001838 line = tv_get_lnum(argvars);
1839 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001841 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001842 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001843 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001844 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001845 if (line > 0)
1846 curwin->w_cursor.lnum = line;
1847 if (col > 0)
1848 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001849 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001850
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001851 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001852 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001853 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001854 if (has_mbyte)
1855 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001856
1857 curwin->w_set_curswant = set_curswant;
1858 rettv->vval.v_number = 0;
1859}
1860
Bram Moolenaar4f974752019-02-17 17:44:42 +01001861#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001862/*
1863 * "debugbreak()" function
1864 */
1865 static void
1866f_debugbreak(typval_T *argvars, typval_T *rettv)
1867{
1868 int pid;
1869
1870 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001871 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001872 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001873 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001874 else
1875 {
1876 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1877
1878 if (hProcess != NULL)
1879 {
1880 DebugBreakProcess(hProcess);
1881 CloseHandle(hProcess);
1882 rettv->vval.v_number = OK;
1883 }
1884 }
1885}
1886#endif
1887
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001888/*
1889 * "deepcopy()" function
1890 */
1891 static void
1892f_deepcopy(typval_T *argvars, typval_T *rettv)
1893{
1894 int noref = 0;
1895 int copyID;
1896
1897 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001898 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001899 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001900 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001901 else
1902 {
1903 copyID = get_copyID();
1904 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1905 }
1906}
1907
1908/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001909 * "did_filetype()" function
1910 */
1911 static void
1912f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1913{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001914 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001915}
1916
1917/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001918 * "echoraw({expr})" function
1919 */
1920 static void
1921f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1922{
1923 char_u *str = tv_get_string_chk(&argvars[0]);
1924
1925 if (str != NULL && *str != NUL)
1926 {
1927 out_str(str);
1928 out_flush();
1929 }
1930}
1931
1932/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001933 * "empty({expr})" function
1934 */
1935 static void
1936f_empty(typval_T *argvars, typval_T *rettv)
1937{
1938 int n = FALSE;
1939
1940 switch (argvars[0].v_type)
1941 {
1942 case VAR_STRING:
1943 case VAR_FUNC:
1944 n = argvars[0].vval.v_string == NULL
1945 || *argvars[0].vval.v_string == NUL;
1946 break;
1947 case VAR_PARTIAL:
1948 n = FALSE;
1949 break;
1950 case VAR_NUMBER:
1951 n = argvars[0].vval.v_number == 0;
1952 break;
1953 case VAR_FLOAT:
1954#ifdef FEAT_FLOAT
1955 n = argvars[0].vval.v_float == 0.0;
1956 break;
1957#endif
1958 case VAR_LIST:
1959 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001960 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001961 break;
1962 case VAR_DICT:
1963 n = argvars[0].vval.v_dict == NULL
1964 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1965 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001966 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001967 case VAR_SPECIAL:
1968 n = argvars[0].vval.v_number != VVAL_TRUE;
1969 break;
1970
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001971 case VAR_BLOB:
1972 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001973 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1974 break;
1975
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 case VAR_JOB:
1977#ifdef FEAT_JOB_CHANNEL
1978 n = argvars[0].vval.v_job == NULL
1979 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1980 break;
1981#endif
1982 case VAR_CHANNEL:
1983#ifdef FEAT_JOB_CHANNEL
1984 n = argvars[0].vval.v_channel == NULL
1985 || !channel_is_open(argvars[0].vval.v_channel);
1986 break;
1987#endif
1988 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02001989 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001990 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001991 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001992 n = TRUE;
1993 break;
1994 }
1995
1996 rettv->vval.v_number = n;
1997}
1998
1999/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002000 * "environ()" function
2001 */
2002 static void
2003f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2004{
2005#if !defined(AMIGA)
2006 int i = 0;
2007 char_u *entry, *value;
2008# ifdef MSWIN
2009 extern wchar_t **_wenviron;
2010# else
2011 extern char **environ;
2012# endif
2013
2014 if (rettv_dict_alloc(rettv) != OK)
2015 return;
2016
2017# ifdef MSWIN
2018 if (*_wenviron == NULL)
2019 return;
2020# else
2021 if (*environ == NULL)
2022 return;
2023# endif
2024
2025 for (i = 0; ; ++i)
2026 {
2027# ifdef MSWIN
2028 short_u *p;
2029
2030 if ((p = (short_u *)_wenviron[i]) == NULL)
2031 return;
2032 entry = utf16_to_enc(p, NULL);
2033# else
2034 if ((entry = (char_u *)environ[i]) == NULL)
2035 return;
2036 entry = vim_strsave(entry);
2037# endif
2038 if (entry == NULL) // out of memory
2039 return;
2040 if ((value = vim_strchr(entry, '=')) == NULL)
2041 {
2042 vim_free(entry);
2043 continue;
2044 }
2045 *value++ = NUL;
2046 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2047 vim_free(entry);
2048 }
2049#endif
2050}
2051
2052/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002053 * "escape({string}, {chars})" function
2054 */
2055 static void
2056f_escape(typval_T *argvars, typval_T *rettv)
2057{
2058 char_u buf[NUMBUFLEN];
2059
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002060 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2061 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002062 rettv->v_type = VAR_STRING;
2063}
2064
2065/*
2066 * "eval()" function
2067 */
2068 static void
2069f_eval(typval_T *argvars, typval_T *rettv)
2070{
2071 char_u *s, *p;
2072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002073 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002074 if (s != NULL)
2075 s = skipwhite(s);
2076
2077 p = s;
Bram Moolenaar32e35112020-05-14 22:41:15 +02002078 if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002079 {
2080 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002081 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082 need_clr_eos = FALSE;
2083 rettv->v_type = VAR_NUMBER;
2084 rettv->vval.v_number = 0;
2085 }
2086 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002087 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088}
2089
2090/*
2091 * "eventhandler()" function
2092 */
2093 static void
2094f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2095{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002096 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097}
2098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002099static garray_T redir_execute_ga;
2100
2101/*
2102 * Append "value[value_len]" to the execute() output.
2103 */
2104 void
2105execute_redir_str(char_u *value, int value_len)
2106{
2107 int len;
2108
2109 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002110 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002111 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002112 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002113 if (ga_grow(&redir_execute_ga, len) == OK)
2114 {
2115 mch_memmove((char *)redir_execute_ga.ga_data
2116 + redir_execute_ga.ga_len, value, len);
2117 redir_execute_ga.ga_len += len;
2118 }
2119}
2120
2121/*
2122 * Get next line from a list.
2123 * Called by do_cmdline() to get the next line.
2124 * Returns allocated string, or NULL for end of function.
2125 */
2126
2127 static char_u *
2128get_list_line(
2129 int c UNUSED,
2130 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002131 int indent UNUSED,
2132 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002133{
2134 listitem_T **p = (listitem_T **)cookie;
2135 listitem_T *item = *p;
2136 char_u buf[NUMBUFLEN];
2137 char_u *s;
2138
2139 if (item == NULL)
2140 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002141 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002142 *p = item->li_next;
2143 return s == NULL ? NULL : vim_strsave(s);
2144}
2145
2146/*
2147 * "execute()" function
2148 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002149 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002150execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002151{
2152 char_u *cmd = NULL;
2153 list_T *list = NULL;
2154 int save_msg_silent = msg_silent;
2155 int save_emsg_silent = emsg_silent;
2156 int save_emsg_noredir = emsg_noredir;
2157 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002158 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002159 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002160 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002161 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162
2163 rettv->vval.v_string = NULL;
2164 rettv->v_type = VAR_STRING;
2165
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002166 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002168 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002169 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002170 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171 return;
2172 ++list->lv_refcount;
2173 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002174 else if (argvars[arg_off].v_type == VAR_JOB
2175 || argvars[arg_off].v_type == VAR_CHANNEL)
2176 {
2177 emsg(_(e_inval_string));
2178 return;
2179 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180 else
2181 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002182 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002183 if (cmd == NULL)
2184 return;
2185 }
2186
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002187 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002188 {
2189 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002190 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002191
2192 if (s == NULL)
2193 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002194 if (*s == NUL)
2195 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002196 if (STRNCMP(s, "silent", 6) == 0)
2197 ++msg_silent;
2198 if (STRCMP(s, "silent!") == 0)
2199 {
2200 emsg_silent = TRUE;
2201 emsg_noredir = TRUE;
2202 }
2203 }
2204 else
2205 ++msg_silent;
2206
2207 if (redir_execute)
2208 save_ga = redir_execute_ga;
2209 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2210 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002211 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002212 if (!echo_output)
2213 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002214
2215 if (cmd != NULL)
2216 do_cmdline_cmd(cmd);
2217 else
2218 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002219 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002220
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002221 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002222 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002223 do_cmdline(NULL, get_list_line, (void *)&item,
2224 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2225 --list->lv_refcount;
2226 }
2227
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002228 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002229 if (ga_grow(&redir_execute_ga, 1) == OK)
2230 {
2231 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2232 rettv->vval.v_string = redir_execute_ga.ga_data;
2233 }
2234 else
2235 {
2236 ga_clear(&redir_execute_ga);
2237 rettv->vval.v_string = NULL;
2238 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002239 msg_silent = save_msg_silent;
2240 emsg_silent = save_emsg_silent;
2241 emsg_noredir = save_emsg_noredir;
2242
2243 redir_execute = save_redir_execute;
2244 if (redir_execute)
2245 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002246 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002247
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002248 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002249 if (echo_output)
2250 // When not working silently: put it in column zero. A following
2251 // "echon" will overwrite the message, unavoidably.
2252 msg_col = 0;
2253 else
2254 // When working silently: Put it back where it was, since nothing
2255 // should have been written.
2256 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002257}
2258
2259/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002260 * "execute()" function
2261 */
2262 static void
2263f_execute(typval_T *argvars, typval_T *rettv)
2264{
2265 execute_common(argvars, rettv, 0);
2266}
2267
2268/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 * "exists()" function
2270 */
2271 static void
2272f_exists(typval_T *argvars, typval_T *rettv)
2273{
2274 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002276
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002277 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002278 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002279 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002280 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002281 if (mch_getenv(p + 1) != NULL)
2282 n = TRUE;
2283 else
2284 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002285 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002286 p = expand_env_save(p);
2287 if (p != NULL && *p != '$')
2288 n = TRUE;
2289 vim_free(p);
2290 }
2291 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002292 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293 {
2294 n = (get_option_tv(&p, NULL, TRUE) == OK);
2295 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002296 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002298 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002299 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002300 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002302 else if (*p == '?') // internal function only
2303 {
2304 n = has_internal_func_name(p + 1);
2305 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002306 else if (*p == ':')
2307 {
2308 n = cmd_exists(p + 1);
2309 }
2310 else if (*p == '#')
2311 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002312 if (p[1] == '#')
2313 n = autocmd_supported(p + 2);
2314 else
2315 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002316 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002317 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002318 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002319 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002320 }
2321
2322 rettv->vval.v_number = n;
2323}
2324
2325#ifdef FEAT_FLOAT
2326/*
2327 * "exp()" function
2328 */
2329 static void
2330f_exp(typval_T *argvars, typval_T *rettv)
2331{
2332 float_T f = 0.0;
2333
2334 rettv->v_type = VAR_FLOAT;
2335 if (get_float_arg(argvars, &f) == OK)
2336 rettv->vval.v_float = exp(f);
2337 else
2338 rettv->vval.v_float = 0.0;
2339}
2340#endif
2341
2342/*
2343 * "expand()" function
2344 */
2345 static void
2346f_expand(typval_T *argvars, typval_T *rettv)
2347{
2348 char_u *s;
2349 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002350 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002351 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2352 expand_T xpc;
2353 int error = FALSE;
2354 char_u *result;
2355
2356 rettv->v_type = VAR_STRING;
2357 if (argvars[1].v_type != VAR_UNKNOWN
2358 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002359 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002361 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002362
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002363 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 if (*s == '%' || *s == '#' || *s == '<')
2365 {
2366 ++emsg_off;
2367 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2368 --emsg_off;
2369 if (rettv->v_type == VAR_LIST)
2370 {
2371 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2372 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002373 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002374 }
2375 else
2376 rettv->vval.v_string = result;
2377 }
2378 else
2379 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002380 // When the optional second argument is non-zero, don't remove matches
2381 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002382 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002383 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002384 options |= WILD_KEEP_ALL;
2385 if (!error)
2386 {
2387 ExpandInit(&xpc);
2388 xpc.xp_context = EXPAND_FILES;
2389 if (p_wic)
2390 options += WILD_ICASE;
2391 if (rettv->v_type == VAR_STRING)
2392 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2393 options, WILD_ALL);
2394 else if (rettv_list_alloc(rettv) != FAIL)
2395 {
2396 int i;
2397
2398 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2399 for (i = 0; i < xpc.xp_numfiles; i++)
2400 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2401 ExpandCleanup(&xpc);
2402 }
2403 }
2404 else
2405 rettv->vval.v_string = NULL;
2406 }
2407}
2408
2409/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002410 * "expandcmd()" function
2411 * Expand all the special characters in a command string.
2412 */
2413 static void
2414f_expandcmd(typval_T *argvars, typval_T *rettv)
2415{
2416 exarg_T eap;
2417 char_u *cmdstr;
2418 char *errormsg = NULL;
2419
2420 rettv->v_type = VAR_STRING;
2421 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2422
2423 memset(&eap, 0, sizeof(eap));
2424 eap.cmd = cmdstr;
2425 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002426 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002427 eap.usefilter = FALSE;
2428 eap.nextcmd = NULL;
2429 eap.cmdidx = CMD_USER;
2430
2431 expand_filename(&eap, &cmdstr, &errormsg);
2432 if (errormsg != NULL && *errormsg != NUL)
2433 emsg(errormsg);
2434
2435 rettv->vval.v_string = cmdstr;
2436}
2437
2438/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002439 * "feedkeys()" function
2440 */
2441 static void
2442f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2443{
2444 int remap = TRUE;
2445 int insert = FALSE;
2446 char_u *keys, *flags;
2447 char_u nbuf[NUMBUFLEN];
2448 int typed = FALSE;
2449 int execute = FALSE;
2450 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002451 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 char_u *keys_esc;
2453
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002454 // This is not allowed in the sandbox. If the commands would still be
2455 // executed in the sandbox it would be OK, but it probably happens later,
2456 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457 if (check_secure())
2458 return;
2459
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002460 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461
2462 if (argvars[1].v_type != VAR_UNKNOWN)
2463 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002464 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 for ( ; *flags != NUL; ++flags)
2466 {
2467 switch (*flags)
2468 {
2469 case 'n': remap = FALSE; break;
2470 case 'm': remap = TRUE; break;
2471 case 't': typed = TRUE; break;
2472 case 'i': insert = TRUE; break;
2473 case 'x': execute = TRUE; break;
2474 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002475 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476 }
2477 }
2478 }
2479
2480 if (*keys != NUL || execute)
2481 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002482 // Need to escape K_SPECIAL and CSI before putting the string in the
2483 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002484 keys_esc = vim_strsave_escape_csi(keys);
2485 if (keys_esc != NULL)
2486 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002487 if (lowlevel)
2488 {
2489#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002490 int idx;
2491 int len = (int)STRLEN(keys);
2492
2493 for (idx = 0; idx < len; ++idx)
2494 {
2495 // if a CTRL-C was typed, set got_int, similar to what
2496 // happens in fill_input_buf()
2497 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2498 got_int = TRUE;
2499 add_to_input_buf(keys + idx, 1);
2500 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002501#else
2502 emsg(_("E980: lowlevel input not supported"));
2503#endif
2504 }
2505 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002506 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002507 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002508 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002509 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002510#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002511 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002512#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002513 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002514 typebuf_was_filled = TRUE;
2515 }
2516 vim_free(keys_esc);
2517
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002518 if (execute)
2519 {
2520 int save_msg_scroll = msg_scroll;
2521
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002522 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002523 msg_scroll = FALSE;
2524
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002525 if (!dangerous)
2526 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002527 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002528 if (!dangerous)
2529 --ex_normal_busy;
2530
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002531 msg_scroll |= save_msg_scroll;
2532 }
2533 }
2534 }
2535}
2536
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537#ifdef FEAT_FLOAT
2538/*
2539 * "float2nr({float})" function
2540 */
2541 static void
2542f_float2nr(typval_T *argvars, typval_T *rettv)
2543{
2544 float_T f = 0.0;
2545
2546 if (get_float_arg(argvars, &f) == OK)
2547 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002548 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002549 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002550 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002551 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 else
2553 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 }
2555}
2556
2557/*
2558 * "floor({float})" function
2559 */
2560 static void
2561f_floor(typval_T *argvars, typval_T *rettv)
2562{
2563 float_T f = 0.0;
2564
2565 rettv->v_type = VAR_FLOAT;
2566 if (get_float_arg(argvars, &f) == OK)
2567 rettv->vval.v_float = floor(f);
2568 else
2569 rettv->vval.v_float = 0.0;
2570}
2571
2572/*
2573 * "fmod()" function
2574 */
2575 static void
2576f_fmod(typval_T *argvars, typval_T *rettv)
2577{
2578 float_T fx = 0.0, fy = 0.0;
2579
2580 rettv->v_type = VAR_FLOAT;
2581 if (get_float_arg(argvars, &fx) == OK
2582 && get_float_arg(&argvars[1], &fy) == OK)
2583 rettv->vval.v_float = fmod(fx, fy);
2584 else
2585 rettv->vval.v_float = 0.0;
2586}
2587#endif
2588
2589/*
2590 * "fnameescape({string})" function
2591 */
2592 static void
2593f_fnameescape(typval_T *argvars, typval_T *rettv)
2594{
2595 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002596 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002597 rettv->v_type = VAR_STRING;
2598}
2599
2600/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601 * "foreground()" function
2602 */
2603 static void
2604f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2605{
2606#ifdef FEAT_GUI
2607 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002608 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002610 return;
2611 }
2612#endif
2613#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002615#endif
2616}
2617
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002619common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620{
2621 char_u *s;
2622 char_u *name;
2623 int use_string = FALSE;
2624 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002625 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002626 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627
2628 if (argvars[0].v_type == VAR_FUNC)
2629 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002630 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002631 s = argvars[0].vval.v_string;
2632 }
2633 else if (argvars[0].v_type == VAR_PARTIAL
2634 && argvars[0].vval.v_partial != NULL)
2635 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002636 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002637 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002638 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002639 }
2640 else
2641 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002642 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002643 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002644 use_string = TRUE;
2645 }
2646
Bram Moolenaar843b8842016-08-21 14:36:15 +02002647 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002648 {
2649 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002650 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002651 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2652 if (*name != NUL)
2653 s = NULL;
2654 }
2655
Bram Moolenaar843b8842016-08-21 14:36:15 +02002656 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2657 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002658 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002659 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002660 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002661 ? find_func(trans_name, is_global, NULL) == NULL
2662 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002663 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002664 else
2665 {
2666 int dict_idx = 0;
2667 int arg_idx = 0;
2668 list_T *list = NULL;
2669
2670 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2671 {
2672 char sid_buf[25];
2673 int off = *s == 's' ? 2 : 5;
2674
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002675 // Expand s: and <SID> into <SNR>nr_, so that the function can
2676 // also be called from another script. Using trans_function_name()
2677 // would also work, but some plugins depend on the name being
2678 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002679 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002680 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002681 if (name != NULL)
2682 {
2683 STRCPY(name, sid_buf);
2684 STRCAT(name, s + off);
2685 }
2686 }
2687 else
2688 name = vim_strsave(s);
2689
2690 if (argvars[1].v_type != VAR_UNKNOWN)
2691 {
2692 if (argvars[2].v_type != VAR_UNKNOWN)
2693 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002694 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002695 arg_idx = 1;
2696 dict_idx = 2;
2697 }
2698 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002699 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002700 dict_idx = 1;
2701 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002702 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703 arg_idx = 1;
2704 if (dict_idx > 0)
2705 {
2706 if (argvars[dict_idx].v_type != VAR_DICT)
2707 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002708 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002710 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711 }
2712 if (argvars[dict_idx].vval.v_dict == NULL)
2713 dict_idx = 0;
2714 }
2715 if (arg_idx > 0)
2716 {
2717 if (argvars[arg_idx].v_type != VAR_LIST)
2718 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002719 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002720 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002721 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002722 }
2723 list = argvars[arg_idx].vval.v_list;
2724 if (list == NULL || list->lv_len == 0)
2725 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002726 else if (list->lv_len > MAX_FUNC_ARGS)
2727 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002728 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002729 vim_free(name);
2730 goto theend;
2731 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002732 }
2733 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002734 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002735 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002736 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002737
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002738 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002739 if (pt == NULL)
2740 vim_free(name);
2741 else
2742 {
2743 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2744 {
2745 listitem_T *li;
2746 int i = 0;
2747 int arg_len = 0;
2748 int lv_len = 0;
2749
2750 if (arg_pt != NULL)
2751 arg_len = arg_pt->pt_argc;
2752 if (list != NULL)
2753 lv_len = list->lv_len;
2754 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002755 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 if (pt->pt_argv == NULL)
2757 {
2758 vim_free(pt);
2759 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002760 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002761 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002762 for (i = 0; i < arg_len; i++)
2763 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2764 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002765 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002766 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002767 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002768 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002769 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 }
2771
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002772 // For "function(dict.func, [], dict)" and "func" is a partial
2773 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002774 if (dict_idx > 0)
2775 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002776 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002777 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2778 ++pt->pt_dict->dv_refcount;
2779 }
2780 else if (arg_pt != NULL)
2781 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002782 // If the dict was bound automatically the result is also
2783 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002784 pt->pt_dict = arg_pt->pt_dict;
2785 pt->pt_auto = arg_pt->pt_auto;
2786 if (pt->pt_dict != NULL)
2787 ++pt->pt_dict->dv_refcount;
2788 }
2789
2790 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002791 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2792 {
2793 pt->pt_func = arg_pt->pt_func;
2794 func_ptr_ref(pt->pt_func);
2795 vim_free(name);
2796 }
2797 else if (is_funcref)
2798 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002799 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002800 func_ptr_ref(pt->pt_func);
2801 vim_free(name);
2802 }
2803 else
2804 {
2805 pt->pt_name = name;
2806 func_ref(name);
2807 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002808 }
2809 rettv->v_type = VAR_PARTIAL;
2810 rettv->vval.v_partial = pt;
2811 }
2812 else
2813 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002814 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002815 rettv->v_type = VAR_FUNC;
2816 rettv->vval.v_string = name;
2817 func_ref(name);
2818 }
2819 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002820theend:
2821 vim_free(trans_name);
2822}
2823
2824/*
2825 * "funcref()" function
2826 */
2827 static void
2828f_funcref(typval_T *argvars, typval_T *rettv)
2829{
2830 common_function(argvars, rettv, TRUE);
2831}
2832
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002833 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002834ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002835{
2836 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2837 return &t_func_any;
Bram Moolenaard77a8522020-04-03 21:59:57 +02002838 return &t_func_void;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002839}
2840
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002841/*
2842 * "function()" function
2843 */
2844 static void
2845f_function(typval_T *argvars, typval_T *rettv)
2846{
2847 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848}
2849
2850/*
2851 * "garbagecollect()" function
2852 */
2853 static void
2854f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2855{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002856 // This is postponed until we are back at the toplevel, because we may be
2857 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002858 want_garbage_collect = TRUE;
2859
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002860 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002861 garbage_collect_at_exit = TRUE;
2862}
2863
2864/*
2865 * "get()" function
2866 */
2867 static void
2868f_get(typval_T *argvars, typval_T *rettv)
2869{
2870 listitem_T *li;
2871 list_T *l;
2872 dictitem_T *di;
2873 dict_T *d;
2874 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002875 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002877 if (argvars[0].v_type == VAR_BLOB)
2878 {
2879 int error = FALSE;
2880 int idx = tv_get_number_chk(&argvars[1], &error);
2881
2882 if (!error)
2883 {
2884 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002885 if (idx < 0)
2886 idx = blob_len(argvars[0].vval.v_blob) + idx;
2887 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2888 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002889 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002890 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002891 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002892 tv = rettv;
2893 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002894 }
2895 }
2896 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002897 {
2898 if ((l = argvars[0].vval.v_list) != NULL)
2899 {
2900 int error = FALSE;
2901
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002902 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002903 if (!error && li != NULL)
2904 tv = &li->li_tv;
2905 }
2906 }
2907 else if (argvars[0].v_type == VAR_DICT)
2908 {
2909 if ((d = argvars[0].vval.v_dict) != NULL)
2910 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002911 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 if (di != NULL)
2913 tv = &di->di_tv;
2914 }
2915 }
2916 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2917 {
2918 partial_T *pt;
2919 partial_T fref_pt;
2920
2921 if (argvars[0].v_type == VAR_PARTIAL)
2922 pt = argvars[0].vval.v_partial;
2923 else
2924 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02002925 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926 fref_pt.pt_name = argvars[0].vval.v_string;
2927 pt = &fref_pt;
2928 }
2929
2930 if (pt != NULL)
2931 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002932 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002933 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002934
2935 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2936 {
2937 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002938 n = partial_name(pt);
2939 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940 rettv->vval.v_string = NULL;
2941 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002942 {
2943 rettv->vval.v_string = vim_strsave(n);
2944 if (rettv->v_type == VAR_FUNC)
2945 func_ref(rettv->vval.v_string);
2946 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002947 }
2948 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002949 {
2950 what_is_dict = TRUE;
2951 if (pt->pt_dict != NULL)
2952 rettv_dict_set(rettv, pt->pt_dict);
2953 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002954 else if (STRCMP(what, "args") == 0)
2955 {
2956 rettv->v_type = VAR_LIST;
2957 if (rettv_list_alloc(rettv) == OK)
2958 {
2959 int i;
2960
2961 for (i = 0; i < pt->pt_argc; ++i)
2962 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2963 }
2964 }
2965 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002966 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002967
2968 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2969 // third argument
2970 if (!what_is_dict)
2971 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002972 }
2973 }
2974 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002975 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002976
2977 if (tv == NULL)
2978 {
2979 if (argvars[2].v_type != VAR_UNKNOWN)
2980 copy_tv(&argvars[2], rettv);
2981 }
2982 else
2983 copy_tv(tv, rettv);
2984}
2985
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002986/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002987 * "getchangelist()" function
2988 */
2989 static void
2990f_getchangelist(typval_T *argvars, typval_T *rettv)
2991{
2992#ifdef FEAT_JUMPLIST
2993 buf_T *buf;
2994 int i;
2995 list_T *l;
2996 dict_T *d;
2997#endif
2998
2999 if (rettv_list_alloc(rettv) != OK)
3000 return;
3001
3002#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003003 if (argvars[0].v_type == VAR_UNKNOWN)
3004 buf = curbuf;
3005 else
3006 {
3007 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3008 ++emsg_off;
3009 buf = tv_get_buf(&argvars[0], FALSE);
3010 --emsg_off;
3011 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003012 if (buf == NULL)
3013 return;
3014
3015 l = list_alloc();
3016 if (l == NULL)
3017 return;
3018
3019 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3020 return;
3021 /*
3022 * The current window change list index tracks only the position in the
3023 * current buffer change list. For other buffers, use the change list
3024 * length as the current index.
3025 */
3026 list_append_number(rettv->vval.v_list,
3027 (varnumber_T)((buf == curwin->w_buffer)
3028 ? curwin->w_changelistidx : buf->b_changelistlen));
3029
3030 for (i = 0; i < buf->b_changelistlen; ++i)
3031 {
3032 if (buf->b_changelist[i].lnum == 0)
3033 continue;
3034 if ((d = dict_alloc()) == NULL)
3035 return;
3036 if (list_append_dict(l, d) == FAIL)
3037 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003038 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3039 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003040 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003041 }
3042#endif
3043}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003044
3045/*
3046 * "getcharsearch()" function
3047 */
3048 static void
3049f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3050{
3051 if (rettv_dict_alloc(rettv) != FAIL)
3052 {
3053 dict_T *dict = rettv->vval.v_dict;
3054
Bram Moolenaare0be1672018-07-08 16:50:37 +02003055 dict_add_string(dict, "char", last_csearch());
3056 dict_add_number(dict, "forward", last_csearch_forward());
3057 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 }
3059}
3060
3061/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003062 * "getenv()" function
3063 */
3064 static void
3065f_getenv(typval_T *argvars, typval_T *rettv)
3066{
3067 int mustfree = FALSE;
3068 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3069
3070 if (p == NULL)
3071 {
3072 rettv->v_type = VAR_SPECIAL;
3073 rettv->vval.v_number = VVAL_NULL;
3074 return;
3075 }
3076 if (!mustfree)
3077 p = vim_strsave(p);
3078 rettv->vval.v_string = p;
3079 rettv->v_type = VAR_STRING;
3080}
3081
3082/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083 * "getfontname()" function
3084 */
3085 static void
3086f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3087{
3088 rettv->v_type = VAR_STRING;
3089 rettv->vval.v_string = NULL;
3090#ifdef FEAT_GUI
3091 if (gui.in_use)
3092 {
3093 GuiFont font;
3094 char_u *name = NULL;
3095
3096 if (argvars[0].v_type == VAR_UNKNOWN)
3097 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003098 // Get the "Normal" font. Either the name saved by
3099 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100 font = gui.norm_font;
3101 name = hl_get_font_name();
3102 }
3103 else
3104 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003105 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003106 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003107 return;
3108 font = gui_mch_get_font(name, FALSE);
3109 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003110 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003111 }
3112 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3113 if (argvars[0].v_type != VAR_UNKNOWN)
3114 gui_mch_free_font(font);
3115 }
3116#endif
3117}
3118
3119/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003120 * "getjumplist()" function
3121 */
3122 static void
3123f_getjumplist(typval_T *argvars, typval_T *rettv)
3124{
3125#ifdef FEAT_JUMPLIST
3126 win_T *wp;
3127 int i;
3128 list_T *l;
3129 dict_T *d;
3130#endif
3131
3132 if (rettv_list_alloc(rettv) != OK)
3133 return;
3134
3135#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003136 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003137 if (wp == NULL)
3138 return;
3139
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003140 cleanup_jumplist(wp, TRUE);
3141
Bram Moolenaar4f505882018-02-10 21:06:32 +01003142 l = list_alloc();
3143 if (l == NULL)
3144 return;
3145
3146 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3147 return;
3148 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3149
3150 for (i = 0; i < wp->w_jumplistlen; ++i)
3151 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003152 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3153 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003154 if ((d = dict_alloc()) == NULL)
3155 return;
3156 if (list_append_dict(l, d) == FAIL)
3157 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003158 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3159 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003160 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003161 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003162 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003163 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003164 }
3165#endif
3166}
3167
3168/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003169 * "getpid()" function
3170 */
3171 static void
3172f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3173{
3174 rettv->vval.v_number = mch_get_pid();
3175}
3176
3177 static void
3178getpos_both(
3179 typval_T *argvars,
3180 typval_T *rettv,
3181 int getcurpos)
3182{
3183 pos_T *fp;
3184 list_T *l;
3185 int fnum = -1;
3186
3187 if (rettv_list_alloc(rettv) == OK)
3188 {
3189 l = rettv->vval.v_list;
3190 if (getcurpos)
3191 fp = &curwin->w_cursor;
3192 else
3193 fp = var2fpos(&argvars[0], TRUE, &fnum);
3194 if (fnum != -1)
3195 list_append_number(l, (varnumber_T)fnum);
3196 else
3197 list_append_number(l, (varnumber_T)0);
3198 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3199 : (varnumber_T)0);
3200 list_append_number(l, (fp != NULL)
3201 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3202 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003203 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003204 (varnumber_T)0);
3205 if (getcurpos)
3206 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003207 int save_set_curswant = curwin->w_set_curswant;
3208 colnr_T save_curswant = curwin->w_curswant;
3209 colnr_T save_virtcol = curwin->w_virtcol;
3210
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003211 update_curswant();
3212 list_append_number(l, curwin->w_curswant == MAXCOL ?
3213 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003214
3215 // Do not change "curswant", as it is unexpected that a get
3216 // function has a side effect.
3217 if (save_set_curswant)
3218 {
3219 curwin->w_set_curswant = save_set_curswant;
3220 curwin->w_curswant = save_curswant;
3221 curwin->w_virtcol = save_virtcol;
3222 curwin->w_valid &= ~VALID_VIRTCOL;
3223 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003224 }
3225 }
3226 else
3227 rettv->vval.v_number = FALSE;
3228}
3229
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230/*
3231 * "getcurpos()" function
3232 */
3233 static void
3234f_getcurpos(typval_T *argvars, typval_T *rettv)
3235{
3236 getpos_both(argvars, rettv, TRUE);
3237}
3238
3239/*
3240 * "getpos(string)" function
3241 */
3242 static void
3243f_getpos(typval_T *argvars, typval_T *rettv)
3244{
3245 getpos_both(argvars, rettv, FALSE);
3246}
3247
3248/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003249 * "getreg()" function
3250 */
3251 static void
3252f_getreg(typval_T *argvars, typval_T *rettv)
3253{
3254 char_u *strregname;
3255 int regname;
3256 int arg2 = FALSE;
3257 int return_list = FALSE;
3258 int error = FALSE;
3259
3260 if (argvars[0].v_type != VAR_UNKNOWN)
3261 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003262 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003263 error = strregname == NULL;
3264 if (argvars[1].v_type != VAR_UNKNOWN)
3265 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003266 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003268 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003269 }
3270 }
3271 else
3272 strregname = get_vim_var_str(VV_REG);
3273
3274 if (error)
3275 return;
3276
3277 regname = (strregname == NULL ? '"' : *strregname);
3278 if (regname == 0)
3279 regname = '"';
3280
3281 if (return_list)
3282 {
3283 rettv->v_type = VAR_LIST;
3284 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3285 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3286 if (rettv->vval.v_list == NULL)
3287 (void)rettv_list_alloc(rettv);
3288 else
3289 ++rettv->vval.v_list->lv_refcount;
3290 }
3291 else
3292 {
3293 rettv->v_type = VAR_STRING;
3294 rettv->vval.v_string = get_reg_contents(regname,
3295 arg2 ? GREG_EXPR_SRC : 0);
3296 }
3297}
3298
3299/*
3300 * "getregtype()" function
3301 */
3302 static void
3303f_getregtype(typval_T *argvars, typval_T *rettv)
3304{
3305 char_u *strregname;
3306 int regname;
3307 char_u buf[NUMBUFLEN + 2];
3308 long reglen = 0;
3309
3310 if (argvars[0].v_type != VAR_UNKNOWN)
3311 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003312 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003313 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003314 {
3315 rettv->v_type = VAR_STRING;
3316 rettv->vval.v_string = NULL;
3317 return;
3318 }
3319 }
3320 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003321 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003322 strregname = get_vim_var_str(VV_REG);
3323
3324 regname = (strregname == NULL ? '"' : *strregname);
3325 if (regname == 0)
3326 regname = '"';
3327
3328 buf[0] = NUL;
3329 buf[1] = NUL;
3330 switch (get_reg_type(regname, &reglen))
3331 {
3332 case MLINE: buf[0] = 'V'; break;
3333 case MCHAR: buf[0] = 'v'; break;
3334 case MBLOCK:
3335 buf[0] = Ctrl_V;
3336 sprintf((char *)buf + 1, "%ld", reglen + 1);
3337 break;
3338 }
3339 rettv->v_type = VAR_STRING;
3340 rettv->vval.v_string = vim_strsave(buf);
3341}
3342
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003343/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003344 * "gettagstack()" function
3345 */
3346 static void
3347f_gettagstack(typval_T *argvars, typval_T *rettv)
3348{
3349 win_T *wp = curwin; // default is current window
3350
3351 if (rettv_dict_alloc(rettv) != OK)
3352 return;
3353
3354 if (argvars[0].v_type != VAR_UNKNOWN)
3355 {
3356 wp = find_win_by_nr_or_id(&argvars[0]);
3357 if (wp == NULL)
3358 return;
3359 }
3360
3361 get_tagstack(wp, rettv->vval.v_dict);
3362}
3363
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003364// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003365#include "version.h"
3366
3367/*
3368 * "has()" function
3369 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003370 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003371f_has(typval_T *argvars, typval_T *rettv)
3372{
3373 int i;
3374 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003375 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003377 typedef struct {
3378 char *name;
3379 short present;
3380 } has_item_T;
3381 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003382 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003383 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003384#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003385 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003386#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003387 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003388#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003389 },
3390 {"arp",
3391#if defined(AMIGA) && defined(FEAT_ARP)
3392 1
3393#else
3394 0
3395#endif
3396 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003397 {"haiku",
3398#ifdef __HAIKU__
3399 1
3400#else
3401 0
3402#endif
3403 },
3404 {"bsd",
3405#if defined(BSD) && !defined(MACOS_X)
3406 1
3407#else
3408 0
3409#endif
3410 },
3411 {"hpux",
3412#ifdef hpux
3413 1
3414#else
3415 0
3416#endif
3417 },
3418 {"linux",
3419#ifdef __linux__
3420 1
3421#else
3422 0
3423#endif
3424 },
3425 {"mac", // Mac OS X (and, once, Mac OS Classic)
3426#ifdef MACOS_X
3427 1
3428#else
3429 0
3430#endif
3431 },
3432 {"osx", // Mac OS X
3433#ifdef MACOS_X
3434 1
3435#else
3436 0
3437#endif
3438 },
3439 {"macunix", // Mac OS X, with the darwin feature
3440#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3441 1
3442#else
3443 0
3444#endif
3445 },
3446 {"osxdarwin", // synonym for macunix
3447#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3448 1
3449#else
3450 0
3451#endif
3452 },
3453 {"qnx",
3454#ifdef __QNX__
3455 1
3456#else
3457 0
3458#endif
3459 },
3460 {"sun",
3461#ifdef SUN_SYSTEM
3462 1
3463#else
3464 0
3465#endif
3466 },
3467 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003469 1
3470#else
3471 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003473 },
3474 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003476 1
3477#else
3478 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003479#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003480 },
3481 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003482#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003483 1
3484#else
3485 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003486#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003487 },
3488 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003489#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003490 1
3491#else
3492 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003493#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003494 },
3495 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003496#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003497 1
3498#else
3499 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003501 },
3502 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003504 1
3505#else
3506 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003507#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003508 },
3509 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003510#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003511 1
3512#else
3513 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003515 },
3516 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003518 1
3519#else
3520 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003521#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003522 },
3523 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003524#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003525 1
3526#else
3527 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003528#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003529 },
3530 {"autocmd", 1},
3531 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003532#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003533 1
3534#else
3535 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003536#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003537 },
3538 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003539#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003540 1
3541#else
3542 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003543#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003544 },
3545 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003546#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003547 1
3548#else
3549 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003550#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003551 },
3552 {"balloon_multiline",
3553#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3554 // MS-Windows requires runtime check, see below
3555 1
3556#else
3557 0
3558#endif
3559 },
3560 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003561#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003562 1
3563#else
3564 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003565#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003566 },
3567 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003569 1
3570#else
3571 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003573 },
3574 {"all_builtin_terms",
3575#if defined(ALL_BUILTIN_TCAPS)
3576 1
3577#else
3578 0
3579#endif
3580 },
3581 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003582#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003583 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003584 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003585 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003586#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003587 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003588#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003589 },
3590 {"byte_offset",
3591#ifdef FEAT_BYTEOFF
3592 1
3593#else
3594 0
3595#endif
3596 },
3597 {"channel",
3598#ifdef FEAT_JOB_CHANNEL
3599 1
3600#else
3601 0
3602#endif
3603 },
3604 {"cindent",
3605#ifdef FEAT_CINDENT
3606 1
3607#else
3608 0
3609#endif
3610 },
3611 {"clientserver",
3612#ifdef FEAT_CLIENTSERVER
3613 1
3614#else
3615 0
3616#endif
3617 },
3618 {"clipboard",
3619#ifdef FEAT_CLIPBOARD
3620 1
3621#else
3622 0
3623#endif
3624 },
3625 {"cmdline_compl", 1},
3626 {"cmdline_hist", 1},
3627 {"comments", 1},
3628 {"conceal",
3629#ifdef FEAT_CONCEAL
3630 1
3631#else
3632 0
3633#endif
3634 },
3635 {"cryptv",
3636#ifdef FEAT_CRYPT
3637 1
3638#else
3639 0
3640#endif
3641 },
3642 {"crypt-blowfish",
3643#ifdef FEAT_CRYPT
3644 1
3645#else
3646 0
3647#endif
3648 },
3649 {"crypt-blowfish2",
3650#ifdef FEAT_CRYPT
3651 1
3652#else
3653 0
3654#endif
3655 },
3656 {"cscope",
3657#ifdef FEAT_CSCOPE
3658 1
3659#else
3660 0
3661#endif
3662 },
3663 {"cursorbind", 1},
3664 {"cursorshape",
3665#ifdef CURSOR_SHAPE
3666 1
3667#else
3668 0
3669#endif
3670 },
3671 {"debug",
3672#ifdef DEBUG
3673 1
3674#else
3675 0
3676#endif
3677 },
3678 {"dialog_con",
3679#ifdef FEAT_CON_DIALOG
3680 1
3681#else
3682 0
3683#endif
3684 },
3685 {"dialog_gui",
3686#ifdef FEAT_GUI_DIALOG
3687 1
3688#else
3689 0
3690#endif
3691 },
3692 {"diff",
3693#ifdef FEAT_DIFF
3694 1
3695#else
3696 0
3697#endif
3698 },
3699 {"digraphs",
3700#ifdef FEAT_DIGRAPHS
3701 1
3702#else
3703 0
3704#endif
3705 },
3706 {"directx",
3707#ifdef FEAT_DIRECTX
3708 1
3709#else
3710 0
3711#endif
3712 },
3713 {"dnd",
3714#ifdef FEAT_DND
3715 1
3716#else
3717 0
3718#endif
3719 },
3720 {"emacs_tags",
3721#ifdef FEAT_EMACS_TAGS
3722 1
3723#else
3724 0
3725#endif
3726 },
3727 {"eval", 1}, // always present, of course!
3728 {"ex_extra", 1}, // graduated feature
3729 {"extra_search",
3730#ifdef FEAT_SEARCH_EXTRA
3731 1
3732#else
3733 0
3734#endif
3735 },
3736 {"file_in_path",
3737#ifdef FEAT_SEARCHPATH
3738 1
3739#else
3740 0
3741#endif
3742 },
3743 {"filterpipe",
3744#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3745 1
3746#else
3747 0
3748#endif
3749 },
3750 {"find_in_path",
3751#ifdef FEAT_FIND_ID
3752 1
3753#else
3754 0
3755#endif
3756 },
3757 {"float",
3758#ifdef FEAT_FLOAT
3759 1
3760#else
3761 0
3762#endif
3763 },
3764 {"folding",
3765#ifdef FEAT_FOLDING
3766 1
3767#else
3768 0
3769#endif
3770 },
3771 {"footer",
3772#ifdef FEAT_FOOTER
3773 1
3774#else
3775 0
3776#endif
3777 },
3778 {"fork",
3779#if !defined(USE_SYSTEM) && defined(UNIX)
3780 1
3781#else
3782 0
3783#endif
3784 },
3785 {"gettext",
3786#ifdef FEAT_GETTEXT
3787 1
3788#else
3789 0
3790#endif
3791 },
3792 {"gui",
3793#ifdef FEAT_GUI
3794 1
3795#else
3796 0
3797#endif
3798 },
3799 {"gui_neXtaw",
3800#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3801 1
3802#else
3803 0
3804#endif
3805 },
3806 {"gui_athena",
3807#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3808 1
3809#else
3810 0
3811#endif
3812 },
3813 {"gui_gtk",
3814#ifdef FEAT_GUI_GTK
3815 1
3816#else
3817 0
3818#endif
3819 },
3820 {"gui_gtk2",
3821#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3822 1
3823#else
3824 0
3825#endif
3826 },
3827 {"gui_gtk3",
3828#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3829 1
3830#else
3831 0
3832#endif
3833 },
3834 {"gui_gnome",
3835#ifdef FEAT_GUI_GNOME
3836 1
3837#else
3838 0
3839#endif
3840 },
3841 {"gui_haiku",
3842#ifdef FEAT_GUI_HAIKU
3843 1
3844#else
3845 0
3846#endif
3847 },
3848 {"gui_mac",
3849#ifdef FEAT_GUI_MAC
3850 1
3851#else
3852 0
3853#endif
3854 },
3855 {"gui_motif",
3856#ifdef FEAT_GUI_MOTIF
3857 1
3858#else
3859 0
3860#endif
3861 },
3862 {"gui_photon",
3863#ifdef FEAT_GUI_PHOTON
3864 1
3865#else
3866 0
3867#endif
3868 },
3869 {"gui_win32",
3870#ifdef FEAT_GUI_MSWIN
3871 1
3872#else
3873 0
3874#endif
3875 },
3876 {"iconv",
3877#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3878 1
3879#else
3880 0
3881#endif
3882 },
3883 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003884 {"ipv6",
3885#ifdef FEAT_IPV6
3886 1
3887#else
3888 0
3889#endif
3890 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003891 {"job",
3892#ifdef FEAT_JOB_CHANNEL
3893 1
3894#else
3895 0
3896#endif
3897 },
3898 {"jumplist",
3899#ifdef FEAT_JUMPLIST
3900 1
3901#else
3902 0
3903#endif
3904 },
3905 {"keymap",
3906#ifdef FEAT_KEYMAP
3907 1
3908#else
3909 0
3910#endif
3911 },
3912 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
3913 {"langmap",
3914#ifdef FEAT_LANGMAP
3915 1
3916#else
3917 0
3918#endif
3919 },
3920 {"libcall",
3921#ifdef FEAT_LIBCALL
3922 1
3923#else
3924 0
3925#endif
3926 },
3927 {"linebreak",
3928#ifdef FEAT_LINEBREAK
3929 1
3930#else
3931 0
3932#endif
3933 },
3934 {"lispindent",
3935#ifdef FEAT_LISP
3936 1
3937#else
3938 0
3939#endif
3940 },
3941 {"listcmds", 1},
3942 {"localmap", 1},
3943 {"lua",
3944#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
3945 1
3946#else
3947 0
3948#endif
3949 },
3950 {"menu",
3951#ifdef FEAT_MENU
3952 1
3953#else
3954 0
3955#endif
3956 },
3957 {"mksession",
3958#ifdef FEAT_SESSION
3959 1
3960#else
3961 0
3962#endif
3963 },
3964 {"modify_fname", 1},
3965 {"mouse", 1},
3966 {"mouseshape",
3967#ifdef FEAT_MOUSESHAPE
3968 1
3969#else
3970 0
3971#endif
3972 },
3973 {"mouse_dec",
3974#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
3975 1
3976#else
3977 0
3978#endif
3979 },
3980 {"mouse_gpm",
3981#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
3982 1
3983#else
3984 0
3985#endif
3986 },
3987 {"mouse_jsbterm",
3988#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
3989 1
3990#else
3991 0
3992#endif
3993 },
3994 {"mouse_netterm",
3995#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
3996 1
3997#else
3998 0
3999#endif
4000 },
4001 {"mouse_pterm",
4002#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
4003 1
4004#else
4005 0
4006#endif
4007 },
4008 {"mouse_sgr",
4009#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4010 1
4011#else
4012 0
4013#endif
4014 },
4015 {"mouse_sysmouse",
4016#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4017 1
4018#else
4019 0
4020#endif
4021 },
4022 {"mouse_urxvt",
4023#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4024 1
4025#else
4026 0
4027#endif
4028 },
4029 {"mouse_xterm",
4030#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4031 1
4032#else
4033 0
4034#endif
4035 },
4036 {"multi_byte", 1},
4037 {"multi_byte_ime",
4038#ifdef FEAT_MBYTE_IME
4039 1
4040#else
4041 0
4042#endif
4043 },
4044 {"multi_lang",
4045#ifdef FEAT_MULTI_LANG
4046 1
4047#else
4048 0
4049#endif
4050 },
4051 {"mzscheme",
4052#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4053 1
4054#else
4055 0
4056#endif
4057 },
4058 {"num64", 1},
4059 {"ole",
4060#ifdef FEAT_OLE
4061 1
4062#else
4063 0
4064#endif
4065 },
4066 {"packages",
4067#ifdef FEAT_EVAL
4068 1
4069#else
4070 0
4071#endif
4072 },
4073 {"path_extra",
4074#ifdef FEAT_PATH_EXTRA
4075 1
4076#else
4077 0
4078#endif
4079 },
4080 {"perl",
4081#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4082 1
4083#else
4084 0
4085#endif
4086 },
4087 {"persistent_undo",
4088#ifdef FEAT_PERSISTENT_UNDO
4089 1
4090#else
4091 0
4092#endif
4093 },
4094 {"python_compiled",
4095#if defined(FEAT_PYTHON)
4096 1
4097#else
4098 0
4099#endif
4100 },
4101 {"python_dynamic",
4102#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4103 1
4104#else
4105 0
4106#endif
4107 },
4108 {"python",
4109#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4110 1
4111#else
4112 0
4113#endif
4114 },
4115 {"pythonx",
4116#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4117 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4118 1
4119#else
4120 0
4121#endif
4122 },
4123 {"python3_compiled",
4124#if defined(FEAT_PYTHON3)
4125 1
4126#else
4127 0
4128#endif
4129 },
4130 {"python3_dynamic",
4131#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4132 1
4133#else
4134 0
4135#endif
4136 },
4137 {"python3",
4138#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4139 1
4140#else
4141 0
4142#endif
4143 },
4144 {"popupwin",
4145#ifdef FEAT_PROP_POPUP
4146 1
4147#else
4148 0
4149#endif
4150 },
4151 {"postscript",
4152#ifdef FEAT_POSTSCRIPT
4153 1
4154#else
4155 0
4156#endif
4157 },
4158 {"printer",
4159#ifdef FEAT_PRINTER
4160 1
4161#else
4162 0
4163#endif
4164 },
4165 {"profile",
4166#ifdef FEAT_PROFILE
4167 1
4168#else
4169 0
4170#endif
4171 },
4172 {"reltime",
4173#ifdef FEAT_RELTIME
4174 1
4175#else
4176 0
4177#endif
4178 },
4179 {"quickfix",
4180#ifdef FEAT_QUICKFIX
4181 1
4182#else
4183 0
4184#endif
4185 },
4186 {"rightleft",
4187#ifdef FEAT_RIGHTLEFT
4188 1
4189#else
4190 0
4191#endif
4192 },
4193 {"ruby",
4194#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4195 1
4196#else
4197 0
4198#endif
4199 },
4200 {"scrollbind", 1},
4201 {"showcmd",
4202#ifdef FEAT_CMDL_INFO
4203 1
4204#else
4205 0
4206#endif
4207 },
4208 {"cmdline_info",
4209#ifdef FEAT_CMDL_INFO
4210 1
4211#else
4212 0
4213#endif
4214 },
4215 {"signs",
4216#ifdef FEAT_SIGNS
4217 1
4218#else
4219 0
4220#endif
4221 },
4222 {"smartindent",
4223#ifdef FEAT_SMARTINDENT
4224 1
4225#else
4226 0
4227#endif
4228 },
4229 {"startuptime",
4230#ifdef STARTUPTIME
4231 1
4232#else
4233 0
4234#endif
4235 },
4236 {"statusline",
4237#ifdef FEAT_STL_OPT
4238 1
4239#else
4240 0
4241#endif
4242 },
4243 {"netbeans_intg",
4244#ifdef FEAT_NETBEANS_INTG
4245 1
4246#else
4247 0
4248#endif
4249 },
4250 {"sound",
4251#ifdef FEAT_SOUND
4252 1
4253#else
4254 0
4255#endif
4256 },
4257 {"spell",
4258#ifdef FEAT_SPELL
4259 1
4260#else
4261 0
4262#endif
4263 },
4264 {"syntax",
4265#ifdef FEAT_SYN_HL
4266 1
4267#else
4268 0
4269#endif
4270 },
4271 {"system",
4272#if defined(USE_SYSTEM) || !defined(UNIX)
4273 1
4274#else
4275 0
4276#endif
4277 },
4278 {"tag_binary",
4279#ifdef FEAT_TAG_BINS
4280 1
4281#else
4282 0
4283#endif
4284 },
4285 {"tcl",
4286#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4287 1
4288#else
4289 0
4290#endif
4291 },
4292 {"termguicolors",
4293#ifdef FEAT_TERMGUICOLORS
4294 1
4295#else
4296 0
4297#endif
4298 },
4299 {"terminal",
4300#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4301 1
4302#else
4303 0
4304#endif
4305 },
4306 {"terminfo",
4307#ifdef TERMINFO
4308 1
4309#else
4310 0
4311#endif
4312 },
4313 {"termresponse",
4314#ifdef FEAT_TERMRESPONSE
4315 1
4316#else
4317 0
4318#endif
4319 },
4320 {"textobjects",
4321#ifdef FEAT_TEXTOBJ
4322 1
4323#else
4324 0
4325#endif
4326 },
4327 {"textprop",
4328#ifdef FEAT_PROP_POPUP
4329 1
4330#else
4331 0
4332#endif
4333 },
4334 {"tgetent",
4335#ifdef HAVE_TGETENT
4336 1
4337#else
4338 0
4339#endif
4340 },
4341 {"timers",
4342#ifdef FEAT_TIMERS
4343 1
4344#else
4345 0
4346#endif
4347 },
4348 {"title",
4349#ifdef FEAT_TITLE
4350 1
4351#else
4352 0
4353#endif
4354 },
4355 {"toolbar",
4356#ifdef FEAT_TOOLBAR
4357 1
4358#else
4359 0
4360#endif
4361 },
4362 {"unnamedplus",
4363#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4364 1
4365#else
4366 0
4367#endif
4368 },
4369 {"user-commands", 1}, // was accidentally included in 5.4
4370 {"user_commands", 1},
4371 {"vartabs",
4372#ifdef FEAT_VARTABS
4373 1
4374#else
4375 0
4376#endif
4377 },
4378 {"vertsplit", 1},
4379 {"viminfo",
4380#ifdef FEAT_VIMINFO
4381 1
4382#else
4383 0
4384#endif
4385 },
4386 {"vimscript-1", 1},
4387 {"vimscript-2", 1},
4388 {"vimscript-3", 1},
4389 {"vimscript-4", 1},
4390 {"virtualedit", 1},
4391 {"visual", 1},
4392 {"visualextra", 1},
4393 {"vreplace", 1},
4394 {"vtp",
4395#ifdef FEAT_VTP
4396 1
4397#else
4398 0
4399#endif
4400 },
4401 {"wildignore",
4402#ifdef FEAT_WILDIGN
4403 1
4404#else
4405 0
4406#endif
4407 },
4408 {"wildmenu",
4409#ifdef FEAT_WILDMENU
4410 1
4411#else
4412 0
4413#endif
4414 },
4415 {"windows", 1},
4416 {"winaltkeys",
4417#ifdef FEAT_WAK
4418 1
4419#else
4420 0
4421#endif
4422 },
4423 {"writebackup",
4424#ifdef FEAT_WRITEBACKUP
4425 1
4426#else
4427 0
4428#endif
4429 },
4430 {"xim",
4431#ifdef FEAT_XIM
4432 1
4433#else
4434 0
4435#endif
4436 },
4437 {"xfontset",
4438#ifdef FEAT_XFONTSET
4439 1
4440#else
4441 0
4442#endif
4443 },
4444 {"xpm",
4445#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4446 1
4447#else
4448 0
4449#endif
4450 },
4451 {"xpm_w32", // for backward compatibility
4452#ifdef FEAT_XPM_W32
4453 1
4454#else
4455 0
4456#endif
4457 },
4458 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004460 1
4461#else
4462 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004463#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004464 },
4465 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004467 1
4468#else
4469 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004470#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004471 },
4472 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004473#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004474 1
4475#else
4476 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004477#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004478 },
4479 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004480#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004481 1
4482#else
4483 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004484#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004485 },
4486 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004488 1
4489#else
4490 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004491#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004492 },
4493 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004494 };
4495
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004496 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004497 for (i = 0; has_list[i].name != NULL; ++i)
4498 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004499 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004500 x = TRUE;
4501 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004502 break;
4503 }
4504
Bram Moolenaar79296512020-03-22 16:17:14 +01004505 // features also in has_list[] but sometimes enabled at runtime
4506 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004508 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004509 {
4510 // intentionally empty
4511 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004512#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004513 else if (STRICMP(name, "balloon_multiline") == 0)
4514 n = multiline_balloon_available();
4515#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004516#ifdef VIMDLL
4517 else if (STRICMP(name, "filterpipe") == 0)
4518 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519#endif
4520#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4521 else if (STRICMP(name, "iconv") == 0)
4522 n = iconv_enabled(FALSE);
4523#endif
4524#ifdef DYNAMIC_LUA
4525 else if (STRICMP(name, "lua") == 0)
4526 n = lua_enabled(FALSE);
4527#endif
4528#ifdef DYNAMIC_MZSCHEME
4529 else if (STRICMP(name, "mzscheme") == 0)
4530 n = mzscheme_enabled(FALSE);
4531#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004532#ifdef DYNAMIC_PERL
4533 else if (STRICMP(name, "perl") == 0)
4534 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004535#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004536#ifdef DYNAMIC_PYTHON
4537 else if (STRICMP(name, "python") == 0)
4538 n = python_enabled(FALSE);
4539#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004540#ifdef DYNAMIC_PYTHON3
4541 else if (STRICMP(name, "python3") == 0)
4542 n = python3_enabled(FALSE);
4543#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004544#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4545 else if (STRICMP(name, "pythonx") == 0)
4546 {
4547# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4548 if (p_pyx == 0)
4549 n = python3_enabled(FALSE) || python_enabled(FALSE);
4550 else if (p_pyx == 3)
4551 n = python3_enabled(FALSE);
4552 else if (p_pyx == 2)
4553 n = python_enabled(FALSE);
4554# elif defined(DYNAMIC_PYTHON)
4555 n = python_enabled(FALSE);
4556# elif defined(DYNAMIC_PYTHON3)
4557 n = python3_enabled(FALSE);
4558# endif
4559 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004561#ifdef DYNAMIC_RUBY
4562 else if (STRICMP(name, "ruby") == 0)
4563 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004564#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004565#ifdef DYNAMIC_TCL
4566 else if (STRICMP(name, "tcl") == 0)
4567 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004568#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004569#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004570 else if (STRICMP(name, "terminal") == 0)
4571 n = terminal_enabled();
4572#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004573 }
4574
Bram Moolenaar79296512020-03-22 16:17:14 +01004575 // features not in has_list[]
4576 if (x == FALSE)
4577 {
4578 if (STRNICMP(name, "patch", 5) == 0)
4579 {
4580 x = TRUE;
4581 if (name[5] == '-'
4582 && STRLEN(name) >= 11
4583 && vim_isdigit(name[6])
4584 && vim_isdigit(name[8])
4585 && vim_isdigit(name[10]))
4586 {
4587 int major = atoi((char *)name + 6);
4588 int minor = atoi((char *)name + 8);
4589
4590 // Expect "patch-9.9.01234".
4591 n = (major < VIM_VERSION_MAJOR
4592 || (major == VIM_VERSION_MAJOR
4593 && (minor < VIM_VERSION_MINOR
4594 || (minor == VIM_VERSION_MINOR
4595 && has_patch(atoi((char *)name + 10))))));
4596 }
4597 else
4598 n = has_patch(atoi((char *)name + 5));
4599 }
4600 else if (STRICMP(name, "vim_starting") == 0)
4601 {
4602 x = TRUE;
4603 n = (starting != 0);
4604 }
4605 else if (STRICMP(name, "ttyin") == 0)
4606 {
4607 x = TRUE;
4608 n = mch_input_isatty();
4609 }
4610 else if (STRICMP(name, "ttyout") == 0)
4611 {
4612 x = TRUE;
4613 n = stdout_isatty;
4614 }
4615 else if (STRICMP(name, "multi_byte_encoding") == 0)
4616 {
4617 x = TRUE;
4618 n = has_mbyte;
4619 }
4620 else if (STRICMP(name, "gui_running") == 0)
4621 {
4622 x = TRUE;
4623#ifdef FEAT_GUI
4624 n = (gui.in_use || gui.starting);
4625#endif
4626 }
4627 else if (STRICMP(name, "browse") == 0)
4628 {
4629 x = TRUE;
4630#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4631 n = gui.in_use; // gui_mch_browse() works when GUI is running
4632#endif
4633 }
4634 else if (STRICMP(name, "syntax_items") == 0)
4635 {
4636 x = TRUE;
4637#ifdef FEAT_SYN_HL
4638 n = syntax_present(curwin);
4639#endif
4640 }
4641 else if (STRICMP(name, "vcon") == 0)
4642 {
4643 x = TRUE;
4644#ifdef FEAT_VTP
4645 n = is_term_win32() && has_vtp_working();
4646#endif
4647 }
4648 else if (STRICMP(name, "netbeans_enabled") == 0)
4649 {
4650 x = TRUE;
4651#ifdef FEAT_NETBEANS_INTG
4652 n = netbeans_active();
4653#endif
4654 }
4655 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4656 {
4657 x = TRUE;
4658#ifdef FEAT_MOUSE_GPM
4659 n = gpm_enabled();
4660#endif
4661 }
4662 else if (STRICMP(name, "conpty") == 0)
4663 {
4664 x = TRUE;
4665#if defined(FEAT_TERMINAL) && defined(MSWIN)
4666 n = use_conpty();
4667#endif
4668 }
4669 else if (STRICMP(name, "clipboard_working") == 0)
4670 {
4671 x = TRUE;
4672#ifdef FEAT_CLIPBOARD
4673 n = clip_star.available;
4674#endif
4675 }
4676 }
4677
4678 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4679 // return whether feature could ever be enabled
4680 rettv->vval.v_number = x;
4681 else
4682 // return whether feature is enabled
4683 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004684}
4685
4686/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004687 * "haslocaldir()" function
4688 */
4689 static void
4690f_haslocaldir(typval_T *argvars, typval_T *rettv)
4691{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004692 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 win_T *wp = NULL;
4694
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004695 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4696
4697 // Check for window-local and tab-local directories
4698 if (wp != NULL && wp->w_localdir != NULL)
4699 rettv->vval.v_number = 1;
4700 else if (tp != NULL && tp->tp_localdir != NULL)
4701 rettv->vval.v_number = 2;
4702 else
4703 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004704}
4705
4706/*
4707 * "hasmapto()" function
4708 */
4709 static void
4710f_hasmapto(typval_T *argvars, typval_T *rettv)
4711{
4712 char_u *name;
4713 char_u *mode;
4714 char_u buf[NUMBUFLEN];
4715 int abbr = FALSE;
4716
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004717 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718 if (argvars[1].v_type == VAR_UNKNOWN)
4719 mode = (char_u *)"nvo";
4720 else
4721 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004722 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004723 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004724 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004725 }
4726
4727 if (map_to_exists(name, mode, abbr))
4728 rettv->vval.v_number = TRUE;
4729 else
4730 rettv->vval.v_number = FALSE;
4731}
4732
4733/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 * "highlightID(name)" function
4735 */
4736 static void
4737f_hlID(typval_T *argvars, typval_T *rettv)
4738{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004739 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004740}
4741
4742/*
4743 * "highlight_exists()" function
4744 */
4745 static void
4746f_hlexists(typval_T *argvars, typval_T *rettv)
4747{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004748 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004749}
4750
4751/*
4752 * "hostname()" function
4753 */
4754 static void
4755f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4756{
4757 char_u hostname[256];
4758
4759 mch_get_host_name(hostname, 256);
4760 rettv->v_type = VAR_STRING;
4761 rettv->vval.v_string = vim_strsave(hostname);
4762}
4763
4764/*
4765 * iconv() function
4766 */
4767 static void
4768f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4769{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004770 char_u buf1[NUMBUFLEN];
4771 char_u buf2[NUMBUFLEN];
4772 char_u *from, *to, *str;
4773 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004774
4775 rettv->v_type = VAR_STRING;
4776 rettv->vval.v_string = NULL;
4777
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004778 str = tv_get_string(&argvars[0]);
4779 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4780 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004781 vimconv.vc_type = CONV_NONE;
4782 convert_setup(&vimconv, from, to);
4783
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004784 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004785 if (vimconv.vc_type == CONV_NONE)
4786 rettv->vval.v_string = vim_strsave(str);
4787 else
4788 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4789
4790 convert_setup(&vimconv, NULL, NULL);
4791 vim_free(from);
4792 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004793}
4794
4795/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796 * "index()" function
4797 */
4798 static void
4799f_index(typval_T *argvars, typval_T *rettv)
4800{
4801 list_T *l;
4802 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004803 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004804 long idx = 0;
4805 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004806 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004807
4808 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004809 if (argvars[0].v_type == VAR_BLOB)
4810 {
4811 typval_T tv;
4812 int start = 0;
4813
4814 if (argvars[2].v_type != VAR_UNKNOWN)
4815 {
4816 start = tv_get_number_chk(&argvars[2], &error);
4817 if (error)
4818 return;
4819 }
4820 b = argvars[0].vval.v_blob;
4821 if (b == NULL)
4822 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004823 if (start < 0)
4824 {
4825 start = blob_len(b) + start;
4826 if (start < 0)
4827 start = 0;
4828 }
4829
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004830 for (idx = start; idx < blob_len(b); ++idx)
4831 {
4832 tv.v_type = VAR_NUMBER;
4833 tv.vval.v_number = blob_get(b, idx);
4834 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4835 {
4836 rettv->vval.v_number = idx;
4837 return;
4838 }
4839 }
4840 return;
4841 }
4842 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004843 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004844 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004845 return;
4846 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004847
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004848 l = argvars[0].vval.v_list;
4849 if (l != NULL)
4850 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004851 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852 item = l->lv_first;
4853 if (argvars[2].v_type != VAR_UNKNOWN)
4854 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004855 // Start at specified item. Use the cached index that list_find()
4856 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004857 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004858 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004860 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861 if (error)
4862 item = NULL;
4863 }
4864
4865 for ( ; item != NULL; item = item->li_next, ++idx)
4866 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4867 {
4868 rettv->vval.v_number = idx;
4869 break;
4870 }
4871 }
4872}
4873
4874static int inputsecret_flag = 0;
4875
4876/*
4877 * "input()" function
4878 * Also handles inputsecret() when inputsecret is set.
4879 */
4880 static void
4881f_input(typval_T *argvars, typval_T *rettv)
4882{
4883 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4884}
4885
4886/*
4887 * "inputdialog()" function
4888 */
4889 static void
4890f_inputdialog(typval_T *argvars, typval_T *rettv)
4891{
4892#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004893 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4895 {
4896 char_u *message;
4897 char_u buf[NUMBUFLEN];
4898 char_u *defstr = (char_u *)"";
4899
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004900 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004901 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004902 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4904 else
4905 IObuff[0] = NUL;
4906 if (message != NULL && defstr != NULL
4907 && do_dialog(VIM_QUESTION, NULL, message,
4908 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4909 rettv->vval.v_string = vim_strsave(IObuff);
4910 else
4911 {
4912 if (message != NULL && defstr != NULL
4913 && argvars[1].v_type != VAR_UNKNOWN
4914 && argvars[2].v_type != VAR_UNKNOWN)
4915 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004916 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917 else
4918 rettv->vval.v_string = NULL;
4919 }
4920 rettv->v_type = VAR_STRING;
4921 }
4922 else
4923#endif
4924 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4925}
4926
4927/*
4928 * "inputlist()" function
4929 */
4930 static void
4931f_inputlist(typval_T *argvars, typval_T *rettv)
4932{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004933 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004934 listitem_T *li;
4935 int selected;
4936 int mouse_used;
4937
4938#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004939 // While starting up, there is no place to enter text. When running tests
4940 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004941 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 return;
4943#endif
4944 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4945 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004946 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 return;
4948 }
4949
4950 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004951 msg_row = Rows - 1; // for when 'cmdheight' > 1
4952 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004953 msg_scroll = TRUE;
4954 msg_clr_eos();
4955
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004956 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004957 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02004958 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004959 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004960 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961 msg_putchar('\n');
4962 }
4963
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004964 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965 selected = prompt_for_number(&mouse_used);
4966 if (mouse_used)
4967 selected -= lines_left;
4968
4969 rettv->vval.v_number = selected;
4970}
4971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4973
4974/*
4975 * "inputrestore()" function
4976 */
4977 static void
4978f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4979{
4980 if (ga_userinput.ga_len > 0)
4981 {
4982 --ga_userinput.ga_len;
4983 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4984 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004985 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004986 }
4987 else if (p_verbose > 1)
4988 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004989 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004990 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004991 }
4992}
4993
4994/*
4995 * "inputsave()" function
4996 */
4997 static void
4998f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4999{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005000 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005001 if (ga_grow(&ga_userinput, 1) == OK)
5002 {
5003 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5004 + ga_userinput.ga_len);
5005 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005006 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005007 }
5008 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005009 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005010}
5011
5012/*
5013 * "inputsecret()" function
5014 */
5015 static void
5016f_inputsecret(typval_T *argvars, typval_T *rettv)
5017{
5018 ++cmdline_star;
5019 ++inputsecret_flag;
5020 f_input(argvars, rettv);
5021 --cmdline_star;
5022 --inputsecret_flag;
5023}
5024
5025/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005026 * "interrupt()" function
5027 */
5028 static void
5029f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5030{
5031 got_int = TRUE;
5032}
5033
5034/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035 * "invert(expr)" function
5036 */
5037 static void
5038f_invert(typval_T *argvars, typval_T *rettv)
5039{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005040 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005041}
5042
5043/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044 * "islocked()" function
5045 */
5046 static void
5047f_islocked(typval_T *argvars, typval_T *rettv)
5048{
5049 lval_T lv;
5050 char_u *end;
5051 dictitem_T *di;
5052
5053 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005054 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005055 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005056 if (end != NULL && lv.ll_name != NULL)
5057 {
5058 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005059 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060 else
5061 {
5062 if (lv.ll_tv == NULL)
5063 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005064 di = find_var(lv.ll_name, NULL, TRUE);
5065 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005066 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005067 // Consider a variable locked when:
5068 // 1. the variable itself is locked
5069 // 2. the value of the variable is locked.
5070 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005071 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5072 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005073 }
5074 }
5075 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005076 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005078 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005079 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005080 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005081 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5082 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005083 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005084 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5085 }
5086 }
5087
5088 clear_lval(&lv);
5089}
5090
5091#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5092/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005093 * "isinf()" function
5094 */
5095 static void
5096f_isinf(typval_T *argvars, typval_T *rettv)
5097{
5098 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5099 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5100}
5101
5102/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103 * "isnan()" function
5104 */
5105 static void
5106f_isnan(typval_T *argvars, typval_T *rettv)
5107{
5108 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5109 && isnan(argvars[0].vval.v_float);
5110}
5111#endif
5112
5113/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114 * "last_buffer_nr()" function.
5115 */
5116 static void
5117f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5118{
5119 int n = 0;
5120 buf_T *buf;
5121
Bram Moolenaar29323592016-07-24 22:04:11 +02005122 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005123 if (n < buf->b_fnum)
5124 n = buf->b_fnum;
5125
5126 rettv->vval.v_number = n;
5127}
5128
5129/*
5130 * "len()" function
5131 */
5132 static void
5133f_len(typval_T *argvars, typval_T *rettv)
5134{
5135 switch (argvars[0].v_type)
5136 {
5137 case VAR_STRING:
5138 case VAR_NUMBER:
5139 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005140 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005141 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005142 case VAR_BLOB:
5143 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5144 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145 case VAR_LIST:
5146 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5147 break;
5148 case VAR_DICT:
5149 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5150 break;
5151 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005152 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005153 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005154 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005155 case VAR_SPECIAL:
5156 case VAR_FLOAT:
5157 case VAR_FUNC:
5158 case VAR_PARTIAL:
5159 case VAR_JOB:
5160 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005161 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005162 break;
5163 }
5164}
5165
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005166 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005167libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005168{
5169#ifdef FEAT_LIBCALL
5170 char_u *string_in;
5171 char_u **string_result;
5172 int nr_result;
5173#endif
5174
5175 rettv->v_type = type;
5176 if (type != VAR_NUMBER)
5177 rettv->vval.v_string = NULL;
5178
5179 if (check_restricted() || check_secure())
5180 return;
5181
5182#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005183 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005184 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5185 {
5186 string_in = NULL;
5187 if (argvars[2].v_type == VAR_STRING)
5188 string_in = argvars[2].vval.v_string;
5189 if (type == VAR_NUMBER)
5190 string_result = NULL;
5191 else
5192 string_result = &rettv->vval.v_string;
5193 if (mch_libcall(argvars[0].vval.v_string,
5194 argvars[1].vval.v_string,
5195 string_in,
5196 argvars[2].vval.v_number,
5197 string_result,
5198 &nr_result) == OK
5199 && type == VAR_NUMBER)
5200 rettv->vval.v_number = nr_result;
5201 }
5202#endif
5203}
5204
5205/*
5206 * "libcall()" function
5207 */
5208 static void
5209f_libcall(typval_T *argvars, typval_T *rettv)
5210{
5211 libcall_common(argvars, rettv, VAR_STRING);
5212}
5213
5214/*
5215 * "libcallnr()" function
5216 */
5217 static void
5218f_libcallnr(typval_T *argvars, typval_T *rettv)
5219{
5220 libcall_common(argvars, rettv, VAR_NUMBER);
5221}
5222
5223/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005224 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005225 */
5226 static void
5227f_line(typval_T *argvars, typval_T *rettv)
5228{
5229 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005230 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005231 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005232 int id;
5233 tabpage_T *tp;
5234 win_T *wp;
5235 win_T *save_curwin;
5236 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005237
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005238 if (argvars[1].v_type != VAR_UNKNOWN)
5239 {
5240 // use window specified in the second argument
5241 id = (int)tv_get_number(&argvars[1]);
5242 wp = win_id2wp_tp(id, &tp);
5243 if (wp != NULL && tp != NULL)
5244 {
5245 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5246 == OK)
5247 {
5248 check_cursor();
5249 fp = var2fpos(&argvars[0], TRUE, &fnum);
5250 }
5251 restore_win_noblock(save_curwin, save_curtab, TRUE);
5252 }
5253 }
5254 else
5255 // use current window
5256 fp = var2fpos(&argvars[0], TRUE, &fnum);
5257
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005258 if (fp != NULL)
5259 lnum = fp->lnum;
5260 rettv->vval.v_number = lnum;
5261}
5262
5263/*
5264 * "line2byte(lnum)" function
5265 */
5266 static void
5267f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5268{
5269#ifndef FEAT_BYTEOFF
5270 rettv->vval.v_number = -1;
5271#else
5272 linenr_T lnum;
5273
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005274 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005275 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5276 rettv->vval.v_number = -1;
5277 else
5278 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5279 if (rettv->vval.v_number >= 0)
5280 ++rettv->vval.v_number;
5281#endif
5282}
5283
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005284#ifdef FEAT_FLOAT
5285/*
5286 * "log()" function
5287 */
5288 static void
5289f_log(typval_T *argvars, typval_T *rettv)
5290{
5291 float_T f = 0.0;
5292
5293 rettv->v_type = VAR_FLOAT;
5294 if (get_float_arg(argvars, &f) == OK)
5295 rettv->vval.v_float = log(f);
5296 else
5297 rettv->vval.v_float = 0.0;
5298}
5299
5300/*
5301 * "log10()" function
5302 */
5303 static void
5304f_log10(typval_T *argvars, typval_T *rettv)
5305{
5306 float_T f = 0.0;
5307
5308 rettv->v_type = VAR_FLOAT;
5309 if (get_float_arg(argvars, &f) == OK)
5310 rettv->vval.v_float = log10(f);
5311 else
5312 rettv->vval.v_float = 0.0;
5313}
5314#endif
5315
5316#ifdef FEAT_LUA
5317/*
5318 * "luaeval()" function
5319 */
5320 static void
5321f_luaeval(typval_T *argvars, typval_T *rettv)
5322{
5323 char_u *str;
5324 char_u buf[NUMBUFLEN];
5325
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005326 if (check_restricted() || check_secure())
5327 return;
5328
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005329 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005330 do_luaeval(str, argvars + 1, rettv);
5331}
5332#endif
5333
5334/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005335 * "maparg()" function
5336 */
5337 static void
5338f_maparg(typval_T *argvars, typval_T *rettv)
5339{
5340 get_maparg(argvars, rettv, TRUE);
5341}
5342
5343/*
5344 * "mapcheck()" function
5345 */
5346 static void
5347f_mapcheck(typval_T *argvars, typval_T *rettv)
5348{
5349 get_maparg(argvars, rettv, FALSE);
5350}
5351
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005352typedef enum
5353{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005354 MATCH_END, // matchend()
5355 MATCH_MATCH, // match()
5356 MATCH_STR, // matchstr()
5357 MATCH_LIST, // matchlist()
5358 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005359} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005360
5361 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005362find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005363{
5364 char_u *str = NULL;
5365 long len = 0;
5366 char_u *expr = NULL;
5367 char_u *pat;
5368 regmatch_T regmatch;
5369 char_u patbuf[NUMBUFLEN];
5370 char_u strbuf[NUMBUFLEN];
5371 char_u *save_cpo;
5372 long start = 0;
5373 long nth = 1;
5374 colnr_T startcol = 0;
5375 int match = 0;
5376 list_T *l = NULL;
5377 listitem_T *li = NULL;
5378 long idx = 0;
5379 char_u *tofree = NULL;
5380
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005381 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005382 save_cpo = p_cpo;
5383 p_cpo = (char_u *)"";
5384
5385 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005386 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005387 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005388 // type MATCH_LIST: return empty list when there are no matches.
5389 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005390 if (rettv_list_alloc(rettv) == FAIL)
5391 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005392 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005393 && (list_append_string(rettv->vval.v_list,
5394 (char_u *)"", 0) == FAIL
5395 || list_append_number(rettv->vval.v_list,
5396 (varnumber_T)-1) == FAIL
5397 || list_append_number(rettv->vval.v_list,
5398 (varnumber_T)-1) == FAIL
5399 || list_append_number(rettv->vval.v_list,
5400 (varnumber_T)-1) == FAIL))
5401 {
5402 list_free(rettv->vval.v_list);
5403 rettv->vval.v_list = NULL;
5404 goto theend;
5405 }
5406 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005407 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005408 {
5409 rettv->v_type = VAR_STRING;
5410 rettv->vval.v_string = NULL;
5411 }
5412
5413 if (argvars[0].v_type == VAR_LIST)
5414 {
5415 if ((l = argvars[0].vval.v_list) == NULL)
5416 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005417 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005418 li = l->lv_first;
5419 }
5420 else
5421 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005422 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005423 len = (long)STRLEN(str);
5424 }
5425
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005426 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005427 if (pat == NULL)
5428 goto theend;
5429
5430 if (argvars[2].v_type != VAR_UNKNOWN)
5431 {
5432 int error = FALSE;
5433
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005434 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005435 if (error)
5436 goto theend;
5437 if (l != NULL)
5438 {
5439 li = list_find(l, start);
5440 if (li == NULL)
5441 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005442 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005443 }
5444 else
5445 {
5446 if (start < 0)
5447 start = 0;
5448 if (start > len)
5449 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005450 // When "count" argument is there ignore matches before "start",
5451 // otherwise skip part of the string. Differs when pattern is "^"
5452 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005453 if (argvars[3].v_type != VAR_UNKNOWN)
5454 startcol = start;
5455 else
5456 {
5457 str += start;
5458 len -= start;
5459 }
5460 }
5461
5462 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005463 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005464 if (error)
5465 goto theend;
5466 }
5467
5468 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5469 if (regmatch.regprog != NULL)
5470 {
5471 regmatch.rm_ic = p_ic;
5472
5473 for (;;)
5474 {
5475 if (l != NULL)
5476 {
5477 if (li == NULL)
5478 {
5479 match = FALSE;
5480 break;
5481 }
5482 vim_free(tofree);
5483 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5484 if (str == NULL)
5485 break;
5486 }
5487
5488 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5489
5490 if (match && --nth <= 0)
5491 break;
5492 if (l == NULL && !match)
5493 break;
5494
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005495 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005496 if (l != NULL)
5497 {
5498 li = li->li_next;
5499 ++idx;
5500 }
5501 else
5502 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005503 startcol = (colnr_T)(regmatch.startp[0]
5504 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005505 if (startcol > (colnr_T)len
5506 || str + startcol <= regmatch.startp[0])
5507 {
5508 match = FALSE;
5509 break;
5510 }
5511 }
5512 }
5513
5514 if (match)
5515 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005516 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005517 {
5518 listitem_T *li1 = rettv->vval.v_list->lv_first;
5519 listitem_T *li2 = li1->li_next;
5520 listitem_T *li3 = li2->li_next;
5521 listitem_T *li4 = li3->li_next;
5522
5523 vim_free(li1->li_tv.vval.v_string);
5524 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005525 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005526 li3->li_tv.vval.v_number =
5527 (varnumber_T)(regmatch.startp[0] - expr);
5528 li4->li_tv.vval.v_number =
5529 (varnumber_T)(regmatch.endp[0] - expr);
5530 if (l != NULL)
5531 li2->li_tv.vval.v_number = (varnumber_T)idx;
5532 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005533 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005534 {
5535 int i;
5536
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005537 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005538 for (i = 0; i < NSUBEXP; ++i)
5539 {
5540 if (regmatch.endp[i] == NULL)
5541 {
5542 if (list_append_string(rettv->vval.v_list,
5543 (char_u *)"", 0) == FAIL)
5544 break;
5545 }
5546 else if (list_append_string(rettv->vval.v_list,
5547 regmatch.startp[i],
5548 (int)(regmatch.endp[i] - regmatch.startp[i]))
5549 == FAIL)
5550 break;
5551 }
5552 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005553 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005555 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556 if (l != NULL)
5557 copy_tv(&li->li_tv, rettv);
5558 else
5559 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005560 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005561 }
5562 else if (l != NULL)
5563 rettv->vval.v_number = idx;
5564 else
5565 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005566 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005567 rettv->vval.v_number =
5568 (varnumber_T)(regmatch.startp[0] - str);
5569 else
5570 rettv->vval.v_number =
5571 (varnumber_T)(regmatch.endp[0] - str);
5572 rettv->vval.v_number += (varnumber_T)(str - expr);
5573 }
5574 }
5575 vim_regfree(regmatch.regprog);
5576 }
5577
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005578theend:
5579 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005580 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005581 listitem_remove(rettv->vval.v_list,
5582 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005583 vim_free(tofree);
5584 p_cpo = save_cpo;
5585}
5586
5587/*
5588 * "match()" function
5589 */
5590 static void
5591f_match(typval_T *argvars, typval_T *rettv)
5592{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005593 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005594}
5595
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596/*
5597 * "matchend()" function
5598 */
5599 static void
5600f_matchend(typval_T *argvars, typval_T *rettv)
5601{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005602 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005603}
5604
5605/*
5606 * "matchlist()" function
5607 */
5608 static void
5609f_matchlist(typval_T *argvars, typval_T *rettv)
5610{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005611 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005612}
5613
5614/*
5615 * "matchstr()" function
5616 */
5617 static void
5618f_matchstr(typval_T *argvars, typval_T *rettv)
5619{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005620 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005621}
5622
5623/*
5624 * "matchstrpos()" function
5625 */
5626 static void
5627f_matchstrpos(typval_T *argvars, typval_T *rettv)
5628{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005629 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630}
5631
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005632 static void
5633max_min(typval_T *argvars, typval_T *rettv, int domax)
5634{
5635 varnumber_T n = 0;
5636 varnumber_T i;
5637 int error = FALSE;
5638
5639 if (argvars[0].v_type == VAR_LIST)
5640 {
5641 list_T *l;
5642 listitem_T *li;
5643
5644 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005645 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005646 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005647 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005649 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5650 n = l->lv_u.nonmat.lv_start;
5651 else
5652 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5653 * l->lv_u.nonmat.lv_stride;
5654 }
5655 else
5656 {
5657 li = l->lv_first;
5658 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005660 n = tv_get_number_chk(&li->li_tv, &error);
5661 for (;;)
5662 {
5663 li = li->li_next;
5664 if (li == NULL)
5665 break;
5666 i = tv_get_number_chk(&li->li_tv, &error);
5667 if (domax ? i > n : i < n)
5668 n = i;
5669 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005670 }
5671 }
5672 }
5673 }
5674 else if (argvars[0].v_type == VAR_DICT)
5675 {
5676 dict_T *d;
5677 int first = TRUE;
5678 hashitem_T *hi;
5679 int todo;
5680
5681 d = argvars[0].vval.v_dict;
5682 if (d != NULL)
5683 {
5684 todo = (int)d->dv_hashtab.ht_used;
5685 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5686 {
5687 if (!HASHITEM_EMPTY(hi))
5688 {
5689 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005690 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691 if (first)
5692 {
5693 n = i;
5694 first = FALSE;
5695 }
5696 else if (domax ? i > n : i < n)
5697 n = i;
5698 }
5699 }
5700 }
5701 }
5702 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005703 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005704 rettv->vval.v_number = error ? 0 : n;
5705}
5706
5707/*
5708 * "max()" function
5709 */
5710 static void
5711f_max(typval_T *argvars, typval_T *rettv)
5712{
5713 max_min(argvars, rettv, TRUE);
5714}
5715
5716/*
5717 * "min()" function
5718 */
5719 static void
5720f_min(typval_T *argvars, typval_T *rettv)
5721{
5722 max_min(argvars, rettv, FALSE);
5723}
5724
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005725#if defined(FEAT_MZSCHEME) || defined(PROTO)
5726/*
5727 * "mzeval()" function
5728 */
5729 static void
5730f_mzeval(typval_T *argvars, typval_T *rettv)
5731{
5732 char_u *str;
5733 char_u buf[NUMBUFLEN];
5734
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005735 if (check_restricted() || check_secure())
5736 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005737 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005738 do_mzeval(str, rettv);
5739}
5740
5741 void
5742mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5743{
5744 typval_T argvars[3];
5745
5746 argvars[0].v_type = VAR_STRING;
5747 argvars[0].vval.v_string = name;
5748 copy_tv(args, &argvars[1]);
5749 argvars[2].v_type = VAR_UNKNOWN;
5750 f_call(argvars, rettv);
5751 clear_tv(&argvars[1]);
5752}
5753#endif
5754
5755/*
5756 * "nextnonblank()" function
5757 */
5758 static void
5759f_nextnonblank(typval_T *argvars, typval_T *rettv)
5760{
5761 linenr_T lnum;
5762
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005763 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005764 {
5765 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5766 {
5767 lnum = 0;
5768 break;
5769 }
5770 if (*skipwhite(ml_get(lnum)) != NUL)
5771 break;
5772 }
5773 rettv->vval.v_number = lnum;
5774}
5775
5776/*
5777 * "nr2char()" function
5778 */
5779 static void
5780f_nr2char(typval_T *argvars, typval_T *rettv)
5781{
5782 char_u buf[NUMBUFLEN];
5783
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005784 if (has_mbyte)
5785 {
5786 int utf8 = 0;
5787
5788 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005789 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005791 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005793 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794 }
5795 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005796 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005797 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005798 buf[1] = NUL;
5799 }
5800 rettv->v_type = VAR_STRING;
5801 rettv->vval.v_string = vim_strsave(buf);
5802}
5803
5804/*
5805 * "or(expr, expr)" function
5806 */
5807 static void
5808f_or(typval_T *argvars, typval_T *rettv)
5809{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005810 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5811 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005812}
5813
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005814#ifdef FEAT_PERL
5815/*
5816 * "perleval()" function
5817 */
5818 static void
5819f_perleval(typval_T *argvars, typval_T *rettv)
5820{
5821 char_u *str;
5822 char_u buf[NUMBUFLEN];
5823
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005824 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005825 do_perleval(str, rettv);
5826}
5827#endif
5828
5829#ifdef FEAT_FLOAT
5830/*
5831 * "pow()" function
5832 */
5833 static void
5834f_pow(typval_T *argvars, typval_T *rettv)
5835{
5836 float_T fx = 0.0, fy = 0.0;
5837
5838 rettv->v_type = VAR_FLOAT;
5839 if (get_float_arg(argvars, &fx) == OK
5840 && get_float_arg(&argvars[1], &fy) == OK)
5841 rettv->vval.v_float = pow(fx, fy);
5842 else
5843 rettv->vval.v_float = 0.0;
5844}
5845#endif
5846
5847/*
5848 * "prevnonblank()" function
5849 */
5850 static void
5851f_prevnonblank(typval_T *argvars, typval_T *rettv)
5852{
5853 linenr_T lnum;
5854
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005855 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005856 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5857 lnum = 0;
5858 else
5859 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5860 --lnum;
5861 rettv->vval.v_number = lnum;
5862}
5863
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005864// This dummy va_list is here because:
5865// - passing a NULL pointer doesn't work when va_list isn't a pointer
5866// - locally in the function results in a "used before set" warning
5867// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868static va_list ap;
5869
5870/*
5871 * "printf()" function
5872 */
5873 static void
5874f_printf(typval_T *argvars, typval_T *rettv)
5875{
5876 char_u buf[NUMBUFLEN];
5877 int len;
5878 char_u *s;
5879 int saved_did_emsg = did_emsg;
5880 char *fmt;
5881
5882 rettv->v_type = VAR_STRING;
5883 rettv->vval.v_string = NULL;
5884
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005885 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005886 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005887 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005888 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005889 if (!did_emsg)
5890 {
5891 s = alloc(len + 1);
5892 if (s != NULL)
5893 {
5894 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005895 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5896 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005897 }
5898 }
5899 did_emsg |= saved_did_emsg;
5900}
5901
5902/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005903 * "pum_getpos()" function
5904 */
5905 static void
5906f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5907{
5908 if (rettv_dict_alloc(rettv) != OK)
5909 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005910 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005911}
5912
5913/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914 * "pumvisible()" function
5915 */
5916 static void
5917f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5918{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005919 if (pum_visible())
5920 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005921}
5922
5923#ifdef FEAT_PYTHON3
5924/*
5925 * "py3eval()" function
5926 */
5927 static void
5928f_py3eval(typval_T *argvars, typval_T *rettv)
5929{
5930 char_u *str;
5931 char_u buf[NUMBUFLEN];
5932
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005933 if (check_restricted() || check_secure())
5934 return;
5935
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005936 if (p_pyx == 0)
5937 p_pyx = 3;
5938
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005939 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005940 do_py3eval(str, rettv);
5941}
5942#endif
5943
5944#ifdef FEAT_PYTHON
5945/*
5946 * "pyeval()" function
5947 */
5948 static void
5949f_pyeval(typval_T *argvars, typval_T *rettv)
5950{
5951 char_u *str;
5952 char_u buf[NUMBUFLEN];
5953
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005954 if (check_restricted() || check_secure())
5955 return;
5956
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005957 if (p_pyx == 0)
5958 p_pyx = 2;
5959
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005960 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005961 do_pyeval(str, rettv);
5962}
5963#endif
5964
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005965#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5966/*
5967 * "pyxeval()" function
5968 */
5969 static void
5970f_pyxeval(typval_T *argvars, typval_T *rettv)
5971{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005972 if (check_restricted() || check_secure())
5973 return;
5974
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005975# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5976 init_pyxversion();
5977 if (p_pyx == 2)
5978 f_pyeval(argvars, rettv);
5979 else
5980 f_py3eval(argvars, rettv);
5981# elif defined(FEAT_PYTHON)
5982 f_pyeval(argvars, rettv);
5983# elif defined(FEAT_PYTHON3)
5984 f_py3eval(argvars, rettv);
5985# endif
5986}
5987#endif
5988
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005989static UINT32_T srand_seed_for_testing = 0;
5990static int srand_seed_for_testing_is_used = FALSE;
5991
5992 static void
5993f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5994{
5995 if (argvars[0].v_type == VAR_UNKNOWN)
5996 srand_seed_for_testing_is_used = FALSE;
5997 else
5998 {
5999 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
6000 srand_seed_for_testing_is_used = TRUE;
6001 }
6002}
6003
6004 static void
6005init_srand(UINT32_T *x)
6006{
6007#ifndef MSWIN
6008 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6009#endif
6010
6011 if (srand_seed_for_testing_is_used)
6012 {
6013 *x = srand_seed_for_testing;
6014 return;
6015 }
6016#ifndef MSWIN
6017 if (dev_urandom_state != FAIL)
6018 {
6019 int fd = open("/dev/urandom", O_RDONLY);
6020 struct {
6021 union {
6022 UINT32_T number;
6023 char bytes[sizeof(UINT32_T)];
6024 } contents;
6025 } buf;
6026
6027 // Attempt reading /dev/urandom.
6028 if (fd == -1)
6029 dev_urandom_state = FAIL;
6030 else
6031 {
6032 buf.contents.number = 0;
6033 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6034 != sizeof(UINT32_T))
6035 dev_urandom_state = FAIL;
6036 else
6037 {
6038 dev_urandom_state = OK;
6039 *x = buf.contents.number;
6040 }
6041 close(fd);
6042 }
6043 }
6044 if (dev_urandom_state != OK)
6045 // Reading /dev/urandom doesn't work, fall back to time().
6046#endif
6047 *x = vim_time();
6048}
6049
6050#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6051#define SPLITMIX32(x, z) ( \
6052 z = (x += 0x9e3779b9), \
6053 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6054 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6055 z ^ (z >> 16) \
6056 )
6057#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6058 result = ROTL(y * 5, 7) * 9; \
6059 t = y << 9; \
6060 z ^= x; \
6061 w ^= y; \
6062 y ^= z, x ^= w; \
6063 z ^= t; \
6064 w = ROTL(w, 11);
6065
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006066/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006067 * "rand()" function
6068 */
6069 static void
6070f_rand(typval_T *argvars, typval_T *rettv)
6071{
6072 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006073 static UINT32_T gx, gy, gz, gw;
6074 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006075 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006076 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006077
6078 if (argvars[0].v_type == VAR_UNKNOWN)
6079 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006080 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006081 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006082 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006083 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006084 init_srand(&x);
6085
6086 gx = SPLITMIX32(x, z);
6087 gy = SPLITMIX32(x, z);
6088 gz = SPLITMIX32(x, z);
6089 gw = SPLITMIX32(x, z);
6090 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006091 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006092
6093 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006094 }
6095 else if (argvars[0].v_type == VAR_LIST)
6096 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006097 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006098 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006099 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006100
6101 lx = list_find(l, 0L);
6102 ly = list_find(l, 1L);
6103 lz = list_find(l, 2L);
6104 lw = list_find(l, 3L);
6105 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6106 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6107 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6108 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6109 x = (UINT32_T)lx->li_tv.vval.v_number;
6110 y = (UINT32_T)ly->li_tv.vval.v_number;
6111 z = (UINT32_T)lz->li_tv.vval.v_number;
6112 w = (UINT32_T)lw->li_tv.vval.v_number;
6113
6114 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6115
6116 lx->li_tv.vval.v_number = (varnumber_T)x;
6117 ly->li_tv.vval.v_number = (varnumber_T)y;
6118 lz->li_tv.vval.v_number = (varnumber_T)z;
6119 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006120 }
6121 else
6122 goto theend;
6123
6124 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006125 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006126 return;
6127
6128theend:
6129 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006130 rettv->v_type = VAR_NUMBER;
6131 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006132}
6133
6134/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006135 * "srand()" function
6136 */
6137 static void
6138f_srand(typval_T *argvars, typval_T *rettv)
6139{
6140 UINT32_T x = 0, z;
6141
6142 if (rettv_list_alloc(rettv) == FAIL)
6143 return;
6144 if (argvars[0].v_type == VAR_UNKNOWN)
6145 {
6146 init_srand(&x);
6147 }
6148 else
6149 {
6150 int error = FALSE;
6151
6152 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6153 if (error)
6154 return;
6155 }
6156
6157 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6158 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6159 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6160 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6161}
6162
6163#undef ROTL
6164#undef SPLITMIX32
6165#undef SHUFFLE_XOSHIRO128STARSTAR
6166
6167/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006168 * "range()" function
6169 */
6170 static void
6171f_range(typval_T *argvars, typval_T *rettv)
6172{
6173 varnumber_T start;
6174 varnumber_T end;
6175 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006176 int error = FALSE;
6177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006178 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006179 if (argvars[1].v_type == VAR_UNKNOWN)
6180 {
6181 end = start - 1;
6182 start = 0;
6183 }
6184 else
6185 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006186 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006187 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006188 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006189 }
6190
6191 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006192 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006193 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006194 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006196 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006197 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006199 list_T *list = rettv->vval.v_list;
6200
6201 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006202 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006203 // be called.
6204 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006205 list->lv_u.nonmat.lv_start = start;
6206 list->lv_u.nonmat.lv_end = end;
6207 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006208 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006209 }
6210}
6211
6212/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006213 * Materialize "list".
6214 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006215 */
6216 void
6217range_list_materialize(list_T *list)
6218{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006219 varnumber_T start = list->lv_u.nonmat.lv_start;
6220 varnumber_T end = list->lv_u.nonmat.lv_end;
6221 int stride = list->lv_u.nonmat.lv_stride;
6222 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006223
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006224 list->lv_first = NULL;
6225 list->lv_u.mat.lv_last = NULL;
6226 list->lv_len = 0;
6227 list->lv_u.mat.lv_idx_item = NULL;
6228 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6229 if (list_append_number(list, (varnumber_T)i) == FAIL)
6230 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006231}
6232
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006233/*
6234 * "getreginfo()" function
6235 */
6236 static void
6237f_getreginfo(typval_T *argvars, typval_T *rettv)
6238{
6239 char_u *strregname;
6240 int regname;
6241 char_u buf[NUMBUFLEN + 2];
6242 long reglen = 0;
6243 dict_T *dict;
6244 list_T *list;
6245
6246 if (argvars[0].v_type != VAR_UNKNOWN)
6247 {
6248 strregname = tv_get_string_chk(&argvars[0]);
6249 if (strregname == NULL)
6250 return;
6251 }
6252 else
6253 strregname = get_vim_var_str(VV_REG);
6254
6255 regname = (strregname == NULL ? '"' : *strregname);
6256 if (regname == 0 || regname == '@')
6257 regname = '"';
6258
6259 if (rettv_dict_alloc(rettv) == FAIL)
6260 return;
6261 dict = rettv->vval.v_dict;
6262
6263 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
6264 if (list == NULL)
6265 return;
6266 dict_add_list(dict, "regcontents", list);
6267
6268 buf[0] = NUL;
6269 buf[1] = NUL;
6270 switch (get_reg_type(regname, &reglen))
6271 {
6272 case MLINE: buf[0] = 'V'; break;
6273 case MCHAR: buf[0] = 'v'; break;
6274 case MBLOCK:
6275 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
6276 reglen + 1);
6277 break;
6278 }
6279 dict_add_string(dict, (char *)"regtype", buf);
6280
6281 buf[0] = get_register_name(get_unname_register());
6282 buf[1] = NUL;
6283 if (regname == '"')
6284 dict_add_string(dict, (char *)"points_to", buf);
6285 else
6286 {
6287 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
6288
6289 if (item != NULL)
6290 {
6291 item->di_tv.v_type = VAR_SPECIAL;
6292 item->di_tv.vval.v_number = regname == buf[0]
6293 ? VVAL_TRUE : VVAL_FALSE;
6294 dict_add(dict, item);
6295 }
6296 }
6297}
6298
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006299 static void
6300return_register(int regname, typval_T *rettv)
6301{
6302 char_u buf[2] = {0, 0};
6303
6304 buf[0] = (char_u)regname;
6305 rettv->v_type = VAR_STRING;
6306 rettv->vval.v_string = vim_strsave(buf);
6307}
6308
6309/*
6310 * "reg_executing()" function
6311 */
6312 static void
6313f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6314{
6315 return_register(reg_executing, rettv);
6316}
6317
6318/*
6319 * "reg_recording()" function
6320 */
6321 static void
6322f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6323{
6324 return_register(reg_recording, rettv);
6325}
6326
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006327/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006328 * "rename({from}, {to})" function
6329 */
6330 static void
6331f_rename(typval_T *argvars, typval_T *rettv)
6332{
6333 char_u buf[NUMBUFLEN];
6334
6335 if (check_restricted() || check_secure())
6336 rettv->vval.v_number = -1;
6337 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006338 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6339 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006340}
6341
6342/*
6343 * "repeat()" function
6344 */
6345 static void
6346f_repeat(typval_T *argvars, typval_T *rettv)
6347{
6348 char_u *p;
6349 int n;
6350 int slen;
6351 int len;
6352 char_u *r;
6353 int i;
6354
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006355 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006356 if (argvars[0].v_type == VAR_LIST)
6357 {
6358 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6359 while (n-- > 0)
6360 if (list_extend(rettv->vval.v_list,
6361 argvars[0].vval.v_list, NULL) == FAIL)
6362 break;
6363 }
6364 else
6365 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006366 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006367 rettv->v_type = VAR_STRING;
6368 rettv->vval.v_string = NULL;
6369
6370 slen = (int)STRLEN(p);
6371 len = slen * n;
6372 if (len <= 0)
6373 return;
6374
6375 r = alloc(len + 1);
6376 if (r != NULL)
6377 {
6378 for (i = 0; i < n; i++)
6379 mch_memmove(r + i * slen, p, (size_t)slen);
6380 r[len] = NUL;
6381 }
6382
6383 rettv->vval.v_string = r;
6384 }
6385}
6386
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006387#define SP_NOMOVE 0x01 // don't move cursor
6388#define SP_REPEAT 0x02 // repeat to find outer pair
6389#define SP_RETCOUNT 0x04 // return matchcount
6390#define SP_SETPCMARK 0x08 // set previous context mark
6391#define SP_START 0x10 // accept match at start position
6392#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6393#define SP_END 0x40 // leave cursor at end of match
6394#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006395
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396/*
6397 * Get flags for a search function.
6398 * Possibly sets "p_ws".
6399 * Returns BACKWARD, FORWARD or zero (for an error).
6400 */
6401 static int
6402get_search_arg(typval_T *varp, int *flagsp)
6403{
6404 int dir = FORWARD;
6405 char_u *flags;
6406 char_u nbuf[NUMBUFLEN];
6407 int mask;
6408
6409 if (varp->v_type != VAR_UNKNOWN)
6410 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006411 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006413 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006414 while (*flags != NUL)
6415 {
6416 switch (*flags)
6417 {
6418 case 'b': dir = BACKWARD; break;
6419 case 'w': p_ws = TRUE; break;
6420 case 'W': p_ws = FALSE; break;
6421 default: mask = 0;
6422 if (flagsp != NULL)
6423 switch (*flags)
6424 {
6425 case 'c': mask = SP_START; break;
6426 case 'e': mask = SP_END; break;
6427 case 'm': mask = SP_RETCOUNT; break;
6428 case 'n': mask = SP_NOMOVE; break;
6429 case 'p': mask = SP_SUBPAT; break;
6430 case 'r': mask = SP_REPEAT; break;
6431 case 's': mask = SP_SETPCMARK; break;
6432 case 'z': mask = SP_COLUMN; break;
6433 }
6434 if (mask == 0)
6435 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006436 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006437 dir = 0;
6438 }
6439 else
6440 *flagsp |= mask;
6441 }
6442 if (dir == 0)
6443 break;
6444 ++flags;
6445 }
6446 }
6447 return dir;
6448}
6449
6450/*
6451 * Shared by search() and searchpos() functions.
6452 */
6453 static int
6454search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6455{
6456 int flags;
6457 char_u *pat;
6458 pos_T pos;
6459 pos_T save_cursor;
6460 int save_p_ws = p_ws;
6461 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006462 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006463 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006464#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006465 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466 long time_limit = 0;
6467#endif
6468 int options = SEARCH_KEEP;
6469 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006470 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006471 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006472 pos_T firstpos;
6473
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006474 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006475 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 if (dir == 0)
6477 goto theend;
6478 flags = *flagsp;
6479 if (flags & SP_START)
6480 options |= SEARCH_START;
6481 if (flags & SP_END)
6482 options |= SEARCH_END;
6483 if (flags & SP_COLUMN)
6484 options |= SEARCH_COL;
6485
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006486 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6488 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006489 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006490 if (lnum_stop < 0)
6491 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006492 if (argvars[3].v_type != VAR_UNKNOWN)
6493 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006494#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006495 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 if (time_limit < 0)
6497 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006498#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02006499 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006500 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 }
6502
6503#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006504 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505 profile_setlimit(time_limit, &tm);
6506#endif
6507
6508 /*
6509 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6510 * Check to make sure only those flags are set.
6511 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6512 * flags cannot be set. Check for that condition also.
6513 */
6514 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6515 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6516 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006517 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006518 goto theend;
6519 }
6520
6521 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006522 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02006523 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006524 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6525#ifdef FEAT_RELTIME
6526 sia.sa_tm = &tm;
6527#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006528
6529 // Repeat until {skip} returns FALSE.
6530 for (;;)
6531 {
6532 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006533 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006534 // finding the first match again means there is no match where {skip}
6535 // evaluates to zero.
6536 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
6537 subpatnum = FAIL;
6538
Bram Moolenaara9c01042020-06-07 14:50:50 +02006539 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006540 // didn't find it or no skip argument
6541 break;
6542 firstpos = pos;
6543
Bram Moolenaara9c01042020-06-07 14:50:50 +02006544 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006545 {
6546 int do_skip;
6547 int err;
6548 pos_T save_pos = curwin->w_cursor;
6549
6550 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006551 err = FALSE;
6552 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006553 curwin->w_cursor = save_pos;
6554 if (err)
6555 {
6556 // Evaluating {skip} caused an error, break here.
6557 subpatnum = FAIL;
6558 break;
6559 }
6560 if (!do_skip)
6561 break;
6562 }
6563 }
6564
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006565 if (subpatnum != FAIL)
6566 {
6567 if (flags & SP_SUBPAT)
6568 retval = subpatnum;
6569 else
6570 retval = pos.lnum;
6571 if (flags & SP_SETPCMARK)
6572 setpcmark();
6573 curwin->w_cursor = pos;
6574 if (match_pos != NULL)
6575 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006576 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006577 match_pos->lnum = pos.lnum;
6578 match_pos->col = pos.col + 1;
6579 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006580 // "/$" will put the cursor after the end of the line, may need to
6581 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006582 check_cursor();
6583 }
6584
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006585 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 if (flags & SP_NOMOVE)
6587 curwin->w_cursor = save_cursor;
6588 else
6589 curwin->w_set_curswant = TRUE;
6590theend:
6591 p_ws = save_p_ws;
6592
6593 return retval;
6594}
6595
6596#ifdef FEAT_FLOAT
6597
6598/*
6599 * round() is not in C90, use ceil() or floor() instead.
6600 */
6601 float_T
6602vim_round(float_T f)
6603{
6604 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6605}
6606
6607/*
6608 * "round({float})" function
6609 */
6610 static void
6611f_round(typval_T *argvars, typval_T *rettv)
6612{
6613 float_T f = 0.0;
6614
6615 rettv->v_type = VAR_FLOAT;
6616 if (get_float_arg(argvars, &f) == OK)
6617 rettv->vval.v_float = vim_round(f);
6618 else
6619 rettv->vval.v_float = 0.0;
6620}
6621#endif
6622
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006623#ifdef FEAT_RUBY
6624/*
6625 * "rubyeval()" function
6626 */
6627 static void
6628f_rubyeval(typval_T *argvars, typval_T *rettv)
6629{
6630 char_u *str;
6631 char_u buf[NUMBUFLEN];
6632
6633 str = tv_get_string_buf(&argvars[0], buf);
6634 do_rubyeval(str, rettv);
6635}
6636#endif
6637
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006638/*
6639 * "screenattr()" function
6640 */
6641 static void
6642f_screenattr(typval_T *argvars, typval_T *rettv)
6643{
6644 int row;
6645 int col;
6646 int c;
6647
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006648 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6649 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650 if (row < 0 || row >= screen_Rows
6651 || col < 0 || col >= screen_Columns)
6652 c = -1;
6653 else
6654 c = ScreenAttrs[LineOffset[row] + col];
6655 rettv->vval.v_number = c;
6656}
6657
6658/*
6659 * "screenchar()" function
6660 */
6661 static void
6662f_screenchar(typval_T *argvars, typval_T *rettv)
6663{
6664 int row;
6665 int col;
6666 int off;
6667 int c;
6668
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006669 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6670 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006671 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006672 c = -1;
6673 else
6674 {
6675 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006676 if (enc_utf8 && ScreenLinesUC[off] != 0)
6677 c = ScreenLinesUC[off];
6678 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006679 c = ScreenLines[off];
6680 }
6681 rettv->vval.v_number = c;
6682}
6683
6684/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006685 * "screenchars()" function
6686 */
6687 static void
6688f_screenchars(typval_T *argvars, typval_T *rettv)
6689{
6690 int row;
6691 int col;
6692 int off;
6693 int c;
6694 int i;
6695
6696 if (rettv_list_alloc(rettv) == FAIL)
6697 return;
6698 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6699 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6700 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6701 return;
6702
6703 off = LineOffset[row] + col;
6704 if (enc_utf8 && ScreenLinesUC[off] != 0)
6705 c = ScreenLinesUC[off];
6706 else
6707 c = ScreenLines[off];
6708 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6709
6710 if (enc_utf8)
6711
6712 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6713 list_append_number(rettv->vval.v_list,
6714 (varnumber_T)ScreenLinesC[i][off]);
6715}
6716
6717/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 * "screencol()" function
6719 *
6720 * First column is 1 to be consistent with virtcol().
6721 */
6722 static void
6723f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6724{
6725 rettv->vval.v_number = screen_screencol() + 1;
6726}
6727
6728/*
6729 * "screenrow()" function
6730 */
6731 static void
6732f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6733{
6734 rettv->vval.v_number = screen_screenrow() + 1;
6735}
6736
6737/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006738 * "screenstring()" function
6739 */
6740 static void
6741f_screenstring(typval_T *argvars, typval_T *rettv)
6742{
6743 int row;
6744 int col;
6745 int off;
6746 int c;
6747 int i;
6748 char_u buf[MB_MAXBYTES + 1];
6749 int buflen = 0;
6750
6751 rettv->vval.v_string = NULL;
6752 rettv->v_type = VAR_STRING;
6753
6754 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6755 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6756 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6757 return;
6758
6759 off = LineOffset[row] + col;
6760 if (enc_utf8 && ScreenLinesUC[off] != 0)
6761 c = ScreenLinesUC[off];
6762 else
6763 c = ScreenLines[off];
6764 buflen += mb_char2bytes(c, buf);
6765
6766 if (enc_utf8)
6767 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6768 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6769
6770 buf[buflen] = NUL;
6771 rettv->vval.v_string = vim_strsave(buf);
6772}
6773
6774/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006775 * "search()" function
6776 */
6777 static void
6778f_search(typval_T *argvars, typval_T *rettv)
6779{
6780 int flags = 0;
6781
6782 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6783}
6784
6785/*
6786 * "searchdecl()" function
6787 */
6788 static void
6789f_searchdecl(typval_T *argvars, typval_T *rettv)
6790{
6791 int locally = 1;
6792 int thisblock = 0;
6793 int error = FALSE;
6794 char_u *name;
6795
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006796 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006798 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006799 if (argvars[1].v_type != VAR_UNKNOWN)
6800 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006801 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006803 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804 }
6805 if (!error && name != NULL)
6806 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6807 locally, thisblock, SEARCH_KEEP) == FAIL;
6808}
6809
6810/*
6811 * Used by searchpair() and searchpairpos()
6812 */
6813 static int
6814searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6815{
6816 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006817 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006818 int save_p_ws = p_ws;
6819 int dir;
6820 int flags = 0;
6821 char_u nbuf1[NUMBUFLEN];
6822 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006823 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006824 long lnum_stop = 0;
6825 long time_limit = 0;
6826
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006827 // Get the three pattern arguments: start, middle, end. Will result in an
6828 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006829 spat = tv_get_string_chk(&argvars[0]);
6830 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6831 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006832 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006833 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006835 // Handle the optional fourth argument: flags
6836 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006837 if (dir == 0)
6838 goto theend;
6839
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006840 // Don't accept SP_END or SP_SUBPAT.
6841 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842 if ((flags & (SP_END | SP_SUBPAT)) != 0
6843 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6844 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006845 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006846 goto theend;
6847 }
6848
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006849 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850 if (flags & SP_REPEAT)
6851 p_ws = FALSE;
6852
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006853 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006854 if (argvars[3].v_type == VAR_UNKNOWN
6855 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006856 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006857 else
6858 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02006859 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01006860 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02006861
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 if (argvars[5].v_type != VAR_UNKNOWN)
6863 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006864 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006866 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006867 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006869 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870#ifdef FEAT_RELTIME
6871 if (argvars[6].v_type != VAR_UNKNOWN)
6872 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006873 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006875 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006876 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006878 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879 }
6880#endif
6881 }
6882 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883
6884 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6885 match_pos, lnum_stop, time_limit);
6886
6887theend:
6888 p_ws = save_p_ws;
6889
6890 return retval;
6891}
6892
6893/*
6894 * "searchpair()" function
6895 */
6896 static void
6897f_searchpair(typval_T *argvars, typval_T *rettv)
6898{
6899 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6900}
6901
6902/*
6903 * "searchpairpos()" function
6904 */
6905 static void
6906f_searchpairpos(typval_T *argvars, typval_T *rettv)
6907{
6908 pos_T match_pos;
6909 int lnum = 0;
6910 int col = 0;
6911
6912 if (rettv_list_alloc(rettv) == FAIL)
6913 return;
6914
6915 if (searchpair_cmn(argvars, &match_pos) > 0)
6916 {
6917 lnum = match_pos.lnum;
6918 col = match_pos.col;
6919 }
6920
6921 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6922 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6923}
6924
6925/*
6926 * Search for a start/middle/end thing.
6927 * Used by searchpair(), see its documentation for the details.
6928 * Returns 0 or -1 for no match,
6929 */
6930 long
6931do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006932 char_u *spat, // start pattern
6933 char_u *mpat, // middle pattern
6934 char_u *epat, // end pattern
6935 int dir, // BACKWARD or FORWARD
6936 typval_T *skip, // skip expression
6937 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006938 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006939 linenr_T lnum_stop, // stop at this line if not zero
6940 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006941{
6942 char_u *save_cpo;
6943 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6944 long retval = 0;
6945 pos_T pos;
6946 pos_T firstpos;
6947 pos_T foundpos;
6948 pos_T save_cursor;
6949 pos_T save_pos;
6950 int n;
6951 int r;
6952 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006953 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954 int err;
6955 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006956#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006957 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006958#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006960 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961 save_cpo = p_cpo;
6962 p_cpo = empty_option;
6963
6964#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006965 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 profile_setlimit(time_limit, &tm);
6967#endif
6968
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006969 // Make two search patterns: start/end (pat2, for in nested pairs) and
6970 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006971 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6972 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006973 if (pat2 == NULL || pat3 == NULL)
6974 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006975 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006976 if (*mpat == NUL)
6977 STRCPY(pat3, pat2);
6978 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006979 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006980 spat, epat, mpat);
6981 if (flags & SP_START)
6982 options |= SEARCH_START;
6983
Bram Moolenaar48570482017-10-30 21:48:41 +01006984 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02006985 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01006986
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006987 save_cursor = curwin->w_cursor;
6988 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006989 CLEAR_POS(&firstpos);
6990 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991 pat = pat3;
6992 for (;;)
6993 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006994 searchit_arg_T sia;
6995
Bram Moolenaara80faa82020-04-12 19:37:17 +02006996 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006997 sia.sa_stop_lnum = lnum_stop;
6998#ifdef FEAT_RELTIME
6999 sia.sa_tm = &tm;
7000#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007001 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007002 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007003 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007004 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007005 break;
7006
7007 if (firstpos.lnum == 0)
7008 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007009 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007011 // Found the same position again. Can happen with a pattern that
7012 // has "\zs" at the end and searching backwards. Advance one
7013 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007014 if (dir == BACKWARD)
7015 decl(&pos);
7016 else
7017 incl(&pos);
7018 }
7019 foundpos = pos;
7020
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007021 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007022 options &= ~SEARCH_START;
7023
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007024 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007025 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007026 {
7027 save_pos = curwin->w_cursor;
7028 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007029 err = FALSE;
7030 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007031 curwin->w_cursor = save_pos;
7032 if (err)
7033 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007034 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007035 curwin->w_cursor = save_cursor;
7036 retval = -1;
7037 break;
7038 }
7039 if (r)
7040 continue;
7041 }
7042
7043 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7044 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007045 // Found end when searching backwards or start when searching
7046 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007047 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007048 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007049 }
7050 else
7051 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007052 // Found end when searching forward or start when searching
7053 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007054 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007055 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007056 }
7057
7058 if (nest == 0)
7059 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007060 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007061 if (flags & SP_RETCOUNT)
7062 ++retval;
7063 else
7064 retval = pos.lnum;
7065 if (flags & SP_SETPCMARK)
7066 setpcmark();
7067 curwin->w_cursor = pos;
7068 if (!(flags & SP_REPEAT))
7069 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007070 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 }
7072 }
7073
7074 if (match_pos != NULL)
7075 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007076 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007077 match_pos->lnum = curwin->w_cursor.lnum;
7078 match_pos->col = curwin->w_cursor.col + 1;
7079 }
7080
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007081 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007082 if ((flags & SP_NOMOVE) || retval == 0)
7083 curwin->w_cursor = save_cursor;
7084
7085theend:
7086 vim_free(pat2);
7087 vim_free(pat3);
7088 if (p_cpo == empty_option)
7089 p_cpo = save_cpo;
7090 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007091 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 free_string_option(save_cpo);
7093
7094 return retval;
7095}
7096
7097/*
7098 * "searchpos()" function
7099 */
7100 static void
7101f_searchpos(typval_T *argvars, typval_T *rettv)
7102{
7103 pos_T match_pos;
7104 int lnum = 0;
7105 int col = 0;
7106 int n;
7107 int flags = 0;
7108
7109 if (rettv_list_alloc(rettv) == FAIL)
7110 return;
7111
7112 n = search_cmn(argvars, &match_pos, &flags);
7113 if (n > 0)
7114 {
7115 lnum = match_pos.lnum;
7116 col = match_pos.col;
7117 }
7118
7119 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7120 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7121 if (flags & SP_SUBPAT)
7122 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7123}
7124
7125 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007126f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7127{
7128 dict_T *d;
7129 dictitem_T *di;
7130 char_u *csearch;
7131
7132 if (argvars[0].v_type != VAR_DICT)
7133 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007134 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 return;
7136 }
7137
7138 if ((d = argvars[0].vval.v_dict) != NULL)
7139 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007140 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007141 if (csearch != NULL)
7142 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007143 if (enc_utf8)
7144 {
7145 int pcc[MAX_MCO];
7146 int c = utfc_ptr2char(csearch, pcc);
7147
7148 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7149 }
7150 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007151 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007152 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007153 }
7154
7155 di = dict_find(d, (char_u *)"forward", -1);
7156 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007157 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007158 ? FORWARD : BACKWARD);
7159
7160 di = dict_find(d, (char_u *)"until", -1);
7161 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007162 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007163 }
7164}
7165
7166/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007167 * "setenv()" function
7168 */
7169 static void
7170f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7171{
7172 char_u namebuf[NUMBUFLEN];
7173 char_u valbuf[NUMBUFLEN];
7174 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7175
7176 if (argvars[1].v_type == VAR_SPECIAL
7177 && argvars[1].vval.v_number == VVAL_NULL)
7178 vim_unsetenv(name);
7179 else
7180 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7181}
7182
7183/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007184 * "setfperm({fname}, {mode})" function
7185 */
7186 static void
7187f_setfperm(typval_T *argvars, typval_T *rettv)
7188{
7189 char_u *fname;
7190 char_u modebuf[NUMBUFLEN];
7191 char_u *mode_str;
7192 int i;
7193 int mask;
7194 int mode = 0;
7195
7196 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007197 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007198 if (fname == NULL)
7199 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007200 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007201 if (mode_str == NULL)
7202 return;
7203 if (STRLEN(mode_str) != 9)
7204 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007205 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 return;
7207 }
7208
7209 mask = 1;
7210 for (i = 8; i >= 0; --i)
7211 {
7212 if (mode_str[i] != '-')
7213 mode |= mask;
7214 mask = mask << 1;
7215 }
7216 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7217}
7218
7219/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007220 * "setpos()" function
7221 */
7222 static void
7223f_setpos(typval_T *argvars, typval_T *rettv)
7224{
7225 pos_T pos;
7226 int fnum;
7227 char_u *name;
7228 colnr_T curswant = -1;
7229
7230 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007231 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007232 if (name != NULL)
7233 {
7234 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7235 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007236 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007237 pos.col = 0;
7238 if (name[0] == '.' && name[1] == NUL)
7239 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007240 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007241 curwin->w_cursor = pos;
7242 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007243 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007244 curwin->w_curswant = curswant - 1;
7245 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007246 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007247 check_cursor();
7248 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007249 }
7250 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7251 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007252 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007253 if (setmark_pos(name[1], &pos, fnum) == OK)
7254 rettv->vval.v_number = 0;
7255 }
7256 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007257 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258 }
7259 }
7260}
7261
7262/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007263 * "setreg()" function
7264 */
7265 static void
7266f_setreg(typval_T *argvars, typval_T *rettv)
7267{
7268 int regname;
7269 char_u *strregname;
7270 char_u *stropt;
7271 char_u *strval;
7272 int append;
7273 char_u yank_type;
7274 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007275 typval_T *regcontents;
7276 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007277
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007278 pointreg = 0;
7279 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007280 block_len = -1;
7281 yank_type = MAUTO;
7282 append = FALSE;
7283
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007284 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007285 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007286
7287 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007288 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007289 regname = *strregname;
7290 if (regname == 0 || regname == '@')
7291 regname = '"';
7292
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007293 if (argvars[1].v_type == VAR_DICT)
7294 {
7295 dict_T *d = argvars[1].vval.v_dict;
7296 dictitem_T *di = dict_find(d, (char_u *)"regcontents", -1);
7297 if (di != NULL)
7298 regcontents = &di->di_tv;
7299
7300 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
7301 if (stropt != NULL)
7302 switch (*stropt)
7303 {
7304 case 'v': // character-wise selection
7305 yank_type = MCHAR;
7306 break;
7307 case 'V': // line-wise selection
7308 yank_type = MLINE;
7309 break;
7310 case Ctrl_V: // block-wise selection
7311 yank_type = MBLOCK;
7312 if (VIM_ISDIGIT(stropt[1]))
7313 {
7314 ++stropt;
7315 block_len = getdigits(&stropt) - 1;
7316 --stropt;
7317 }
7318 break;
7319 }
7320
7321 if (regname == '"')
7322 {
7323 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
7324 if (stropt != NULL)
7325 {
7326 pointreg = *stropt;
7327 regname = pointreg;
7328 }
7329 }
7330 else if (dict_get_number(d, (char_u *)"isunnamed"))
7331 pointreg = regname;
7332 }
7333 else
7334 regcontents = &argvars[1];
7335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336 if (argvars[2].v_type != VAR_UNKNOWN)
7337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007338 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007339 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007340 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007341 for (; *stropt != NUL; ++stropt)
7342 switch (*stropt)
7343 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007344 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 append = TRUE;
7346 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007347 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007348 yank_type = MCHAR;
7349 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007350 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351 yank_type = MLINE;
7352 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007353 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007354 yank_type = MBLOCK;
7355 if (VIM_ISDIGIT(stropt[1]))
7356 {
7357 ++stropt;
7358 block_len = getdigits(&stropt) - 1;
7359 --stropt;
7360 }
7361 break;
7362 }
7363 }
7364
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007365 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007366 {
7367 char_u **lstval;
7368 char_u **allocval;
7369 char_u buf[NUMBUFLEN];
7370 char_u **curval;
7371 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007372 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007373 listitem_T *li;
7374 int len;
7375
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007376 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 len = ll == NULL ? 0 : ll->lv_len;
7378
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007379 // First half: use for pointers to result lines; second half: use for
7380 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007381 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 if (lstval == NULL)
7383 return;
7384 curval = lstval;
7385 allocval = lstval + len + 2;
7386 curallocval = allocval;
7387
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007388 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007389 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007390 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007391 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007393 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007394 if (strval == NULL)
7395 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007396 if (strval == buf)
7397 {
7398 // Need to make a copy, next tv_get_string_buf_chk() will
7399 // overwrite the string.
7400 strval = vim_strsave(buf);
7401 if (strval == NULL)
7402 goto free_lstval;
7403 *curallocval++ = strval;
7404 }
7405 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007406 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 }
7408 *curval++ = NULL;
7409
7410 write_reg_contents_lst(regname, lstval, -1,
7411 append, yank_type, block_len);
7412free_lstval:
7413 while (curallocval > allocval)
7414 vim_free(*--curallocval);
7415 vim_free(lstval);
7416 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007417 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007419 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007420 if (strval == NULL)
7421 return;
7422 write_reg_contents_ex(regname, strval, -1,
7423 append, yank_type, block_len);
7424 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007425 if (pointreg != 0)
7426 get_yank_register(pointreg, TRUE);
7427
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 rettv->vval.v_number = 0;
7429}
7430
7431/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007432 * "settagstack()" function
7433 */
7434 static void
7435f_settagstack(typval_T *argvars, typval_T *rettv)
7436{
7437 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7438 win_T *wp;
7439 dict_T *d;
7440 int action = 'r';
7441
7442 rettv->vval.v_number = -1;
7443
7444 // first argument: window number or id
7445 wp = find_win_by_nr_or_id(&argvars[0]);
7446 if (wp == NULL)
7447 return;
7448
7449 // second argument: dict with items to set in the tag stack
7450 if (argvars[1].v_type != VAR_DICT)
7451 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007452 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007453 return;
7454 }
7455 d = argvars[1].vval.v_dict;
7456 if (d == NULL)
7457 return;
7458
7459 // third argument: action - 'a' for append and 'r' for replace.
7460 // default is to replace the stack.
7461 if (argvars[2].v_type == VAR_UNKNOWN)
7462 action = 'r';
7463 else if (argvars[2].v_type == VAR_STRING)
7464 {
7465 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007466 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007467 if (actstr == NULL)
7468 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007469 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7470 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007471 action = *actstr;
7472 else
7473 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007474 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007475 return;
7476 }
7477 }
7478 else
7479 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007480 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007481 return;
7482 }
7483
7484 if (set_tagstack(wp, d, action) == OK)
7485 rettv->vval.v_number = 0;
7486}
7487
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488#ifdef FEAT_CRYPT
7489/*
7490 * "sha256({string})" function
7491 */
7492 static void
7493f_sha256(typval_T *argvars, typval_T *rettv)
7494{
7495 char_u *p;
7496
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007497 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498 rettv->vval.v_string = vim_strsave(
7499 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7500 rettv->v_type = VAR_STRING;
7501}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007502#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503
7504/*
7505 * "shellescape({string})" function
7506 */
7507 static void
7508f_shellescape(typval_T *argvars, typval_T *rettv)
7509{
Bram Moolenaar20615522017-06-05 18:46:26 +02007510 int do_special = non_zero_arg(&argvars[1]);
7511
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007512 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007513 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007514 rettv->v_type = VAR_STRING;
7515}
7516
7517/*
7518 * shiftwidth() function
7519 */
7520 static void
7521f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7522{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007523 rettv->vval.v_number = 0;
7524
7525 if (argvars[0].v_type != VAR_UNKNOWN)
7526 {
7527 long col;
7528
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007529 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007530 if (col < 0)
7531 return; // type error; errmsg already given
7532#ifdef FEAT_VARTABS
7533 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7534 return;
7535#endif
7536 }
7537
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007538 rettv->vval.v_number = get_sw_value(curbuf);
7539}
7540
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007541#ifdef FEAT_FLOAT
7542/*
7543 * "sin()" function
7544 */
7545 static void
7546f_sin(typval_T *argvars, typval_T *rettv)
7547{
7548 float_T f = 0.0;
7549
7550 rettv->v_type = VAR_FLOAT;
7551 if (get_float_arg(argvars, &f) == OK)
7552 rettv->vval.v_float = sin(f);
7553 else
7554 rettv->vval.v_float = 0.0;
7555}
7556
7557/*
7558 * "sinh()" function
7559 */
7560 static void
7561f_sinh(typval_T *argvars, typval_T *rettv)
7562{
7563 float_T f = 0.0;
7564
7565 rettv->v_type = VAR_FLOAT;
7566 if (get_float_arg(argvars, &f) == OK)
7567 rettv->vval.v_float = sinh(f);
7568 else
7569 rettv->vval.v_float = 0.0;
7570}
7571#endif
7572
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007573/*
7574 * "soundfold({word})" function
7575 */
7576 static void
7577f_soundfold(typval_T *argvars, typval_T *rettv)
7578{
7579 char_u *s;
7580
7581 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007582 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007583#ifdef FEAT_SPELL
7584 rettv->vval.v_string = eval_soundfold(s);
7585#else
7586 rettv->vval.v_string = vim_strsave(s);
7587#endif
7588}
7589
7590/*
7591 * "spellbadword()" function
7592 */
7593 static void
7594f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7595{
7596 char_u *word = (char_u *)"";
7597 hlf_T attr = HLF_COUNT;
7598 int len = 0;
7599
7600 if (rettv_list_alloc(rettv) == FAIL)
7601 return;
7602
7603#ifdef FEAT_SPELL
7604 if (argvars[0].v_type == VAR_UNKNOWN)
7605 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007606 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007607 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7608 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007609 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007611 curwin->w_set_curswant = TRUE;
7612 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613 }
7614 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7615 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007616 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617 int capcol = -1;
7618
7619 if (str != NULL)
7620 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007621 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007622 while (*str != NUL)
7623 {
7624 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7625 if (attr != HLF_COUNT)
7626 {
7627 word = str;
7628 break;
7629 }
7630 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007631 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007632 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633 }
7634 }
7635 }
7636#endif
7637
7638 list_append_string(rettv->vval.v_list, word, len);
7639 list_append_string(rettv->vval.v_list, (char_u *)(
7640 attr == HLF_SPB ? "bad" :
7641 attr == HLF_SPR ? "rare" :
7642 attr == HLF_SPL ? "local" :
7643 attr == HLF_SPC ? "caps" :
7644 ""), -1);
7645}
7646
7647/*
7648 * "spellsuggest()" function
7649 */
7650 static void
7651f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7652{
7653#ifdef FEAT_SPELL
7654 char_u *str;
7655 int typeerr = FALSE;
7656 int maxcount;
7657 garray_T ga;
7658 int i;
7659 listitem_T *li;
7660 int need_capital = FALSE;
7661#endif
7662
7663 if (rettv_list_alloc(rettv) == FAIL)
7664 return;
7665
7666#ifdef FEAT_SPELL
7667 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7668 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007669 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 if (argvars[1].v_type != VAR_UNKNOWN)
7671 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007672 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007673 if (maxcount <= 0)
7674 return;
7675 if (argvars[2].v_type != VAR_UNKNOWN)
7676 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007677 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678 if (typeerr)
7679 return;
7680 }
7681 }
7682 else
7683 maxcount = 25;
7684
7685 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7686
7687 for (i = 0; i < ga.ga_len; ++i)
7688 {
7689 str = ((char_u **)ga.ga_data)[i];
7690
7691 li = listitem_alloc();
7692 if (li == NULL)
7693 vim_free(str);
7694 else
7695 {
7696 li->li_tv.v_type = VAR_STRING;
7697 li->li_tv.v_lock = 0;
7698 li->li_tv.vval.v_string = str;
7699 list_append(rettv->vval.v_list, li);
7700 }
7701 }
7702 ga_clear(&ga);
7703 }
7704#endif
7705}
7706
7707 static void
7708f_split(typval_T *argvars, typval_T *rettv)
7709{
7710 char_u *str;
7711 char_u *end;
7712 char_u *pat = NULL;
7713 regmatch_T regmatch;
7714 char_u patbuf[NUMBUFLEN];
7715 char_u *save_cpo;
7716 int match;
7717 colnr_T col = 0;
7718 int keepempty = FALSE;
7719 int typeerr = FALSE;
7720
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007721 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722 save_cpo = p_cpo;
7723 p_cpo = (char_u *)"";
7724
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007725 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726 if (argvars[1].v_type != VAR_UNKNOWN)
7727 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007728 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007729 if (pat == NULL)
7730 typeerr = TRUE;
7731 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007732 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007733 }
7734 if (pat == NULL || *pat == NUL)
7735 pat = (char_u *)"[\\x01- ]\\+";
7736
7737 if (rettv_list_alloc(rettv) == FAIL)
7738 return;
7739 if (typeerr)
7740 return;
7741
7742 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7743 if (regmatch.regprog != NULL)
7744 {
7745 regmatch.rm_ic = FALSE;
7746 while (*str != NUL || keepempty)
7747 {
7748 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007749 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 else
7751 match = vim_regexec_nl(&regmatch, str, col);
7752 if (match)
7753 end = regmatch.startp[0];
7754 else
7755 end = str + STRLEN(str);
7756 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7757 && *str != NUL && match && end < regmatch.endp[0]))
7758 {
7759 if (list_append_string(rettv->vval.v_list, str,
7760 (int)(end - str)) == FAIL)
7761 break;
7762 }
7763 if (!match)
7764 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007765 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007766 if (regmatch.endp[0] > str)
7767 col = 0;
7768 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007769 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007771 str = regmatch.endp[0];
7772 }
7773
7774 vim_regfree(regmatch.regprog);
7775 }
7776
7777 p_cpo = save_cpo;
7778}
7779
7780#ifdef FEAT_FLOAT
7781/*
7782 * "sqrt()" function
7783 */
7784 static void
7785f_sqrt(typval_T *argvars, typval_T *rettv)
7786{
7787 float_T f = 0.0;
7788
7789 rettv->v_type = VAR_FLOAT;
7790 if (get_float_arg(argvars, &f) == OK)
7791 rettv->vval.v_float = sqrt(f);
7792 else
7793 rettv->vval.v_float = 0.0;
7794}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007795#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007796
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007797#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007798/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799 * "str2float()" function
7800 */
7801 static void
7802f_str2float(typval_T *argvars, typval_T *rettv)
7803{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007804 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007805 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007806
Bram Moolenaar08243d22017-01-10 16:12:29 +01007807 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007808 p = skipwhite(p + 1);
7809 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007810 if (isneg)
7811 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007812 rettv->v_type = VAR_FLOAT;
7813}
7814#endif
7815
7816/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007817 * "str2list()" function
7818 */
7819 static void
7820f_str2list(typval_T *argvars, typval_T *rettv)
7821{
7822 char_u *p;
7823 int utf8 = FALSE;
7824
7825 if (rettv_list_alloc(rettv) == FAIL)
7826 return;
7827
7828 if (argvars[1].v_type != VAR_UNKNOWN)
7829 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7830
7831 p = tv_get_string(&argvars[0]);
7832
7833 if (has_mbyte || utf8)
7834 {
7835 int (*ptr2len)(char_u *);
7836 int (*ptr2char)(char_u *);
7837
7838 if (utf8 || enc_utf8)
7839 {
7840 ptr2len = utf_ptr2len;
7841 ptr2char = utf_ptr2char;
7842 }
7843 else
7844 {
7845 ptr2len = mb_ptr2len;
7846 ptr2char = mb_ptr2char;
7847 }
7848
7849 for ( ; *p != NUL; p += (*ptr2len)(p))
7850 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7851 }
7852 else
7853 for ( ; *p != NUL; ++p)
7854 list_append_number(rettv->vval.v_list, *p);
7855}
7856
7857/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858 * "str2nr()" function
7859 */
7860 static void
7861f_str2nr(typval_T *argvars, typval_T *rettv)
7862{
7863 int base = 10;
7864 char_u *p;
7865 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007866 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007867 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868
7869 if (argvars[1].v_type != VAR_UNKNOWN)
7870 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007871 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007872 if (base != 2 && base != 8 && base != 10 && base != 16)
7873 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007874 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875 return;
7876 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007877 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7878 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007879 }
7880
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007881 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007882 isneg = (*p == '-');
7883 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007884 p = skipwhite(p + 1);
7885 switch (base)
7886 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007887 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02007888 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007889 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007891 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7892 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007893 if (isneg)
7894 rettv->vval.v_number = -n;
7895 else
7896 rettv->vval.v_number = n;
7897
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007898}
7899
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900/*
7901 * "strgetchar()" function
7902 */
7903 static void
7904f_strgetchar(typval_T *argvars, typval_T *rettv)
7905{
7906 char_u *str;
7907 int len;
7908 int error = FALSE;
7909 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007910 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007911
7912 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007913 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914 if (str == NULL)
7915 return;
7916 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007917 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918 if (error)
7919 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007920
Bram Moolenaar13505972019-01-24 15:04:48 +01007921 while (charidx >= 0 && byteidx < len)
7922 {
7923 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007925 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7926 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007927 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007928 --charidx;
7929 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007930 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931}
7932
7933/*
7934 * "stridx()" function
7935 */
7936 static void
7937f_stridx(typval_T *argvars, typval_T *rettv)
7938{
7939 char_u buf[NUMBUFLEN];
7940 char_u *needle;
7941 char_u *haystack;
7942 char_u *save_haystack;
7943 char_u *pos;
7944 int start_idx;
7945
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007946 needle = tv_get_string_chk(&argvars[1]);
7947 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007948 rettv->vval.v_number = -1;
7949 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007950 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951
7952 if (argvars[2].v_type != VAR_UNKNOWN)
7953 {
7954 int error = FALSE;
7955
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007956 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007957 if (error || start_idx >= (int)STRLEN(haystack))
7958 return;
7959 if (start_idx >= 0)
7960 haystack += start_idx;
7961 }
7962
7963 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7964 if (pos != NULL)
7965 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7966}
7967
7968/*
7969 * "string()" function
7970 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007971 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007972f_string(typval_T *argvars, typval_T *rettv)
7973{
7974 char_u *tofree;
7975 char_u numbuf[NUMBUFLEN];
7976
7977 rettv->v_type = VAR_STRING;
7978 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7979 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007980 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007981 if (rettv->vval.v_string != NULL && tofree == NULL)
7982 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7983}
7984
7985/*
7986 * "strlen()" function
7987 */
7988 static void
7989f_strlen(typval_T *argvars, typval_T *rettv)
7990{
7991 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007992 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993}
7994
7995/*
7996 * "strchars()" function
7997 */
7998 static void
7999f_strchars(typval_T *argvars, typval_T *rettv)
8000{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008001 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 varnumber_T len = 0;
8004 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008005
8006 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008007 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008009 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008010 else
8011 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008012 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8013 while (*s != NUL)
8014 {
8015 func_mb_ptr2char_adv(&s);
8016 ++len;
8017 }
8018 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019 }
8020}
8021
8022/*
8023 * "strdisplaywidth()" function
8024 */
8025 static void
8026f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8027{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008028 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029 int col = 0;
8030
8031 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008032 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033
8034 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8035}
8036
8037/*
8038 * "strwidth()" function
8039 */
8040 static void
8041f_strwidth(typval_T *argvars, typval_T *rettv)
8042{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008043 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008044
Bram Moolenaar13505972019-01-24 15:04:48 +01008045 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008046}
8047
8048/*
8049 * "strcharpart()" function
8050 */
8051 static void
8052f_strcharpart(typval_T *argvars, typval_T *rettv)
8053{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008054 char_u *p;
8055 int nchar;
8056 int nbyte = 0;
8057 int charlen;
8058 int len = 0;
8059 int slen;
8060 int error = FALSE;
8061
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008062 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063 slen = (int)STRLEN(p);
8064
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008065 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 if (!error)
8067 {
8068 if (nchar > 0)
8069 while (nchar > 0 && nbyte < slen)
8070 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008071 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008072 --nchar;
8073 }
8074 else
8075 nbyte = nchar;
8076 if (argvars[2].v_type != VAR_UNKNOWN)
8077 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008078 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 while (charlen > 0 && nbyte + len < slen)
8080 {
8081 int off = nbyte + len;
8082
8083 if (off < 0)
8084 len += 1;
8085 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008086 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087 --charlen;
8088 }
8089 }
8090 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008091 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008092 }
8093
8094 /*
8095 * Only return the overlap between the specified part and the actual
8096 * string.
8097 */
8098 if (nbyte < 0)
8099 {
8100 len += nbyte;
8101 nbyte = 0;
8102 }
8103 else if (nbyte > slen)
8104 nbyte = slen;
8105 if (len < 0)
8106 len = 0;
8107 else if (nbyte + len > slen)
8108 len = slen - nbyte;
8109
8110 rettv->v_type = VAR_STRING;
8111 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008112}
8113
8114/*
8115 * "strpart()" function
8116 */
8117 static void
8118f_strpart(typval_T *argvars, typval_T *rettv)
8119{
8120 char_u *p;
8121 int n;
8122 int len;
8123 int slen;
8124 int error = FALSE;
8125
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008126 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008127 slen = (int)STRLEN(p);
8128
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008129 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 if (error)
8131 len = 0;
8132 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008133 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008134 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008135 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008136
8137 /*
8138 * Only return the overlap between the specified part and the actual
8139 * string.
8140 */
8141 if (n < 0)
8142 {
8143 len += n;
8144 n = 0;
8145 }
8146 else if (n > slen)
8147 n = slen;
8148 if (len < 0)
8149 len = 0;
8150 else if (n + len > slen)
8151 len = slen - n;
8152
8153 rettv->v_type = VAR_STRING;
8154 rettv->vval.v_string = vim_strnsave(p + n, len);
8155}
8156
8157/*
8158 * "strridx()" function
8159 */
8160 static void
8161f_strridx(typval_T *argvars, typval_T *rettv)
8162{
8163 char_u buf[NUMBUFLEN];
8164 char_u *needle;
8165 char_u *haystack;
8166 char_u *rest;
8167 char_u *lastmatch = NULL;
8168 int haystack_len, end_idx;
8169
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008170 needle = tv_get_string_chk(&argvars[1]);
8171 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008172
8173 rettv->vval.v_number = -1;
8174 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008175 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176
8177 haystack_len = (int)STRLEN(haystack);
8178 if (argvars[2].v_type != VAR_UNKNOWN)
8179 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008180 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008181 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008183 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 }
8185 else
8186 end_idx = haystack_len;
8187
8188 if (*needle == NUL)
8189 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008190 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008191 lastmatch = haystack + end_idx;
8192 }
8193 else
8194 {
8195 for (rest = haystack; *rest != '\0'; ++rest)
8196 {
8197 rest = (char_u *)strstr((char *)rest, (char *)needle);
8198 if (rest == NULL || rest > haystack + end_idx)
8199 break;
8200 lastmatch = rest;
8201 }
8202 }
8203
8204 if (lastmatch == NULL)
8205 rettv->vval.v_number = -1;
8206 else
8207 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8208}
8209
8210/*
8211 * "strtrans()" function
8212 */
8213 static void
8214f_strtrans(typval_T *argvars, typval_T *rettv)
8215{
8216 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008217 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008218}
8219
8220/*
8221 * "submatch()" function
8222 */
8223 static void
8224f_submatch(typval_T *argvars, typval_T *rettv)
8225{
8226 int error = FALSE;
8227 int no;
8228 int retList = 0;
8229
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008230 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008231 if (error)
8232 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008233 if (no < 0 || no >= NSUBEXP)
8234 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008235 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008236 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008237 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008239 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008240 if (error)
8241 return;
8242
8243 if (retList == 0)
8244 {
8245 rettv->v_type = VAR_STRING;
8246 rettv->vval.v_string = reg_submatch(no);
8247 }
8248 else
8249 {
8250 rettv->v_type = VAR_LIST;
8251 rettv->vval.v_list = reg_submatch_list(no);
8252 }
8253}
8254
8255/*
8256 * "substitute()" function
8257 */
8258 static void
8259f_substitute(typval_T *argvars, typval_T *rettv)
8260{
8261 char_u patbuf[NUMBUFLEN];
8262 char_u subbuf[NUMBUFLEN];
8263 char_u flagsbuf[NUMBUFLEN];
8264
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008265 char_u *str = tv_get_string_chk(&argvars[0]);
8266 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008267 char_u *sub = NULL;
8268 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008269 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008270
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008271 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8272 expr = &argvars[2];
8273 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008274 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008275
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008276 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008277 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8278 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008279 rettv->vval.v_string = NULL;
8280 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008281 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008282}
8283
8284/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008285 * "swapinfo(swap_filename)" function
8286 */
8287 static void
8288f_swapinfo(typval_T *argvars, typval_T *rettv)
8289{
8290 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008291 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008292}
8293
8294/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008295 * "swapname(expr)" function
8296 */
8297 static void
8298f_swapname(typval_T *argvars, typval_T *rettv)
8299{
8300 buf_T *buf;
8301
8302 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008303 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008304 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8305 || buf->b_ml.ml_mfp->mf_fname == NULL)
8306 rettv->vval.v_string = NULL;
8307 else
8308 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8309}
8310
8311/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008312 * "synID(lnum, col, trans)" function
8313 */
8314 static void
8315f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8316{
8317 int id = 0;
8318#ifdef FEAT_SYN_HL
8319 linenr_T lnum;
8320 colnr_T col;
8321 int trans;
8322 int transerr = FALSE;
8323
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008324 lnum = tv_get_lnum(argvars); // -1 on type error
8325 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008326 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008327
8328 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8329 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8330 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8331#endif
8332
8333 rettv->vval.v_number = id;
8334}
8335
8336/*
8337 * "synIDattr(id, what [, mode])" function
8338 */
8339 static void
8340f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8341{
8342 char_u *p = NULL;
8343#ifdef FEAT_SYN_HL
8344 int id;
8345 char_u *what;
8346 char_u *mode;
8347 char_u modebuf[NUMBUFLEN];
8348 int modec;
8349
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008350 id = (int)tv_get_number(&argvars[0]);
8351 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008352 if (argvars[2].v_type != VAR_UNKNOWN)
8353 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008354 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008355 modec = TOLOWER_ASC(mode[0]);
8356 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008357 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008358 }
8359 else
8360 {
8361#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8362 if (USE_24BIT)
8363 modec = 'g';
8364 else
8365#endif
8366 if (t_colors > 1)
8367 modec = 'c';
8368 else
8369 modec = 't';
8370 }
8371
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008372 switch (TOLOWER_ASC(what[0]))
8373 {
8374 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008375 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008377 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008378 p = highlight_has_attr(id, HL_BOLD, modec);
8379 break;
8380
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008381 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008382 p = highlight_color(id, what, modec);
8383 break;
8384
8385 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008386 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008387 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008388 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008389 p = highlight_has_attr(id, HL_ITALIC, modec);
8390 break;
8391
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008392 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008393 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394 break;
8395
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008396 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008397 p = highlight_has_attr(id, HL_INVERSE, modec);
8398 break;
8399
8400 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008401 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008403 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008404 else if (TOLOWER_ASC(what[1]) == 't' &&
8405 TOLOWER_ASC(what[2]) == 'r')
8406 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008407 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008408 p = highlight_has_attr(id, HL_STANDOUT, modec);
8409 break;
8410
8411 case 'u':
8412 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008413 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008414 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8415 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008416 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008417 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8418 break;
8419 }
8420
8421 if (p != NULL)
8422 p = vim_strsave(p);
8423#endif
8424 rettv->v_type = VAR_STRING;
8425 rettv->vval.v_string = p;
8426}
8427
8428/*
8429 * "synIDtrans(id)" function
8430 */
8431 static void
8432f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8433{
8434 int id;
8435
8436#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008437 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008438
8439 if (id > 0)
8440 id = syn_get_final_id(id);
8441 else
8442#endif
8443 id = 0;
8444
8445 rettv->vval.v_number = id;
8446}
8447
8448/*
8449 * "synconcealed(lnum, col)" function
8450 */
8451 static void
8452f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8453{
8454#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8455 linenr_T lnum;
8456 colnr_T col;
8457 int syntax_flags = 0;
8458 int cchar;
8459 int matchid = 0;
8460 char_u str[NUMBUFLEN];
8461#endif
8462
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008463 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008464
8465#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008466 lnum = tv_get_lnum(argvars); // -1 on type error
8467 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008468
Bram Moolenaara80faa82020-04-12 19:37:17 +02008469 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470
8471 if (rettv_list_alloc(rettv) != FAIL)
8472 {
8473 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8474 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8475 && curwin->w_p_cole > 0)
8476 {
8477 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8478 syntax_flags = get_syntax_info(&matchid);
8479
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008480 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008481 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8482 {
8483 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008484 if (cchar == NUL && curwin->w_p_cole == 1)
8485 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008486 if (cchar != NUL)
8487 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008488 if (has_mbyte)
8489 (*mb_char2bytes)(cchar, str);
8490 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008491 str[0] = cchar;
8492 }
8493 }
8494 }
8495
8496 list_append_number(rettv->vval.v_list,
8497 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008498 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008499 list_append_string(rettv->vval.v_list, str, -1);
8500 list_append_number(rettv->vval.v_list, matchid);
8501 }
8502#endif
8503}
8504
8505/*
8506 * "synstack(lnum, col)" function
8507 */
8508 static void
8509f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8510{
8511#ifdef FEAT_SYN_HL
8512 linenr_T lnum;
8513 colnr_T col;
8514 int i;
8515 int id;
8516#endif
8517
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008518 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008519
8520#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008521 lnum = tv_get_lnum(argvars); // -1 on type error
8522 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008523
8524 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8525 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8526 && rettv_list_alloc(rettv) != FAIL)
8527 {
8528 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8529 for (i = 0; ; ++i)
8530 {
8531 id = syn_get_stack_item(i);
8532 if (id < 0)
8533 break;
8534 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8535 break;
8536 }
8537 }
8538#endif
8539}
8540
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008541/*
8542 * "tabpagebuflist()" function
8543 */
8544 static void
8545f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8546{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547 tabpage_T *tp;
8548 win_T *wp = NULL;
8549
8550 if (argvars[0].v_type == VAR_UNKNOWN)
8551 wp = firstwin;
8552 else
8553 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008554 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008555 if (tp != NULL)
8556 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8557 }
8558 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8559 {
8560 for (; wp != NULL; wp = wp->w_next)
8561 if (list_append_number(rettv->vval.v_list,
8562 wp->w_buffer->b_fnum) == FAIL)
8563 break;
8564 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008565}
8566
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008567/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008568 * "tagfiles()" function
8569 */
8570 static void
8571f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8572{
8573 char_u *fname;
8574 tagname_T tn;
8575 int first;
8576
8577 if (rettv_list_alloc(rettv) == FAIL)
8578 return;
8579 fname = alloc(MAXPATHL);
8580 if (fname == NULL)
8581 return;
8582
8583 for (first = TRUE; ; first = FALSE)
8584 if (get_tagfname(&tn, first, fname) == FAIL
8585 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8586 break;
8587 tagname_free(&tn);
8588 vim_free(fname);
8589}
8590
8591/*
8592 * "taglist()" function
8593 */
8594 static void
8595f_taglist(typval_T *argvars, typval_T *rettv)
8596{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008597 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008598 char_u *tag_pattern;
8599
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008600 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008601
8602 rettv->vval.v_number = FALSE;
8603 if (*tag_pattern == NUL)
8604 return;
8605
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008606 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008607 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008609 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008610}
8611
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008612#ifdef FEAT_FLOAT
8613/*
8614 * "tan()" function
8615 */
8616 static void
8617f_tan(typval_T *argvars, typval_T *rettv)
8618{
8619 float_T f = 0.0;
8620
8621 rettv->v_type = VAR_FLOAT;
8622 if (get_float_arg(argvars, &f) == OK)
8623 rettv->vval.v_float = tan(f);
8624 else
8625 rettv->vval.v_float = 0.0;
8626}
8627
8628/*
8629 * "tanh()" function
8630 */
8631 static void
8632f_tanh(typval_T *argvars, typval_T *rettv)
8633{
8634 float_T f = 0.0;
8635
8636 rettv->v_type = VAR_FLOAT;
8637 if (get_float_arg(argvars, &f) == OK)
8638 rettv->vval.v_float = tanh(f);
8639 else
8640 rettv->vval.v_float = 0.0;
8641}
8642#endif
8643
8644/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008645 * "tolower(string)" function
8646 */
8647 static void
8648f_tolower(typval_T *argvars, typval_T *rettv)
8649{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008650 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008651 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008652}
8653
8654/*
8655 * "toupper(string)" function
8656 */
8657 static void
8658f_toupper(typval_T *argvars, typval_T *rettv)
8659{
8660 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008661 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008662}
8663
8664/*
8665 * "tr(string, fromstr, tostr)" function
8666 */
8667 static void
8668f_tr(typval_T *argvars, typval_T *rettv)
8669{
8670 char_u *in_str;
8671 char_u *fromstr;
8672 char_u *tostr;
8673 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008674 int inlen;
8675 int fromlen;
8676 int tolen;
8677 int idx;
8678 char_u *cpstr;
8679 int cplen;
8680 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008681 char_u buf[NUMBUFLEN];
8682 char_u buf2[NUMBUFLEN];
8683 garray_T ga;
8684
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008685 in_str = tv_get_string(&argvars[0]);
8686 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8687 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008688
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008689 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008690 rettv->v_type = VAR_STRING;
8691 rettv->vval.v_string = NULL;
8692 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008693 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008694 ga_init2(&ga, (int)sizeof(char), 80);
8695
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008696 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008697 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008698 if (STRLEN(fromstr) != STRLEN(tostr))
8699 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008700error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008701 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008702 ga_clear(&ga);
8703 return;
8704 }
8705
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008706 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008707 while (*in_str != NUL)
8708 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008709 if (has_mbyte)
8710 {
8711 inlen = (*mb_ptr2len)(in_str);
8712 cpstr = in_str;
8713 cplen = inlen;
8714 idx = 0;
8715 for (p = fromstr; *p != NUL; p += fromlen)
8716 {
8717 fromlen = (*mb_ptr2len)(p);
8718 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8719 {
8720 for (p = tostr; *p != NUL; p += tolen)
8721 {
8722 tolen = (*mb_ptr2len)(p);
8723 if (idx-- == 0)
8724 {
8725 cplen = tolen;
8726 cpstr = p;
8727 break;
8728 }
8729 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008730 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008731 goto error;
8732 break;
8733 }
8734 ++idx;
8735 }
8736
8737 if (first && cpstr == in_str)
8738 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008739 // Check that fromstr and tostr have the same number of
8740 // (multi-byte) characters. Done only once when a character
8741 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008742 first = FALSE;
8743 for (p = tostr; *p != NUL; p += tolen)
8744 {
8745 tolen = (*mb_ptr2len)(p);
8746 --idx;
8747 }
8748 if (idx != 0)
8749 goto error;
8750 }
8751
8752 (void)ga_grow(&ga, cplen);
8753 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8754 ga.ga_len += cplen;
8755
8756 in_str += inlen;
8757 }
8758 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008759 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008760 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008761 p = vim_strchr(fromstr, *in_str);
8762 if (p != NULL)
8763 ga_append(&ga, tostr[p - fromstr]);
8764 else
8765 ga_append(&ga, *in_str);
8766 ++in_str;
8767 }
8768 }
8769
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008770 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008771 (void)ga_grow(&ga, 1);
8772 ga_append(&ga, NUL);
8773
8774 rettv->vval.v_string = ga.ga_data;
8775}
8776
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008777/*
8778 * "trim({expr})" function
8779 */
8780 static void
8781f_trim(typval_T *argvars, typval_T *rettv)
8782{
8783 char_u buf1[NUMBUFLEN];
8784 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008785 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008786 char_u *mask = NULL;
8787 char_u *tail;
8788 char_u *prev;
8789 char_u *p;
8790 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008791 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008792
8793 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008794 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008795 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008796 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008797
8798 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008799 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008800 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008801
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008802 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008803 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008804 int error = 0;
8805
8806 // leading or trailing characters to trim
8807 dir = (int)tv_get_number_chk(&argvars[2], &error);
8808 if (error)
8809 return;
8810 if (dir < 0 || dir > 2)
8811 {
8812 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8813 return;
8814 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008815 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008816 }
8817
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008818 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008819 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008820 // Trim leading characters
8821 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008822 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008823 c1 = PTR2CHAR(head);
8824 if (mask == NULL)
8825 {
8826 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008827 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008828 }
8829 else
8830 {
8831 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8832 if (c1 == PTR2CHAR(p))
8833 break;
8834 if (*p == NUL)
8835 break;
8836 }
8837 MB_PTR_ADV(head);
8838 }
8839 }
8840
8841 tail = head + STRLEN(head);
8842 if (dir == 0 || dir == 2)
8843 {
8844 // Trim trailing characters
8845 for (; tail > head; tail = prev)
8846 {
8847 prev = tail;
8848 MB_PTR_BACK(head, prev);
8849 c1 = PTR2CHAR(prev);
8850 if (mask == NULL)
8851 {
8852 if (c1 > ' ' && c1 != 0xa0)
8853 break;
8854 }
8855 else
8856 {
8857 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8858 if (c1 == PTR2CHAR(p))
8859 break;
8860 if (*p == NUL)
8861 break;
8862 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008863 }
8864 }
Bram Moolenaardf44a272020-06-07 20:49:05 +02008865 rettv->vval.v_string = vim_strnsave(head, tail - head);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008866}
8867
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008868#ifdef FEAT_FLOAT
8869/*
8870 * "trunc({float})" function
8871 */
8872 static void
8873f_trunc(typval_T *argvars, typval_T *rettv)
8874{
8875 float_T f = 0.0;
8876
8877 rettv->v_type = VAR_FLOAT;
8878 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008879 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008880 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8881 else
8882 rettv->vval.v_float = 0.0;
8883}
8884#endif
8885
8886/*
8887 * "type(expr)" function
8888 */
8889 static void
8890f_type(typval_T *argvars, typval_T *rettv)
8891{
8892 int n = -1;
8893
8894 switch (argvars[0].v_type)
8895 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008896 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8897 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008898 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008899 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8900 case VAR_LIST: n = VAR_TYPE_LIST; break;
8901 case VAR_DICT: n = VAR_TYPE_DICT; break;
8902 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8903 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8904 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008905 case VAR_JOB: n = VAR_TYPE_JOB; break;
8906 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008907 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008908 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02008909 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008910 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008911 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008912 n = -1;
8913 break;
8914 }
8915 rettv->vval.v_number = n;
8916}
8917
8918/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008919 * "virtcol(string)" function
8920 */
8921 static void
8922f_virtcol(typval_T *argvars, typval_T *rettv)
8923{
8924 colnr_T vcol = 0;
8925 pos_T *fp;
8926 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008927 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008928
8929 fp = var2fpos(&argvars[0], FALSE, &fnum);
8930 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8931 && fnum == curbuf->b_fnum)
8932 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008933 // Limit the column to a valid value, getvvcol() doesn't check.
8934 if (fp->col < 0)
8935 fp->col = 0;
8936 else
8937 {
8938 len = (int)STRLEN(ml_get(fp->lnum));
8939 if (fp->col > len)
8940 fp->col = len;
8941 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008942 getvvcol(curwin, fp, NULL, NULL, &vcol);
8943 ++vcol;
8944 }
8945
8946 rettv->vval.v_number = vcol;
8947}
8948
8949/*
8950 * "visualmode()" function
8951 */
8952 static void
8953f_visualmode(typval_T *argvars, typval_T *rettv)
8954{
8955 char_u str[2];
8956
8957 rettv->v_type = VAR_STRING;
8958 str[0] = curbuf->b_visual_mode_eval;
8959 str[1] = NUL;
8960 rettv->vval.v_string = vim_strsave(str);
8961
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008962 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008963 if (non_zero_arg(&argvars[0]))
8964 curbuf->b_visual_mode_eval = NUL;
8965}
8966
8967/*
8968 * "wildmenumode()" function
8969 */
8970 static void
8971f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8972{
8973#ifdef FEAT_WILDMENU
8974 if (wild_menu_showing)
8975 rettv->vval.v_number = 1;
8976#endif
8977}
8978
8979/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008980 * "windowsversion()" function
8981 */
8982 static void
8983f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8984{
8985 rettv->v_type = VAR_STRING;
8986 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8987}
8988
8989/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008990 * "wordcount()" function
8991 */
8992 static void
8993f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8994{
8995 if (rettv_dict_alloc(rettv) == FAIL)
8996 return;
8997 cursor_pos_info(rettv->vval.v_dict);
8998}
8999
9000/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009001 * "xor(expr, expr)" function
9002 */
9003 static void
9004f_xor(typval_T *argvars, typval_T *rettv)
9005{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009006 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9007 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009008}
9009
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009010#endif // FEAT_EVAL