blob: cdc806db2b5042f9b1b88d70ffbf2920e6c4a4da [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 Moolenaar15c47602020-03-26 22:16:48 +0100544 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)},
545 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)},
546 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100547 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
548 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
549 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
550 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
551 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
552 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
553 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
554 {"foreground", 0, 0, 0, ret_void, f_foreground},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200555 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100556 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
557 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
558 {"get", 2, 3, FEARG_1, ret_any, f_get},
559 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
560 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
561 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
562 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
563 {"getchar", 0, 1, 0, ret_number, f_getchar},
564 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
565 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
566 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
567 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
568 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
569 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
570 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
571 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
572 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
573 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
574 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
575 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
576 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
577 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
578 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
579 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
580 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
581 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
582 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +0200583 {"getmarklist", 0, 1, FEARG_1, ret_list_dict_any, f_getmarklist},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100584 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
585 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
586 {"getpid", 0, 0, 0, ret_number, f_getpid},
587 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
588 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
589 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
Bram Moolenaarbb861e22020-06-07 18:16:36 +0200590 {"getreginfo", 0, 1, FEARG_1, ret_dict_any, f_getreginfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100591 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
592 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
593 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
594 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
595 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
596 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
597 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
598 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
599 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
600 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
601 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
602 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
603 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100604 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100605 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
606 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
607 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
608 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
609 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
610 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
611 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
612 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
613 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
614 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
615 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
616 {"hostname", 0, 0, 0, ret_string, f_hostname},
617 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
618 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
619 {"index", 2, 4, FEARG_1, ret_number, f_index},
620 {"input", 1, 3, FEARG_1, ret_string, f_input},
621 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
622 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
623 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
624 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
625 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
626 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
627 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
628 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
629 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100630 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100631 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100632 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100633 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100634 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
635 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
636 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
637 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
638 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
639 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100640 {"join", 1, 2, FEARG_1, ret_string, f_join},
641 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
642 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
643 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
644 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
645 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
646 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
647 {"len", 1, 1, FEARG_1, ret_number, f_len},
648 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
649 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
650 {"line", 1, 2, FEARG_1, ret_number, f_line},
651 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
652 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
653 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
654 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
655 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
656 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
657 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100658 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
659 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
660 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100662 f_luaeval
663#else
664 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200665#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100666 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100667 {"map", 2, 2, FEARG_1, ret_any, f_map},
668 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
669 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200670 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100671 {"match", 2, 4, FEARG_1, ret_any, f_match},
672 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
673 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
674 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
675 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
676 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
677 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
678 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
679 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
680 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100681 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100682#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100683 f_menu_info
684#else
685 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100686#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100687 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100688 {"min", 1, 1, FEARG_1, ret_any, f_min},
689 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
690 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100691 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200692#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100693 f_mzeval
694#else
695 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200696#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100697 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100698 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
699 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
700 {"or", 2, 2, FEARG_1, ret_number, f_or},
701 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100702 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200703#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100704 f_perleval
705#else
706 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200707#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100708 },
709 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
710 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200711 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100712 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
713 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
714 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
715 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)},
716 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)},
717 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
718 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
719 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
720 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
721 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200722 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100723 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
724 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
725 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
726 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
727 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
728 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
729 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
730 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100731 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
732 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100733 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
734 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
735 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
736 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
737 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
738 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
739 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
740 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
741 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
742 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
743 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
744 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
745 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100746 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
747 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100748 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200749#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100750 f_py3eval
751#else
752 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200753#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100754 },
755 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200756#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100757 f_pyeval
758#else
759 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200760#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100761 },
762 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100763#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100764 f_pyxeval
765#else
766 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100767#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100768 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100769 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
770 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
771 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
Bram Moolenaar6c9ba042020-06-01 16:09:41 +0200772 {"readdirex", 1, 2, FEARG_1, ret_list_dict_any, f_readdirex},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100773 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
Bram Moolenaar85629982020-06-01 18:39:20 +0200774 {"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100775 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
776 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
777 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100778 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100779 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
780 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
781 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
782 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
783 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
784 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
785 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
786 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
787 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
788 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
789 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
790 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100791 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
792 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100793#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100794 f_rubyeval
795#else
796 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100797#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100798 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100799 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
800 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
801 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
802 {"screencol", 0, 0, 0, ret_number, f_screencol},
803 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
804 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
805 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200806 {"search", 1, 5, FEARG_1, ret_number, f_search},
Bram Moolenaare8f5ec02020-06-01 17:28:35 +0200807 {"searchcount", 0, 1, FEARG_1, ret_dict_any, f_searchcount},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100808 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
809 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
810 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200811 {"searchpos", 1, 5, FEARG_1, ret_list_number, f_searchpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100812 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
813 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
814 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
815 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
816 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
817 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
818 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
819 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
820 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
821 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
822 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
823 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
824 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
825 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
826 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
827 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
828 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
829 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100830 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200831#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100832 f_sha256
833#else
834 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200835#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100836 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100837 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
838 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100839 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
840 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
841 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
842 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
843 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
844 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
845 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
846 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
847 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200848 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100849 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
850 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100851 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100852 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
853 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
854 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
855 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100856 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
857 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
858 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
859 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100860 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100861 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
862 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100863 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100864 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
865 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
866 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
867 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
868 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100869 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100871 f_strftime
872#else
873 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100875 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100876 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
877 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
878 {"string", 1, 1, FEARG_1, ret_string, f_string},
879 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
880 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100881 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100882#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100883 f_strptime
884#else
885 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100886#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100887 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100888 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
889 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
890 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
891 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
892 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
893 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
894 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
895 {"synID", 3, 3, 0, ret_number, f_synID},
896 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
897 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
898 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
899 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
900 {"system", 1, 2, FEARG_1, ret_string, f_system},
901 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
902 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
903 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
904 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
905 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
906 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100907 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
908 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100909 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100910 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
911 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
912 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
913 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
914 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100915#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100916 f_term_getansicolors
917#else
918 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200919#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100920 },
921 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
922 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
923 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
924 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
925 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
926 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
927 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
928 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
929 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
930 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
931 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
932 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
933 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100934#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100935 f_term_setansicolors
936#else
937 NULL
938#endif
939 },
940 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
941 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
942 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
943 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
944 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
945 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100946 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
947 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
948 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
949 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
950 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
951 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
952 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
953 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100954 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100955 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200956 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100957 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100958 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200959 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100960 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
961 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
962 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
963 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100964 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +0200965#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +0100966 f_test_scrollbar
967#else
968 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +0200969#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100970 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100971 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
972 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
973 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
974 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
975 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100976 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
977 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
978 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
979 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
980 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100981 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
982 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
983 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +0200984 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100985 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100986 {"type", 1, 1, FEARG_1, ret_number, f_type},
987 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
988 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
989 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
990 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
991 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
992 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
993 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
994 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
995 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
996 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
997 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
998 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
999 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
1000 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
1001 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
1002 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
1003 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
1004 {"wincol", 0, 0, 0, ret_number, f_wincol},
1005 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1006 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1007 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1008 {"winline", 0, 0, 0, ret_number, f_winline},
1009 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1010 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1011 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1012 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1013 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1014 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1015 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1016 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001017};
1018
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019/*
1020 * Function given to ExpandGeneric() to obtain the list of internal
1021 * or user defined function names.
1022 */
1023 char_u *
1024get_function_name(expand_T *xp, int idx)
1025{
1026 static int intidx = -1;
1027 char_u *name;
1028
1029 if (idx == 0)
1030 intidx = -1;
1031 if (intidx < 0)
1032 {
1033 name = get_user_func_name(xp, idx);
1034 if (name != NULL)
1035 return name;
1036 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001037 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001038 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001039 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001040 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001041 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001042 STRCAT(IObuff, ")");
1043 return IObuff;
1044 }
1045
1046 return NULL;
1047}
1048
1049/*
1050 * Function given to ExpandGeneric() to obtain the list of internal or
1051 * user defined variable or function names.
1052 */
1053 char_u *
1054get_expr_name(expand_T *xp, int idx)
1055{
1056 static int intidx = -1;
1057 char_u *name;
1058
1059 if (idx == 0)
1060 intidx = -1;
1061 if (intidx < 0)
1062 {
1063 name = get_function_name(xp, idx);
1064 if (name != NULL)
1065 return name;
1066 }
1067 return get_user_var_name(xp, ++intidx);
1068}
1069
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001070/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001071 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001072 * Return index, or -1 if not found or "implemented" is TRUE and the function
1073 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001074 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001075 static int
1076find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001077{
1078 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001079 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080 int cmp;
1081 int x;
1082
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001083 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001084
1085 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001086 while (first <= last)
1087 {
1088 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001089 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001090 if (cmp < 0)
1091 last = x - 1;
1092 else if (cmp > 0)
1093 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001094 else if (implemented && global_functions[x].f_func == NULL)
1095 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001096 else
1097 return x;
1098 }
1099 return -1;
1100}
1101
Bram Moolenaar15c47602020-03-26 22:16:48 +01001102/*
1103 * Find internal function "name" in table "global_functions".
1104 * Return index, or -1 if not found or the function is not implemented.
1105 */
1106 int
1107find_internal_func(char_u *name)
1108{
1109 return find_internal_func_opt(name, TRUE);
1110}
1111
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001112 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001113has_internal_func(char_u *name)
1114{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001115 return find_internal_func_opt(name, TRUE) >= 0;
1116}
1117
1118 static int
1119has_internal_func_name(char_u *name)
1120{
1121 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001122}
1123
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001124 char *
1125internal_func_name(int idx)
1126{
1127 return global_functions[idx].f_name;
1128}
1129
1130 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001131internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001132{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001133 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001134}
1135
1136/*
1137 * Check the argument count to use for internal function "idx".
1138 * Returns OK or FAIL;
1139 */
1140 int
1141check_internal_func(int idx, int argcount)
1142{
1143 int res;
1144 char *name;
1145
1146 if (argcount < global_functions[idx].f_min_argc)
1147 res = FCERR_TOOFEW;
1148 else if (argcount > global_functions[idx].f_max_argc)
1149 res = FCERR_TOOMANY;
1150 else
1151 return OK;
1152
1153 name = internal_func_name(idx);
1154 if (res == FCERR_TOOMANY)
1155 semsg(_(e_toomanyarg), name);
1156 else
1157 semsg(_(e_toofewarg), name);
1158 return FAIL;
1159}
1160
Bram Moolenaarac92e252019-08-03 21:58:38 +02001161 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001162call_internal_func(
1163 char_u *name,
1164 int argcount,
1165 typval_T *argvars,
1166 typval_T *rettv)
1167{
1168 int i;
1169
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001170 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001171 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001172 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001173 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001174 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001175 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001176 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001177 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001178 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001179 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001180}
1181
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001182 void
1183call_internal_func_by_idx(
1184 int idx,
1185 typval_T *argvars,
1186 typval_T *rettv)
1187{
1188 global_functions[idx].f_func(argvars, rettv);
1189}
1190
Bram Moolenaarac92e252019-08-03 21:58:38 +02001191/*
1192 * Invoke a method for base->method().
1193 */
1194 int
1195call_internal_method(
1196 char_u *name,
1197 int argcount,
1198 typval_T *argvars,
1199 typval_T *rettv,
1200 typval_T *basetv)
1201{
1202 int i;
1203 int fi;
1204 typval_T argv[MAX_FUNC_ARGS + 1];
1205
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001206 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001207 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001208 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001209 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001210 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001211 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001212 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001213 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001214 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001215
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001216 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001217 {
1218 // base value goes last
1219 for (i = 0; i < argcount; ++i)
1220 argv[i] = argvars[i];
1221 argv[argcount] = *basetv;
1222 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001223 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001224 {
1225 // base value goes second
1226 argv[0] = argvars[0];
1227 argv[1] = *basetv;
1228 for (i = 1; i < argcount; ++i)
1229 argv[i + 1] = argvars[i];
1230 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001231 else if (global_functions[fi].f_argtype == FEARG_3)
1232 {
1233 // base value goes third
1234 argv[0] = argvars[0];
1235 argv[1] = argvars[1];
1236 argv[2] = *basetv;
1237 for (i = 2; i < argcount; ++i)
1238 argv[i + 1] = argvars[i];
1239 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001240 else if (global_functions[fi].f_argtype == FEARG_4)
1241 {
1242 // base value goes fourth
1243 argv[0] = argvars[0];
1244 argv[1] = argvars[1];
1245 argv[2] = argvars[2];
1246 argv[3] = *basetv;
1247 for (i = 3; i < argcount; ++i)
1248 argv[i + 1] = argvars[i];
1249 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001250 else
1251 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001252 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001253 argv[0] = *basetv;
1254 for (i = 0; i < argcount; ++i)
1255 argv[i + 1] = argvars[i];
1256 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001257 argv[argcount + 1].v_type = VAR_UNKNOWN;
1258
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001259 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001260 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001261}
1262
1263/*
1264 * Return TRUE for a non-zero Number and a non-empty String.
1265 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001266 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001267non_zero_arg(typval_T *argvars)
1268{
1269 return ((argvars[0].v_type == VAR_NUMBER
1270 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001271 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001272 && argvars[0].vval.v_number == VVAL_TRUE)
1273 || (argvars[0].v_type == VAR_STRING
1274 && argvars[0].vval.v_string != NULL
1275 && *argvars[0].vval.v_string != NUL));
1276}
1277
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001278#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001279/*
1280 * Get the float value of "argvars[0]" into "f".
1281 * Returns FAIL when the argument is not a Number or Float.
1282 */
1283 static int
1284get_float_arg(typval_T *argvars, float_T *f)
1285{
1286 if (argvars[0].v_type == VAR_FLOAT)
1287 {
1288 *f = argvars[0].vval.v_float;
1289 return OK;
1290 }
1291 if (argvars[0].v_type == VAR_NUMBER)
1292 {
1293 *f = (float_T)argvars[0].vval.v_number;
1294 return OK;
1295 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001296 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001297 return FAIL;
1298}
1299
1300/*
1301 * "abs(expr)" function
1302 */
1303 static void
1304f_abs(typval_T *argvars, typval_T *rettv)
1305{
1306 if (argvars[0].v_type == VAR_FLOAT)
1307 {
1308 rettv->v_type = VAR_FLOAT;
1309 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1310 }
1311 else
1312 {
1313 varnumber_T n;
1314 int error = FALSE;
1315
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001316 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001317 if (error)
1318 rettv->vval.v_number = -1;
1319 else if (n > 0)
1320 rettv->vval.v_number = n;
1321 else
1322 rettv->vval.v_number = -n;
1323 }
1324}
1325
1326/*
1327 * "acos()" function
1328 */
1329 static void
1330f_acos(typval_T *argvars, typval_T *rettv)
1331{
1332 float_T f = 0.0;
1333
1334 rettv->v_type = VAR_FLOAT;
1335 if (get_float_arg(argvars, &f) == OK)
1336 rettv->vval.v_float = acos(f);
1337 else
1338 rettv->vval.v_float = 0.0;
1339}
1340#endif
1341
1342/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343 * "and(expr, expr)" function
1344 */
1345 static void
1346f_and(typval_T *argvars, typval_T *rettv)
1347{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001348 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1349 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001350}
1351
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001352#ifdef FEAT_FLOAT
1353/*
1354 * "asin()" function
1355 */
1356 static void
1357f_asin(typval_T *argvars, typval_T *rettv)
1358{
1359 float_T f = 0.0;
1360
1361 rettv->v_type = VAR_FLOAT;
1362 if (get_float_arg(argvars, &f) == OK)
1363 rettv->vval.v_float = asin(f);
1364 else
1365 rettv->vval.v_float = 0.0;
1366}
1367
1368/*
1369 * "atan()" function
1370 */
1371 static void
1372f_atan(typval_T *argvars, typval_T *rettv)
1373{
1374 float_T f = 0.0;
1375
1376 rettv->v_type = VAR_FLOAT;
1377 if (get_float_arg(argvars, &f) == OK)
1378 rettv->vval.v_float = atan(f);
1379 else
1380 rettv->vval.v_float = 0.0;
1381}
1382
1383/*
1384 * "atan2()" function
1385 */
1386 static void
1387f_atan2(typval_T *argvars, typval_T *rettv)
1388{
1389 float_T fx = 0.0, fy = 0.0;
1390
1391 rettv->v_type = VAR_FLOAT;
1392 if (get_float_arg(argvars, &fx) == OK
1393 && get_float_arg(&argvars[1], &fy) == OK)
1394 rettv->vval.v_float = atan2(fx, fy);
1395 else
1396 rettv->vval.v_float = 0.0;
1397}
1398#endif
1399
1400/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001401 * "balloon_show()" function
1402 */
1403#ifdef FEAT_BEVAL
1404 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001405f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1406{
1407 rettv->v_type = VAR_STRING;
1408 if (balloonEval != NULL)
1409 {
1410 if (balloonEval->msg == NULL)
1411 rettv->vval.v_string = NULL;
1412 else
1413 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1414 }
1415}
1416
1417 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001418f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1419{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001420 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001421 {
1422 if (argvars[0].v_type == VAR_LIST
1423# ifdef FEAT_GUI
1424 && !gui.in_use
1425# endif
1426 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001427 {
1428 list_T *l = argvars[0].vval.v_list;
1429
1430 // empty list removes the balloon
1431 post_balloon(balloonEval, NULL,
1432 l == NULL || l->lv_len == 0 ? NULL : l);
1433 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001434 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001435 {
1436 char_u *mesg = tv_get_string_chk(&argvars[0]);
1437
1438 if (mesg != NULL)
1439 // empty string removes the balloon
1440 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1441 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001442 }
1443}
1444
Bram Moolenaar669a8282017-11-19 20:13:05 +01001445# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001446 static void
1447f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1448{
1449 if (rettv_list_alloc(rettv) == OK)
1450 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001451 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001452
1453 if (msg != NULL)
1454 {
1455 pumitem_T *array;
1456 int size = split_message(msg, &array);
1457 int i;
1458
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001459 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001460 for (i = 1; i < size - 1; ++i)
1461 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001462 while (size > 0)
1463 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001464 vim_free(array);
1465 }
1466 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001467}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001468# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001469#endif
1470
1471/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001472 * Get the buffer from "arg" and give an error and return NULL if it is not
1473 * valid.
1474 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001475 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001476get_buf_arg(typval_T *arg)
1477{
1478 buf_T *buf;
1479
1480 ++emsg_off;
1481 buf = tv_get_buf(arg, FALSE);
1482 --emsg_off;
1483 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001484 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001485 return buf;
1486}
1487
1488/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001489 * "byte2line(byte)" function
1490 */
1491 static void
1492f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1493{
1494#ifndef FEAT_BYTEOFF
1495 rettv->vval.v_number = -1;
1496#else
1497 long boff = 0;
1498
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001499 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001500 if (boff < 0)
1501 rettv->vval.v_number = -1;
1502 else
1503 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1504 (linenr_T)0, &boff);
1505#endif
1506}
1507
1508 static void
1509byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1510{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001511 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512 char_u *str;
1513 varnumber_T idx;
1514
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001515 str = tv_get_string_chk(&argvars[0]);
1516 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001517 rettv->vval.v_number = -1;
1518 if (str == NULL || idx < 0)
1519 return;
1520
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001521 t = str;
1522 for ( ; idx > 0; idx--)
1523 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001524 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001525 return;
1526 if (enc_utf8 && comp)
1527 t += utf_ptr2len(t);
1528 else
1529 t += (*mb_ptr2len)(t);
1530 }
1531 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001532}
1533
1534/*
1535 * "byteidx()" function
1536 */
1537 static void
1538f_byteidx(typval_T *argvars, typval_T *rettv)
1539{
1540 byteidx(argvars, rettv, FALSE);
1541}
1542
1543/*
1544 * "byteidxcomp()" function
1545 */
1546 static void
1547f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1548{
1549 byteidx(argvars, rettv, TRUE);
1550}
1551
1552/*
1553 * "call(func, arglist [, dict])" function
1554 */
1555 static void
1556f_call(typval_T *argvars, typval_T *rettv)
1557{
1558 char_u *func;
1559 partial_T *partial = NULL;
1560 dict_T *selfdict = NULL;
1561
1562 if (argvars[1].v_type != VAR_LIST)
1563 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001564 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001565 return;
1566 }
1567 if (argvars[1].vval.v_list == NULL)
1568 return;
1569
1570 if (argvars[0].v_type == VAR_FUNC)
1571 func = argvars[0].vval.v_string;
1572 else if (argvars[0].v_type == VAR_PARTIAL)
1573 {
1574 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001575 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 }
1577 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001578 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001579 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001580 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001581
1582 if (argvars[2].v_type != VAR_UNKNOWN)
1583 {
1584 if (argvars[2].v_type != VAR_DICT)
1585 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001586 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001587 return;
1588 }
1589 selfdict = argvars[2].vval.v_dict;
1590 }
1591
1592 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1593}
1594
1595#ifdef FEAT_FLOAT
1596/*
1597 * "ceil({float})" function
1598 */
1599 static void
1600f_ceil(typval_T *argvars, typval_T *rettv)
1601{
1602 float_T f = 0.0;
1603
1604 rettv->v_type = VAR_FLOAT;
1605 if (get_float_arg(argvars, &f) == OK)
1606 rettv->vval.v_float = ceil(f);
1607 else
1608 rettv->vval.v_float = 0.0;
1609}
1610#endif
1611
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001612/*
1613 * "changenr()" function
1614 */
1615 static void
1616f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1617{
1618 rettv->vval.v_number = curbuf->b_u_seq_cur;
1619}
1620
1621/*
1622 * "char2nr(string)" function
1623 */
1624 static void
1625f_char2nr(typval_T *argvars, typval_T *rettv)
1626{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627 if (has_mbyte)
1628 {
1629 int utf8 = 0;
1630
1631 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001632 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001633
1634 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001635 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001636 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001637 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001638 }
1639 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001640 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001641}
1642
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001643 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001644get_optional_window(typval_T *argvars, int idx)
1645{
1646 win_T *win = curwin;
1647
1648 if (argvars[idx].v_type != VAR_UNKNOWN)
1649 {
1650 win = find_win_by_nr_or_id(&argvars[idx]);
1651 if (win == NULL)
1652 {
1653 emsg(_(e_invalwindow));
1654 return NULL;
1655 }
1656 }
1657 return win;
1658}
1659
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001660/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661 * "col(string)" function
1662 */
1663 static void
1664f_col(typval_T *argvars, typval_T *rettv)
1665{
1666 colnr_T col = 0;
1667 pos_T *fp;
1668 int fnum = curbuf->b_fnum;
1669
1670 fp = var2fpos(&argvars[0], FALSE, &fnum);
1671 if (fp != NULL && fnum == curbuf->b_fnum)
1672 {
1673 if (fp->col == MAXCOL)
1674 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001675 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001676 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1677 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1678 else
1679 col = MAXCOL;
1680 }
1681 else
1682 {
1683 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001684 // col(".") when the cursor is on the NUL at the end of the line
1685 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 if (virtual_active() && fp == &curwin->w_cursor)
1687 {
1688 char_u *p = ml_get_cursor();
1689
1690 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1691 curwin->w_virtcol - curwin->w_cursor.coladd))
1692 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693 int l;
1694
1695 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1696 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697 }
1698 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001699 }
1700 }
1701 rettv->vval.v_number = col;
1702}
1703
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001704/*
1705 * "confirm(message, buttons[, default [, type]])" function
1706 */
1707 static void
1708f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1709{
1710#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1711 char_u *message;
1712 char_u *buttons = NULL;
1713 char_u buf[NUMBUFLEN];
1714 char_u buf2[NUMBUFLEN];
1715 int def = 1;
1716 int type = VIM_GENERIC;
1717 char_u *typestr;
1718 int error = FALSE;
1719
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001720 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001721 if (message == NULL)
1722 error = TRUE;
1723 if (argvars[1].v_type != VAR_UNKNOWN)
1724 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001725 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001726 if (buttons == NULL)
1727 error = TRUE;
1728 if (argvars[2].v_type != VAR_UNKNOWN)
1729 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001730 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001731 if (argvars[3].v_type != VAR_UNKNOWN)
1732 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001733 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001734 if (typestr == NULL)
1735 error = TRUE;
1736 else
1737 {
1738 switch (TOUPPER_ASC(*typestr))
1739 {
1740 case 'E': type = VIM_ERROR; break;
1741 case 'Q': type = VIM_QUESTION; break;
1742 case 'I': type = VIM_INFO; break;
1743 case 'W': type = VIM_WARNING; break;
1744 case 'G': type = VIM_GENERIC; break;
1745 }
1746 }
1747 }
1748 }
1749 }
1750
1751 if (buttons == NULL || *buttons == NUL)
1752 buttons = (char_u *)_("&Ok");
1753
1754 if (!error)
1755 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1756 def, NULL, FALSE);
1757#endif
1758}
1759
1760/*
1761 * "copy()" function
1762 */
1763 static void
1764f_copy(typval_T *argvars, typval_T *rettv)
1765{
1766 item_copy(&argvars[0], rettv, FALSE, 0);
1767}
1768
1769#ifdef FEAT_FLOAT
1770/*
1771 * "cos()" function
1772 */
1773 static void
1774f_cos(typval_T *argvars, typval_T *rettv)
1775{
1776 float_T f = 0.0;
1777
1778 rettv->v_type = VAR_FLOAT;
1779 if (get_float_arg(argvars, &f) == OK)
1780 rettv->vval.v_float = cos(f);
1781 else
1782 rettv->vval.v_float = 0.0;
1783}
1784
1785/*
1786 * "cosh()" function
1787 */
1788 static void
1789f_cosh(typval_T *argvars, typval_T *rettv)
1790{
1791 float_T f = 0.0;
1792
1793 rettv->v_type = VAR_FLOAT;
1794 if (get_float_arg(argvars, &f) == OK)
1795 rettv->vval.v_float = cosh(f);
1796 else
1797 rettv->vval.v_float = 0.0;
1798}
1799#endif
1800
1801/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001802 * "cursor(lnum, col)" function, or
1803 * "cursor(list)"
1804 *
1805 * Moves the cursor to the specified line and column.
1806 * Returns 0 when the position could be set, -1 otherwise.
1807 */
1808 static void
1809f_cursor(typval_T *argvars, typval_T *rettv)
1810{
1811 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001812 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 int set_curswant = TRUE;
1814
1815 rettv->vval.v_number = -1;
1816 if (argvars[1].v_type == VAR_UNKNOWN)
1817 {
1818 pos_T pos;
1819 colnr_T curswant = -1;
1820
1821 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1822 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001823 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001824 return;
1825 }
1826 line = pos.lnum;
1827 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001829 if (curswant >= 0)
1830 {
1831 curwin->w_curswant = curswant - 1;
1832 set_curswant = FALSE;
1833 }
1834 }
1835 else
1836 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001837 line = tv_get_lnum(argvars);
1838 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001840 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001841 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001842 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001843 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844 if (line > 0)
1845 curwin->w_cursor.lnum = line;
1846 if (col > 0)
1847 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001848 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001849
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001850 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001851 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001852 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001853 if (has_mbyte)
1854 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001855
1856 curwin->w_set_curswant = set_curswant;
1857 rettv->vval.v_number = 0;
1858}
1859
Bram Moolenaar4f974752019-02-17 17:44:42 +01001860#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001861/*
1862 * "debugbreak()" function
1863 */
1864 static void
1865f_debugbreak(typval_T *argvars, typval_T *rettv)
1866{
1867 int pid;
1868
1869 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001870 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001871 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001872 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001873 else
1874 {
1875 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1876
1877 if (hProcess != NULL)
1878 {
1879 DebugBreakProcess(hProcess);
1880 CloseHandle(hProcess);
1881 rettv->vval.v_number = OK;
1882 }
1883 }
1884}
1885#endif
1886
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001887/*
1888 * "deepcopy()" function
1889 */
1890 static void
1891f_deepcopy(typval_T *argvars, typval_T *rettv)
1892{
1893 int noref = 0;
1894 int copyID;
1895
1896 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001897 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001898 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001899 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900 else
1901 {
1902 copyID = get_copyID();
1903 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1904 }
1905}
1906
1907/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908 * "did_filetype()" function
1909 */
1910 static void
1911f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1912{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001913 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001914}
1915
1916/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001917 * "echoraw({expr})" function
1918 */
1919 static void
1920f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1921{
1922 char_u *str = tv_get_string_chk(&argvars[0]);
1923
1924 if (str != NULL && *str != NUL)
1925 {
1926 out_str(str);
1927 out_flush();
1928 }
1929}
1930
1931/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001932 * "empty({expr})" function
1933 */
1934 static void
1935f_empty(typval_T *argvars, typval_T *rettv)
1936{
1937 int n = FALSE;
1938
1939 switch (argvars[0].v_type)
1940 {
1941 case VAR_STRING:
1942 case VAR_FUNC:
1943 n = argvars[0].vval.v_string == NULL
1944 || *argvars[0].vval.v_string == NUL;
1945 break;
1946 case VAR_PARTIAL:
1947 n = FALSE;
1948 break;
1949 case VAR_NUMBER:
1950 n = argvars[0].vval.v_number == 0;
1951 break;
1952 case VAR_FLOAT:
1953#ifdef FEAT_FLOAT
1954 n = argvars[0].vval.v_float == 0.0;
1955 break;
1956#endif
1957 case VAR_LIST:
1958 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001959 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001960 break;
1961 case VAR_DICT:
1962 n = argvars[0].vval.v_dict == NULL
1963 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1964 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001965 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001966 case VAR_SPECIAL:
1967 n = argvars[0].vval.v_number != VVAL_TRUE;
1968 break;
1969
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001970 case VAR_BLOB:
1971 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001972 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1973 break;
1974
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001975 case VAR_JOB:
1976#ifdef FEAT_JOB_CHANNEL
1977 n = argvars[0].vval.v_job == NULL
1978 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1979 break;
1980#endif
1981 case VAR_CHANNEL:
1982#ifdef FEAT_JOB_CHANNEL
1983 n = argvars[0].vval.v_channel == NULL
1984 || !channel_is_open(argvars[0].vval.v_channel);
1985 break;
1986#endif
1987 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02001988 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001989 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001990 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991 n = TRUE;
1992 break;
1993 }
1994
1995 rettv->vval.v_number = n;
1996}
1997
1998/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001999 * "environ()" function
2000 */
2001 static void
2002f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2003{
2004#if !defined(AMIGA)
2005 int i = 0;
2006 char_u *entry, *value;
2007# ifdef MSWIN
2008 extern wchar_t **_wenviron;
2009# else
2010 extern char **environ;
2011# endif
2012
2013 if (rettv_dict_alloc(rettv) != OK)
2014 return;
2015
2016# ifdef MSWIN
2017 if (*_wenviron == NULL)
2018 return;
2019# else
2020 if (*environ == NULL)
2021 return;
2022# endif
2023
2024 for (i = 0; ; ++i)
2025 {
2026# ifdef MSWIN
2027 short_u *p;
2028
2029 if ((p = (short_u *)_wenviron[i]) == NULL)
2030 return;
2031 entry = utf16_to_enc(p, NULL);
2032# else
2033 if ((entry = (char_u *)environ[i]) == NULL)
2034 return;
2035 entry = vim_strsave(entry);
2036# endif
2037 if (entry == NULL) // out of memory
2038 return;
2039 if ((value = vim_strchr(entry, '=')) == NULL)
2040 {
2041 vim_free(entry);
2042 continue;
2043 }
2044 *value++ = NUL;
2045 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2046 vim_free(entry);
2047 }
2048#endif
2049}
2050
2051/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052 * "escape({string}, {chars})" function
2053 */
2054 static void
2055f_escape(typval_T *argvars, typval_T *rettv)
2056{
2057 char_u buf[NUMBUFLEN];
2058
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002059 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2060 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 rettv->v_type = VAR_STRING;
2062}
2063
2064/*
2065 * "eval()" function
2066 */
2067 static void
2068f_eval(typval_T *argvars, typval_T *rettv)
2069{
2070 char_u *s, *p;
2071
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002072 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002073 if (s != NULL)
2074 s = skipwhite(s);
2075
2076 p = s;
Bram Moolenaar32e35112020-05-14 22:41:15 +02002077 if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002078 {
2079 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002080 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002081 need_clr_eos = FALSE;
2082 rettv->v_type = VAR_NUMBER;
2083 rettv->vval.v_number = 0;
2084 }
2085 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002086 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002087}
2088
2089/*
2090 * "eventhandler()" function
2091 */
2092 static void
2093f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2094{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002095 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002096}
2097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098static garray_T redir_execute_ga;
2099
2100/*
2101 * Append "value[value_len]" to the execute() output.
2102 */
2103 void
2104execute_redir_str(char_u *value, int value_len)
2105{
2106 int len;
2107
2108 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002109 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002110 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002111 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002112 if (ga_grow(&redir_execute_ga, len) == OK)
2113 {
2114 mch_memmove((char *)redir_execute_ga.ga_data
2115 + redir_execute_ga.ga_len, value, len);
2116 redir_execute_ga.ga_len += len;
2117 }
2118}
2119
2120/*
2121 * Get next line from a list.
2122 * Called by do_cmdline() to get the next line.
2123 * Returns allocated string, or NULL for end of function.
2124 */
2125
2126 static char_u *
2127get_list_line(
2128 int c UNUSED,
2129 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002130 int indent UNUSED,
2131 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002132{
2133 listitem_T **p = (listitem_T **)cookie;
2134 listitem_T *item = *p;
2135 char_u buf[NUMBUFLEN];
2136 char_u *s;
2137
2138 if (item == NULL)
2139 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002140 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002141 *p = item->li_next;
2142 return s == NULL ? NULL : vim_strsave(s);
2143}
2144
2145/*
2146 * "execute()" function
2147 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002148 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002149execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002150{
2151 char_u *cmd = NULL;
2152 list_T *list = NULL;
2153 int save_msg_silent = msg_silent;
2154 int save_emsg_silent = emsg_silent;
2155 int save_emsg_noredir = emsg_noredir;
2156 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002157 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002159 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002160 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161
2162 rettv->vval.v_string = NULL;
2163 rettv->v_type = VAR_STRING;
2164
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002165 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002167 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002168 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002169 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002170 return;
2171 ++list->lv_refcount;
2172 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002173 else if (argvars[arg_off].v_type == VAR_JOB
2174 || argvars[arg_off].v_type == VAR_CHANNEL)
2175 {
2176 emsg(_(e_inval_string));
2177 return;
2178 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002179 else
2180 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002181 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182 if (cmd == NULL)
2183 return;
2184 }
2185
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002186 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002187 {
2188 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002189 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002190
2191 if (s == NULL)
2192 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002193 if (*s == NUL)
2194 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002195 if (STRNCMP(s, "silent", 6) == 0)
2196 ++msg_silent;
2197 if (STRCMP(s, "silent!") == 0)
2198 {
2199 emsg_silent = TRUE;
2200 emsg_noredir = TRUE;
2201 }
2202 }
2203 else
2204 ++msg_silent;
2205
2206 if (redir_execute)
2207 save_ga = redir_execute_ga;
2208 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2209 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002210 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002211 if (!echo_output)
2212 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002213
2214 if (cmd != NULL)
2215 do_cmdline_cmd(cmd);
2216 else
2217 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002218 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002219
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002220 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002221 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002222 do_cmdline(NULL, get_list_line, (void *)&item,
2223 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2224 --list->lv_refcount;
2225 }
2226
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002227 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002228 if (ga_grow(&redir_execute_ga, 1) == OK)
2229 {
2230 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2231 rettv->vval.v_string = redir_execute_ga.ga_data;
2232 }
2233 else
2234 {
2235 ga_clear(&redir_execute_ga);
2236 rettv->vval.v_string = NULL;
2237 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002238 msg_silent = save_msg_silent;
2239 emsg_silent = save_emsg_silent;
2240 emsg_noredir = save_emsg_noredir;
2241
2242 redir_execute = save_redir_execute;
2243 if (redir_execute)
2244 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002245 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002246
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002247 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002248 if (echo_output)
2249 // When not working silently: put it in column zero. A following
2250 // "echon" will overwrite the message, unavoidably.
2251 msg_col = 0;
2252 else
2253 // When working silently: Put it back where it was, since nothing
2254 // should have been written.
2255 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256}
2257
2258/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002259 * "execute()" function
2260 */
2261 static void
2262f_execute(typval_T *argvars, typval_T *rettv)
2263{
2264 execute_common(argvars, rettv, 0);
2265}
2266
2267/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 * "exists()" function
2269 */
2270 static void
2271f_exists(typval_T *argvars, typval_T *rettv)
2272{
2273 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002274 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002276 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002277 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002278 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002279 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 if (mch_getenv(p + 1) != NULL)
2281 n = TRUE;
2282 else
2283 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002284 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002285 p = expand_env_save(p);
2286 if (p != NULL && *p != '$')
2287 n = TRUE;
2288 vim_free(p);
2289 }
2290 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002291 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 {
2293 n = (get_option_tv(&p, NULL, TRUE) == OK);
2294 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002295 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002297 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002298 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002299 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002300 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002301 else if (*p == '?') // internal function only
2302 {
2303 n = has_internal_func_name(p + 1);
2304 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002305 else if (*p == ':')
2306 {
2307 n = cmd_exists(p + 1);
2308 }
2309 else if (*p == '#')
2310 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002311 if (p[1] == '#')
2312 n = autocmd_supported(p + 2);
2313 else
2314 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002315 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002316 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002317 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002318 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002319 }
2320
2321 rettv->vval.v_number = n;
2322}
2323
2324#ifdef FEAT_FLOAT
2325/*
2326 * "exp()" function
2327 */
2328 static void
2329f_exp(typval_T *argvars, typval_T *rettv)
2330{
2331 float_T f = 0.0;
2332
2333 rettv->v_type = VAR_FLOAT;
2334 if (get_float_arg(argvars, &f) == OK)
2335 rettv->vval.v_float = exp(f);
2336 else
2337 rettv->vval.v_float = 0.0;
2338}
2339#endif
2340
2341/*
2342 * "expand()" function
2343 */
2344 static void
2345f_expand(typval_T *argvars, typval_T *rettv)
2346{
2347 char_u *s;
2348 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002349 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002350 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2351 expand_T xpc;
2352 int error = FALSE;
2353 char_u *result;
2354
2355 rettv->v_type = VAR_STRING;
2356 if (argvars[1].v_type != VAR_UNKNOWN
2357 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002358 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002360 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002361
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002362 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002363 if (*s == '%' || *s == '#' || *s == '<')
2364 {
2365 ++emsg_off;
2366 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2367 --emsg_off;
2368 if (rettv->v_type == VAR_LIST)
2369 {
2370 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2371 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002372 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002373 }
2374 else
2375 rettv->vval.v_string = result;
2376 }
2377 else
2378 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002379 // When the optional second argument is non-zero, don't remove matches
2380 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002381 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002382 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002383 options |= WILD_KEEP_ALL;
2384 if (!error)
2385 {
2386 ExpandInit(&xpc);
2387 xpc.xp_context = EXPAND_FILES;
2388 if (p_wic)
2389 options += WILD_ICASE;
2390 if (rettv->v_type == VAR_STRING)
2391 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2392 options, WILD_ALL);
2393 else if (rettv_list_alloc(rettv) != FAIL)
2394 {
2395 int i;
2396
2397 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2398 for (i = 0; i < xpc.xp_numfiles; i++)
2399 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2400 ExpandCleanup(&xpc);
2401 }
2402 }
2403 else
2404 rettv->vval.v_string = NULL;
2405 }
2406}
2407
2408/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002409 * "expandcmd()" function
2410 * Expand all the special characters in a command string.
2411 */
2412 static void
2413f_expandcmd(typval_T *argvars, typval_T *rettv)
2414{
2415 exarg_T eap;
2416 char_u *cmdstr;
2417 char *errormsg = NULL;
2418
2419 rettv->v_type = VAR_STRING;
2420 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2421
2422 memset(&eap, 0, sizeof(eap));
2423 eap.cmd = cmdstr;
2424 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002425 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002426 eap.usefilter = FALSE;
2427 eap.nextcmd = NULL;
2428 eap.cmdidx = CMD_USER;
2429
2430 expand_filename(&eap, &cmdstr, &errormsg);
2431 if (errormsg != NULL && *errormsg != NUL)
2432 emsg(errormsg);
2433
2434 rettv->vval.v_string = cmdstr;
2435}
2436
2437/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002438 * "feedkeys()" function
2439 */
2440 static void
2441f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2442{
2443 int remap = TRUE;
2444 int insert = FALSE;
2445 char_u *keys, *flags;
2446 char_u nbuf[NUMBUFLEN];
2447 int typed = FALSE;
2448 int execute = FALSE;
2449 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002450 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451 char_u *keys_esc;
2452
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002453 // This is not allowed in the sandbox. If the commands would still be
2454 // executed in the sandbox it would be OK, but it probably happens later,
2455 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002456 if (check_secure())
2457 return;
2458
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002459 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460
2461 if (argvars[1].v_type != VAR_UNKNOWN)
2462 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002463 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002464 for ( ; *flags != NUL; ++flags)
2465 {
2466 switch (*flags)
2467 {
2468 case 'n': remap = FALSE; break;
2469 case 'm': remap = TRUE; break;
2470 case 't': typed = TRUE; break;
2471 case 'i': insert = TRUE; break;
2472 case 'x': execute = TRUE; break;
2473 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002474 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002475 }
2476 }
2477 }
2478
2479 if (*keys != NUL || execute)
2480 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002481 // Need to escape K_SPECIAL and CSI before putting the string in the
2482 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002483 keys_esc = vim_strsave_escape_csi(keys);
2484 if (keys_esc != NULL)
2485 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002486 if (lowlevel)
2487 {
2488#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002489 int idx;
2490 int len = (int)STRLEN(keys);
2491
2492 for (idx = 0; idx < len; ++idx)
2493 {
2494 // if a CTRL-C was typed, set got_int, similar to what
2495 // happens in fill_input_buf()
2496 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2497 got_int = TRUE;
2498 add_to_input_buf(keys + idx, 1);
2499 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002500#else
2501 emsg(_("E980: lowlevel input not supported"));
2502#endif
2503 }
2504 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002505 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002506 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002507 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002508 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002509#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002510 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002511#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002512 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002513 typebuf_was_filled = TRUE;
2514 }
2515 vim_free(keys_esc);
2516
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517 if (execute)
2518 {
2519 int save_msg_scroll = msg_scroll;
2520
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002521 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002522 msg_scroll = FALSE;
2523
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002524 if (!dangerous)
2525 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002526 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002527 if (!dangerous)
2528 --ex_normal_busy;
2529
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002530 msg_scroll |= save_msg_scroll;
2531 }
2532 }
2533 }
2534}
2535
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002536#ifdef FEAT_FLOAT
2537/*
2538 * "float2nr({float})" function
2539 */
2540 static void
2541f_float2nr(typval_T *argvars, typval_T *rettv)
2542{
2543 float_T f = 0.0;
2544
2545 if (get_float_arg(argvars, &f) == OK)
2546 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002547 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002548 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002549 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002550 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002551 else
2552 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002553 }
2554}
2555
2556/*
2557 * "floor({float})" function
2558 */
2559 static void
2560f_floor(typval_T *argvars, typval_T *rettv)
2561{
2562 float_T f = 0.0;
2563
2564 rettv->v_type = VAR_FLOAT;
2565 if (get_float_arg(argvars, &f) == OK)
2566 rettv->vval.v_float = floor(f);
2567 else
2568 rettv->vval.v_float = 0.0;
2569}
2570
2571/*
2572 * "fmod()" function
2573 */
2574 static void
2575f_fmod(typval_T *argvars, typval_T *rettv)
2576{
2577 float_T fx = 0.0, fy = 0.0;
2578
2579 rettv->v_type = VAR_FLOAT;
2580 if (get_float_arg(argvars, &fx) == OK
2581 && get_float_arg(&argvars[1], &fy) == OK)
2582 rettv->vval.v_float = fmod(fx, fy);
2583 else
2584 rettv->vval.v_float = 0.0;
2585}
2586#endif
2587
2588/*
2589 * "fnameescape({string})" function
2590 */
2591 static void
2592f_fnameescape(typval_T *argvars, typval_T *rettv)
2593{
2594 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002595 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002596 rettv->v_type = VAR_STRING;
2597}
2598
2599/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002600 * "foreground()" function
2601 */
2602 static void
2603f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2604{
2605#ifdef FEAT_GUI
2606 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002607 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002608 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002609 return;
2610 }
2611#endif
2612#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002613 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614#endif
2615}
2616
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002617 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002618common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002619{
2620 char_u *s;
2621 char_u *name;
2622 int use_string = FALSE;
2623 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002624 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002625 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002626
2627 if (argvars[0].v_type == VAR_FUNC)
2628 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002629 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002630 s = argvars[0].vval.v_string;
2631 }
2632 else if (argvars[0].v_type == VAR_PARTIAL
2633 && argvars[0].vval.v_partial != NULL)
2634 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002635 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002636 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002637 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002638 }
2639 else
2640 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002641 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002642 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002643 use_string = TRUE;
2644 }
2645
Bram Moolenaar843b8842016-08-21 14:36:15 +02002646 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002647 {
2648 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002649 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002650 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2651 if (*name != NUL)
2652 s = NULL;
2653 }
2654
Bram Moolenaar843b8842016-08-21 14:36:15 +02002655 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2656 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002657 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002658 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002659 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002660 ? find_func(trans_name, is_global, NULL) == NULL
2661 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002662 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663 else
2664 {
2665 int dict_idx = 0;
2666 int arg_idx = 0;
2667 list_T *list = NULL;
2668
2669 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2670 {
2671 char sid_buf[25];
2672 int off = *s == 's' ? 2 : 5;
2673
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002674 // Expand s: and <SID> into <SNR>nr_, so that the function can
2675 // also be called from another script. Using trans_function_name()
2676 // would also work, but some plugins depend on the name being
2677 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002678 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002679 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002680 if (name != NULL)
2681 {
2682 STRCPY(name, sid_buf);
2683 STRCAT(name, s + off);
2684 }
2685 }
2686 else
2687 name = vim_strsave(s);
2688
2689 if (argvars[1].v_type != VAR_UNKNOWN)
2690 {
2691 if (argvars[2].v_type != VAR_UNKNOWN)
2692 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002693 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694 arg_idx = 1;
2695 dict_idx = 2;
2696 }
2697 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002698 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699 dict_idx = 1;
2700 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002701 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002702 arg_idx = 1;
2703 if (dict_idx > 0)
2704 {
2705 if (argvars[dict_idx].v_type != VAR_DICT)
2706 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002707 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002708 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002709 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002710 }
2711 if (argvars[dict_idx].vval.v_dict == NULL)
2712 dict_idx = 0;
2713 }
2714 if (arg_idx > 0)
2715 {
2716 if (argvars[arg_idx].v_type != VAR_LIST)
2717 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002718 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002720 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002721 }
2722 list = argvars[arg_idx].vval.v_list;
2723 if (list == NULL || list->lv_len == 0)
2724 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002725 else if (list->lv_len > MAX_FUNC_ARGS)
2726 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002727 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002728 vim_free(name);
2729 goto theend;
2730 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002731 }
2732 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002733 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002734 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002735 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002736
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002737 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002738 if (pt == NULL)
2739 vim_free(name);
2740 else
2741 {
2742 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2743 {
2744 listitem_T *li;
2745 int i = 0;
2746 int arg_len = 0;
2747 int lv_len = 0;
2748
2749 if (arg_pt != NULL)
2750 arg_len = arg_pt->pt_argc;
2751 if (list != NULL)
2752 lv_len = list->lv_len;
2753 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002754 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002755 if (pt->pt_argv == NULL)
2756 {
2757 vim_free(pt);
2758 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002759 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002760 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002761 for (i = 0; i < arg_len; i++)
2762 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2763 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002764 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002765 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002766 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002767 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002768 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002769 }
2770
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002771 // For "function(dict.func, [], dict)" and "func" is a partial
2772 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002773 if (dict_idx > 0)
2774 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002775 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002776 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2777 ++pt->pt_dict->dv_refcount;
2778 }
2779 else if (arg_pt != NULL)
2780 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002781 // If the dict was bound automatically the result is also
2782 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783 pt->pt_dict = arg_pt->pt_dict;
2784 pt->pt_auto = arg_pt->pt_auto;
2785 if (pt->pt_dict != NULL)
2786 ++pt->pt_dict->dv_refcount;
2787 }
2788
2789 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002790 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2791 {
2792 pt->pt_func = arg_pt->pt_func;
2793 func_ptr_ref(pt->pt_func);
2794 vim_free(name);
2795 }
2796 else if (is_funcref)
2797 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002798 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002799 func_ptr_ref(pt->pt_func);
2800 vim_free(name);
2801 }
2802 else
2803 {
2804 pt->pt_name = name;
2805 func_ref(name);
2806 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002807 }
2808 rettv->v_type = VAR_PARTIAL;
2809 rettv->vval.v_partial = pt;
2810 }
2811 else
2812 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002813 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002814 rettv->v_type = VAR_FUNC;
2815 rettv->vval.v_string = name;
2816 func_ref(name);
2817 }
2818 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002819theend:
2820 vim_free(trans_name);
2821}
2822
2823/*
2824 * "funcref()" function
2825 */
2826 static void
2827f_funcref(typval_T *argvars, typval_T *rettv)
2828{
2829 common_function(argvars, rettv, TRUE);
2830}
2831
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002832 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002833ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002834{
2835 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2836 return &t_func_any;
Bram Moolenaard77a8522020-04-03 21:59:57 +02002837 return &t_func_void;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002838}
2839
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002840/*
2841 * "function()" function
2842 */
2843 static void
2844f_function(typval_T *argvars, typval_T *rettv)
2845{
2846 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002847}
2848
2849/*
2850 * "garbagecollect()" function
2851 */
2852 static void
2853f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2854{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002855 // This is postponed until we are back at the toplevel, because we may be
2856 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002857 want_garbage_collect = TRUE;
2858
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002859 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860 garbage_collect_at_exit = TRUE;
2861}
2862
2863/*
2864 * "get()" function
2865 */
2866 static void
2867f_get(typval_T *argvars, typval_T *rettv)
2868{
2869 listitem_T *li;
2870 list_T *l;
2871 dictitem_T *di;
2872 dict_T *d;
2873 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002874 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002875
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002876 if (argvars[0].v_type == VAR_BLOB)
2877 {
2878 int error = FALSE;
2879 int idx = tv_get_number_chk(&argvars[1], &error);
2880
2881 if (!error)
2882 {
2883 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002884 if (idx < 0)
2885 idx = blob_len(argvars[0].vval.v_blob) + idx;
2886 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2887 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002888 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002889 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002890 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002891 tv = rettv;
2892 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002893 }
2894 }
2895 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002896 {
2897 if ((l = argvars[0].vval.v_list) != NULL)
2898 {
2899 int error = FALSE;
2900
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002901 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002902 if (!error && li != NULL)
2903 tv = &li->li_tv;
2904 }
2905 }
2906 else if (argvars[0].v_type == VAR_DICT)
2907 {
2908 if ((d = argvars[0].vval.v_dict) != NULL)
2909 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002910 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002911 if (di != NULL)
2912 tv = &di->di_tv;
2913 }
2914 }
2915 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2916 {
2917 partial_T *pt;
2918 partial_T fref_pt;
2919
2920 if (argvars[0].v_type == VAR_PARTIAL)
2921 pt = argvars[0].vval.v_partial;
2922 else
2923 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02002924 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002925 fref_pt.pt_name = argvars[0].vval.v_string;
2926 pt = &fref_pt;
2927 }
2928
2929 if (pt != NULL)
2930 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002931 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002932 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933
2934 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2935 {
2936 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002937 n = partial_name(pt);
2938 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002939 rettv->vval.v_string = NULL;
2940 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002941 {
2942 rettv->vval.v_string = vim_strsave(n);
2943 if (rettv->v_type == VAR_FUNC)
2944 func_ref(rettv->vval.v_string);
2945 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002946 }
2947 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002948 {
2949 what_is_dict = TRUE;
2950 if (pt->pt_dict != NULL)
2951 rettv_dict_set(rettv, pt->pt_dict);
2952 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002953 else if (STRCMP(what, "args") == 0)
2954 {
2955 rettv->v_type = VAR_LIST;
2956 if (rettv_list_alloc(rettv) == OK)
2957 {
2958 int i;
2959
2960 for (i = 0; i < pt->pt_argc; ++i)
2961 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2962 }
2963 }
2964 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002965 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002966
2967 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2968 // third argument
2969 if (!what_is_dict)
2970 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002971 }
2972 }
2973 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002974 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975
2976 if (tv == NULL)
2977 {
2978 if (argvars[2].v_type != VAR_UNKNOWN)
2979 copy_tv(&argvars[2], rettv);
2980 }
2981 else
2982 copy_tv(tv, rettv);
2983}
2984
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002985/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002986 * "getchangelist()" function
2987 */
2988 static void
2989f_getchangelist(typval_T *argvars, typval_T *rettv)
2990{
2991#ifdef FEAT_JUMPLIST
2992 buf_T *buf;
2993 int i;
2994 list_T *l;
2995 dict_T *d;
2996#endif
2997
2998 if (rettv_list_alloc(rettv) != OK)
2999 return;
3000
3001#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003002 if (argvars[0].v_type == VAR_UNKNOWN)
3003 buf = curbuf;
3004 else
3005 {
3006 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3007 ++emsg_off;
3008 buf = tv_get_buf(&argvars[0], FALSE);
3009 --emsg_off;
3010 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003011 if (buf == NULL)
3012 return;
3013
3014 l = list_alloc();
3015 if (l == NULL)
3016 return;
3017
3018 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3019 return;
3020 /*
3021 * The current window change list index tracks only the position in the
3022 * current buffer change list. For other buffers, use the change list
3023 * length as the current index.
3024 */
3025 list_append_number(rettv->vval.v_list,
3026 (varnumber_T)((buf == curwin->w_buffer)
3027 ? curwin->w_changelistidx : buf->b_changelistlen));
3028
3029 for (i = 0; i < buf->b_changelistlen; ++i)
3030 {
3031 if (buf->b_changelist[i].lnum == 0)
3032 continue;
3033 if ((d = dict_alloc()) == NULL)
3034 return;
3035 if (list_append_dict(l, d) == FAIL)
3036 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003037 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3038 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003039 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003040 }
3041#endif
3042}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003043
3044/*
3045 * "getcharsearch()" function
3046 */
3047 static void
3048f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3049{
3050 if (rettv_dict_alloc(rettv) != FAIL)
3051 {
3052 dict_T *dict = rettv->vval.v_dict;
3053
Bram Moolenaare0be1672018-07-08 16:50:37 +02003054 dict_add_string(dict, "char", last_csearch());
3055 dict_add_number(dict, "forward", last_csearch_forward());
3056 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003057 }
3058}
3059
3060/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003061 * "getenv()" function
3062 */
3063 static void
3064f_getenv(typval_T *argvars, typval_T *rettv)
3065{
3066 int mustfree = FALSE;
3067 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3068
3069 if (p == NULL)
3070 {
3071 rettv->v_type = VAR_SPECIAL;
3072 rettv->vval.v_number = VVAL_NULL;
3073 return;
3074 }
3075 if (!mustfree)
3076 p = vim_strsave(p);
3077 rettv->vval.v_string = p;
3078 rettv->v_type = VAR_STRING;
3079}
3080
3081/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003082 * "getfontname()" function
3083 */
3084 static void
3085f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3086{
3087 rettv->v_type = VAR_STRING;
3088 rettv->vval.v_string = NULL;
3089#ifdef FEAT_GUI
3090 if (gui.in_use)
3091 {
3092 GuiFont font;
3093 char_u *name = NULL;
3094
3095 if (argvars[0].v_type == VAR_UNKNOWN)
3096 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003097 // Get the "Normal" font. Either the name saved by
3098 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 font = gui.norm_font;
3100 name = hl_get_font_name();
3101 }
3102 else
3103 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003104 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003105 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003106 return;
3107 font = gui_mch_get_font(name, FALSE);
3108 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003109 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003110 }
3111 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3112 if (argvars[0].v_type != VAR_UNKNOWN)
3113 gui_mch_free_font(font);
3114 }
3115#endif
3116}
3117
3118/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003119 * "getjumplist()" function
3120 */
3121 static void
3122f_getjumplist(typval_T *argvars, typval_T *rettv)
3123{
3124#ifdef FEAT_JUMPLIST
3125 win_T *wp;
3126 int i;
3127 list_T *l;
3128 dict_T *d;
3129#endif
3130
3131 if (rettv_list_alloc(rettv) != OK)
3132 return;
3133
3134#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003135 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003136 if (wp == NULL)
3137 return;
3138
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003139 cleanup_jumplist(wp, TRUE);
3140
Bram Moolenaar4f505882018-02-10 21:06:32 +01003141 l = list_alloc();
3142 if (l == NULL)
3143 return;
3144
3145 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3146 return;
3147 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3148
3149 for (i = 0; i < wp->w_jumplistlen; ++i)
3150 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003151 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3152 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003153 if ((d = dict_alloc()) == NULL)
3154 return;
3155 if (list_append_dict(l, d) == FAIL)
3156 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003157 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3158 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003159 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003160 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003161 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003162 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003163 }
3164#endif
3165}
3166
3167/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003168 * "getpid()" function
3169 */
3170 static void
3171f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3172{
3173 rettv->vval.v_number = mch_get_pid();
3174}
3175
3176 static void
3177getpos_both(
3178 typval_T *argvars,
3179 typval_T *rettv,
3180 int getcurpos)
3181{
3182 pos_T *fp;
3183 list_T *l;
3184 int fnum = -1;
3185
3186 if (rettv_list_alloc(rettv) == OK)
3187 {
3188 l = rettv->vval.v_list;
3189 if (getcurpos)
3190 fp = &curwin->w_cursor;
3191 else
3192 fp = var2fpos(&argvars[0], TRUE, &fnum);
3193 if (fnum != -1)
3194 list_append_number(l, (varnumber_T)fnum);
3195 else
3196 list_append_number(l, (varnumber_T)0);
3197 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3198 : (varnumber_T)0);
3199 list_append_number(l, (fp != NULL)
3200 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3201 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003202 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003203 (varnumber_T)0);
3204 if (getcurpos)
3205 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003206 int save_set_curswant = curwin->w_set_curswant;
3207 colnr_T save_curswant = curwin->w_curswant;
3208 colnr_T save_virtcol = curwin->w_virtcol;
3209
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003210 update_curswant();
3211 list_append_number(l, curwin->w_curswant == MAXCOL ?
3212 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003213
3214 // Do not change "curswant", as it is unexpected that a get
3215 // function has a side effect.
3216 if (save_set_curswant)
3217 {
3218 curwin->w_set_curswant = save_set_curswant;
3219 curwin->w_curswant = save_curswant;
3220 curwin->w_virtcol = save_virtcol;
3221 curwin->w_valid &= ~VALID_VIRTCOL;
3222 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003223 }
3224 }
3225 else
3226 rettv->vval.v_number = FALSE;
3227}
3228
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003229/*
3230 * "getcurpos()" function
3231 */
3232 static void
3233f_getcurpos(typval_T *argvars, typval_T *rettv)
3234{
3235 getpos_both(argvars, rettv, TRUE);
3236}
3237
3238/*
3239 * "getpos(string)" function
3240 */
3241 static void
3242f_getpos(typval_T *argvars, typval_T *rettv)
3243{
3244 getpos_both(argvars, rettv, FALSE);
3245}
3246
3247/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003248 * "getreg()" function
3249 */
3250 static void
3251f_getreg(typval_T *argvars, typval_T *rettv)
3252{
3253 char_u *strregname;
3254 int regname;
3255 int arg2 = FALSE;
3256 int return_list = FALSE;
3257 int error = FALSE;
3258
3259 if (argvars[0].v_type != VAR_UNKNOWN)
3260 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003261 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003262 error = strregname == NULL;
3263 if (argvars[1].v_type != VAR_UNKNOWN)
3264 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003265 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003266 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003267 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268 }
3269 }
3270 else
3271 strregname = get_vim_var_str(VV_REG);
3272
3273 if (error)
3274 return;
3275
3276 regname = (strregname == NULL ? '"' : *strregname);
3277 if (regname == 0)
3278 regname = '"';
3279
3280 if (return_list)
3281 {
3282 rettv->v_type = VAR_LIST;
3283 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3284 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3285 if (rettv->vval.v_list == NULL)
3286 (void)rettv_list_alloc(rettv);
3287 else
3288 ++rettv->vval.v_list->lv_refcount;
3289 }
3290 else
3291 {
3292 rettv->v_type = VAR_STRING;
3293 rettv->vval.v_string = get_reg_contents(regname,
3294 arg2 ? GREG_EXPR_SRC : 0);
3295 }
3296}
3297
3298/*
3299 * "getregtype()" function
3300 */
3301 static void
3302f_getregtype(typval_T *argvars, typval_T *rettv)
3303{
3304 char_u *strregname;
3305 int regname;
3306 char_u buf[NUMBUFLEN + 2];
3307 long reglen = 0;
3308
3309 if (argvars[0].v_type != VAR_UNKNOWN)
3310 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003311 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003312 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003313 {
3314 rettv->v_type = VAR_STRING;
3315 rettv->vval.v_string = NULL;
3316 return;
3317 }
3318 }
3319 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003320 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321 strregname = get_vim_var_str(VV_REG);
3322
3323 regname = (strregname == NULL ? '"' : *strregname);
3324 if (regname == 0)
3325 regname = '"';
3326
3327 buf[0] = NUL;
3328 buf[1] = NUL;
3329 switch (get_reg_type(regname, &reglen))
3330 {
3331 case MLINE: buf[0] = 'V'; break;
3332 case MCHAR: buf[0] = 'v'; break;
3333 case MBLOCK:
3334 buf[0] = Ctrl_V;
3335 sprintf((char *)buf + 1, "%ld", reglen + 1);
3336 break;
3337 }
3338 rettv->v_type = VAR_STRING;
3339 rettv->vval.v_string = vim_strsave(buf);
3340}
3341
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003342/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003343 * "gettagstack()" function
3344 */
3345 static void
3346f_gettagstack(typval_T *argvars, typval_T *rettv)
3347{
3348 win_T *wp = curwin; // default is current window
3349
3350 if (rettv_dict_alloc(rettv) != OK)
3351 return;
3352
3353 if (argvars[0].v_type != VAR_UNKNOWN)
3354 {
3355 wp = find_win_by_nr_or_id(&argvars[0]);
3356 if (wp == NULL)
3357 return;
3358 }
3359
3360 get_tagstack(wp, rettv->vval.v_dict);
3361}
3362
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003363// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003364#include "version.h"
3365
3366/*
3367 * "has()" function
3368 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003369 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003370f_has(typval_T *argvars, typval_T *rettv)
3371{
3372 int i;
3373 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003374 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003375 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003376 typedef struct {
3377 char *name;
3378 short present;
3379 } has_item_T;
3380 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003381 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003382 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003383#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003384 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003385#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003386 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003387#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003388 },
3389 {"arp",
3390#if defined(AMIGA) && defined(FEAT_ARP)
3391 1
3392#else
3393 0
3394#endif
3395 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003396 {"haiku",
3397#ifdef __HAIKU__
3398 1
3399#else
3400 0
3401#endif
3402 },
3403 {"bsd",
3404#if defined(BSD) && !defined(MACOS_X)
3405 1
3406#else
3407 0
3408#endif
3409 },
3410 {"hpux",
3411#ifdef hpux
3412 1
3413#else
3414 0
3415#endif
3416 },
3417 {"linux",
3418#ifdef __linux__
3419 1
3420#else
3421 0
3422#endif
3423 },
3424 {"mac", // Mac OS X (and, once, Mac OS Classic)
3425#ifdef MACOS_X
3426 1
3427#else
3428 0
3429#endif
3430 },
3431 {"osx", // Mac OS X
3432#ifdef MACOS_X
3433 1
3434#else
3435 0
3436#endif
3437 },
3438 {"macunix", // Mac OS X, with the darwin feature
3439#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3440 1
3441#else
3442 0
3443#endif
3444 },
3445 {"osxdarwin", // synonym for macunix
3446#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3447 1
3448#else
3449 0
3450#endif
3451 },
3452 {"qnx",
3453#ifdef __QNX__
3454 1
3455#else
3456 0
3457#endif
3458 },
3459 {"sun",
3460#ifdef SUN_SYSTEM
3461 1
3462#else
3463 0
3464#endif
3465 },
3466 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003467#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003468 1
3469#else
3470 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003472 },
3473 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003475 1
3476#else
3477 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003479 },
3480 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003481#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003482 1
3483#else
3484 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003485#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003486 },
3487 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003488#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003489 1
3490#else
3491 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003493 },
3494 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003495#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003496 1
3497#else
3498 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003499#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003500 },
3501 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003502#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003503 1
3504#else
3505 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003507 },
3508 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003509#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003510 1
3511#else
3512 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003513#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003514 },
3515 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003516#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003517 1
3518#else
3519 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003521 },
3522 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003523#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003524 1
3525#else
3526 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003527#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003528 },
3529 {"autocmd", 1},
3530 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003531#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003532 1
3533#else
3534 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003535#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003536 },
3537 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003538#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003539 1
3540#else
3541 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003542#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003543 },
3544 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003545#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003546 1
3547#else
3548 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003549#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003550 },
3551 {"balloon_multiline",
3552#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3553 // MS-Windows requires runtime check, see below
3554 1
3555#else
3556 0
3557#endif
3558 },
3559 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003560#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003561 1
3562#else
3563 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003564#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003565 },
3566 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003567#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003568 1
3569#else
3570 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003571#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003572 },
3573 {"all_builtin_terms",
3574#if defined(ALL_BUILTIN_TCAPS)
3575 1
3576#else
3577 0
3578#endif
3579 },
3580 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003581#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003582 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003583 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003584 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003585#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003586 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003587#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003588 },
3589 {"byte_offset",
3590#ifdef FEAT_BYTEOFF
3591 1
3592#else
3593 0
3594#endif
3595 },
3596 {"channel",
3597#ifdef FEAT_JOB_CHANNEL
3598 1
3599#else
3600 0
3601#endif
3602 },
3603 {"cindent",
3604#ifdef FEAT_CINDENT
3605 1
3606#else
3607 0
3608#endif
3609 },
3610 {"clientserver",
3611#ifdef FEAT_CLIENTSERVER
3612 1
3613#else
3614 0
3615#endif
3616 },
3617 {"clipboard",
3618#ifdef FEAT_CLIPBOARD
3619 1
3620#else
3621 0
3622#endif
3623 },
3624 {"cmdline_compl", 1},
3625 {"cmdline_hist", 1},
3626 {"comments", 1},
3627 {"conceal",
3628#ifdef FEAT_CONCEAL
3629 1
3630#else
3631 0
3632#endif
3633 },
3634 {"cryptv",
3635#ifdef FEAT_CRYPT
3636 1
3637#else
3638 0
3639#endif
3640 },
3641 {"crypt-blowfish",
3642#ifdef FEAT_CRYPT
3643 1
3644#else
3645 0
3646#endif
3647 },
3648 {"crypt-blowfish2",
3649#ifdef FEAT_CRYPT
3650 1
3651#else
3652 0
3653#endif
3654 },
3655 {"cscope",
3656#ifdef FEAT_CSCOPE
3657 1
3658#else
3659 0
3660#endif
3661 },
3662 {"cursorbind", 1},
3663 {"cursorshape",
3664#ifdef CURSOR_SHAPE
3665 1
3666#else
3667 0
3668#endif
3669 },
3670 {"debug",
3671#ifdef DEBUG
3672 1
3673#else
3674 0
3675#endif
3676 },
3677 {"dialog_con",
3678#ifdef FEAT_CON_DIALOG
3679 1
3680#else
3681 0
3682#endif
3683 },
3684 {"dialog_gui",
3685#ifdef FEAT_GUI_DIALOG
3686 1
3687#else
3688 0
3689#endif
3690 },
3691 {"diff",
3692#ifdef FEAT_DIFF
3693 1
3694#else
3695 0
3696#endif
3697 },
3698 {"digraphs",
3699#ifdef FEAT_DIGRAPHS
3700 1
3701#else
3702 0
3703#endif
3704 },
3705 {"directx",
3706#ifdef FEAT_DIRECTX
3707 1
3708#else
3709 0
3710#endif
3711 },
3712 {"dnd",
3713#ifdef FEAT_DND
3714 1
3715#else
3716 0
3717#endif
3718 },
3719 {"emacs_tags",
3720#ifdef FEAT_EMACS_TAGS
3721 1
3722#else
3723 0
3724#endif
3725 },
3726 {"eval", 1}, // always present, of course!
3727 {"ex_extra", 1}, // graduated feature
3728 {"extra_search",
3729#ifdef FEAT_SEARCH_EXTRA
3730 1
3731#else
3732 0
3733#endif
3734 },
3735 {"file_in_path",
3736#ifdef FEAT_SEARCHPATH
3737 1
3738#else
3739 0
3740#endif
3741 },
3742 {"filterpipe",
3743#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3744 1
3745#else
3746 0
3747#endif
3748 },
3749 {"find_in_path",
3750#ifdef FEAT_FIND_ID
3751 1
3752#else
3753 0
3754#endif
3755 },
3756 {"float",
3757#ifdef FEAT_FLOAT
3758 1
3759#else
3760 0
3761#endif
3762 },
3763 {"folding",
3764#ifdef FEAT_FOLDING
3765 1
3766#else
3767 0
3768#endif
3769 },
3770 {"footer",
3771#ifdef FEAT_FOOTER
3772 1
3773#else
3774 0
3775#endif
3776 },
3777 {"fork",
3778#if !defined(USE_SYSTEM) && defined(UNIX)
3779 1
3780#else
3781 0
3782#endif
3783 },
3784 {"gettext",
3785#ifdef FEAT_GETTEXT
3786 1
3787#else
3788 0
3789#endif
3790 },
3791 {"gui",
3792#ifdef FEAT_GUI
3793 1
3794#else
3795 0
3796#endif
3797 },
3798 {"gui_neXtaw",
3799#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3800 1
3801#else
3802 0
3803#endif
3804 },
3805 {"gui_athena",
3806#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3807 1
3808#else
3809 0
3810#endif
3811 },
3812 {"gui_gtk",
3813#ifdef FEAT_GUI_GTK
3814 1
3815#else
3816 0
3817#endif
3818 },
3819 {"gui_gtk2",
3820#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3821 1
3822#else
3823 0
3824#endif
3825 },
3826 {"gui_gtk3",
3827#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3828 1
3829#else
3830 0
3831#endif
3832 },
3833 {"gui_gnome",
3834#ifdef FEAT_GUI_GNOME
3835 1
3836#else
3837 0
3838#endif
3839 },
3840 {"gui_haiku",
3841#ifdef FEAT_GUI_HAIKU
3842 1
3843#else
3844 0
3845#endif
3846 },
3847 {"gui_mac",
3848#ifdef FEAT_GUI_MAC
3849 1
3850#else
3851 0
3852#endif
3853 },
3854 {"gui_motif",
3855#ifdef FEAT_GUI_MOTIF
3856 1
3857#else
3858 0
3859#endif
3860 },
3861 {"gui_photon",
3862#ifdef FEAT_GUI_PHOTON
3863 1
3864#else
3865 0
3866#endif
3867 },
3868 {"gui_win32",
3869#ifdef FEAT_GUI_MSWIN
3870 1
3871#else
3872 0
3873#endif
3874 },
3875 {"iconv",
3876#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3877 1
3878#else
3879 0
3880#endif
3881 },
3882 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003883 {"ipv6",
3884#ifdef FEAT_IPV6
3885 1
3886#else
3887 0
3888#endif
3889 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003890 {"job",
3891#ifdef FEAT_JOB_CHANNEL
3892 1
3893#else
3894 0
3895#endif
3896 },
3897 {"jumplist",
3898#ifdef FEAT_JUMPLIST
3899 1
3900#else
3901 0
3902#endif
3903 },
3904 {"keymap",
3905#ifdef FEAT_KEYMAP
3906 1
3907#else
3908 0
3909#endif
3910 },
3911 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
3912 {"langmap",
3913#ifdef FEAT_LANGMAP
3914 1
3915#else
3916 0
3917#endif
3918 },
3919 {"libcall",
3920#ifdef FEAT_LIBCALL
3921 1
3922#else
3923 0
3924#endif
3925 },
3926 {"linebreak",
3927#ifdef FEAT_LINEBREAK
3928 1
3929#else
3930 0
3931#endif
3932 },
3933 {"lispindent",
3934#ifdef FEAT_LISP
3935 1
3936#else
3937 0
3938#endif
3939 },
3940 {"listcmds", 1},
3941 {"localmap", 1},
3942 {"lua",
3943#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
3944 1
3945#else
3946 0
3947#endif
3948 },
3949 {"menu",
3950#ifdef FEAT_MENU
3951 1
3952#else
3953 0
3954#endif
3955 },
3956 {"mksession",
3957#ifdef FEAT_SESSION
3958 1
3959#else
3960 0
3961#endif
3962 },
3963 {"modify_fname", 1},
3964 {"mouse", 1},
3965 {"mouseshape",
3966#ifdef FEAT_MOUSESHAPE
3967 1
3968#else
3969 0
3970#endif
3971 },
3972 {"mouse_dec",
3973#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
3974 1
3975#else
3976 0
3977#endif
3978 },
3979 {"mouse_gpm",
3980#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
3981 1
3982#else
3983 0
3984#endif
3985 },
3986 {"mouse_jsbterm",
3987#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
3988 1
3989#else
3990 0
3991#endif
3992 },
3993 {"mouse_netterm",
3994#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
3995 1
3996#else
3997 0
3998#endif
3999 },
4000 {"mouse_pterm",
4001#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
4002 1
4003#else
4004 0
4005#endif
4006 },
4007 {"mouse_sgr",
4008#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4009 1
4010#else
4011 0
4012#endif
4013 },
4014 {"mouse_sysmouse",
4015#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4016 1
4017#else
4018 0
4019#endif
4020 },
4021 {"mouse_urxvt",
4022#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4023 1
4024#else
4025 0
4026#endif
4027 },
4028 {"mouse_xterm",
4029#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4030 1
4031#else
4032 0
4033#endif
4034 },
4035 {"multi_byte", 1},
4036 {"multi_byte_ime",
4037#ifdef FEAT_MBYTE_IME
4038 1
4039#else
4040 0
4041#endif
4042 },
4043 {"multi_lang",
4044#ifdef FEAT_MULTI_LANG
4045 1
4046#else
4047 0
4048#endif
4049 },
4050 {"mzscheme",
4051#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4052 1
4053#else
4054 0
4055#endif
4056 },
4057 {"num64", 1},
4058 {"ole",
4059#ifdef FEAT_OLE
4060 1
4061#else
4062 0
4063#endif
4064 },
4065 {"packages",
4066#ifdef FEAT_EVAL
4067 1
4068#else
4069 0
4070#endif
4071 },
4072 {"path_extra",
4073#ifdef FEAT_PATH_EXTRA
4074 1
4075#else
4076 0
4077#endif
4078 },
4079 {"perl",
4080#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4081 1
4082#else
4083 0
4084#endif
4085 },
4086 {"persistent_undo",
4087#ifdef FEAT_PERSISTENT_UNDO
4088 1
4089#else
4090 0
4091#endif
4092 },
4093 {"python_compiled",
4094#if defined(FEAT_PYTHON)
4095 1
4096#else
4097 0
4098#endif
4099 },
4100 {"python_dynamic",
4101#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4102 1
4103#else
4104 0
4105#endif
4106 },
4107 {"python",
4108#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4109 1
4110#else
4111 0
4112#endif
4113 },
4114 {"pythonx",
4115#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4116 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4117 1
4118#else
4119 0
4120#endif
4121 },
4122 {"python3_compiled",
4123#if defined(FEAT_PYTHON3)
4124 1
4125#else
4126 0
4127#endif
4128 },
4129 {"python3_dynamic",
4130#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4131 1
4132#else
4133 0
4134#endif
4135 },
4136 {"python3",
4137#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4138 1
4139#else
4140 0
4141#endif
4142 },
4143 {"popupwin",
4144#ifdef FEAT_PROP_POPUP
4145 1
4146#else
4147 0
4148#endif
4149 },
4150 {"postscript",
4151#ifdef FEAT_POSTSCRIPT
4152 1
4153#else
4154 0
4155#endif
4156 },
4157 {"printer",
4158#ifdef FEAT_PRINTER
4159 1
4160#else
4161 0
4162#endif
4163 },
4164 {"profile",
4165#ifdef FEAT_PROFILE
4166 1
4167#else
4168 0
4169#endif
4170 },
4171 {"reltime",
4172#ifdef FEAT_RELTIME
4173 1
4174#else
4175 0
4176#endif
4177 },
4178 {"quickfix",
4179#ifdef FEAT_QUICKFIX
4180 1
4181#else
4182 0
4183#endif
4184 },
4185 {"rightleft",
4186#ifdef FEAT_RIGHTLEFT
4187 1
4188#else
4189 0
4190#endif
4191 },
4192 {"ruby",
4193#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4194 1
4195#else
4196 0
4197#endif
4198 },
4199 {"scrollbind", 1},
4200 {"showcmd",
4201#ifdef FEAT_CMDL_INFO
4202 1
4203#else
4204 0
4205#endif
4206 },
4207 {"cmdline_info",
4208#ifdef FEAT_CMDL_INFO
4209 1
4210#else
4211 0
4212#endif
4213 },
4214 {"signs",
4215#ifdef FEAT_SIGNS
4216 1
4217#else
4218 0
4219#endif
4220 },
4221 {"smartindent",
4222#ifdef FEAT_SMARTINDENT
4223 1
4224#else
4225 0
4226#endif
4227 },
4228 {"startuptime",
4229#ifdef STARTUPTIME
4230 1
4231#else
4232 0
4233#endif
4234 },
4235 {"statusline",
4236#ifdef FEAT_STL_OPT
4237 1
4238#else
4239 0
4240#endif
4241 },
4242 {"netbeans_intg",
4243#ifdef FEAT_NETBEANS_INTG
4244 1
4245#else
4246 0
4247#endif
4248 },
4249 {"sound",
4250#ifdef FEAT_SOUND
4251 1
4252#else
4253 0
4254#endif
4255 },
4256 {"spell",
4257#ifdef FEAT_SPELL
4258 1
4259#else
4260 0
4261#endif
4262 },
4263 {"syntax",
4264#ifdef FEAT_SYN_HL
4265 1
4266#else
4267 0
4268#endif
4269 },
4270 {"system",
4271#if defined(USE_SYSTEM) || !defined(UNIX)
4272 1
4273#else
4274 0
4275#endif
4276 },
4277 {"tag_binary",
4278#ifdef FEAT_TAG_BINS
4279 1
4280#else
4281 0
4282#endif
4283 },
4284 {"tcl",
4285#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4286 1
4287#else
4288 0
4289#endif
4290 },
4291 {"termguicolors",
4292#ifdef FEAT_TERMGUICOLORS
4293 1
4294#else
4295 0
4296#endif
4297 },
4298 {"terminal",
4299#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4300 1
4301#else
4302 0
4303#endif
4304 },
4305 {"terminfo",
4306#ifdef TERMINFO
4307 1
4308#else
4309 0
4310#endif
4311 },
4312 {"termresponse",
4313#ifdef FEAT_TERMRESPONSE
4314 1
4315#else
4316 0
4317#endif
4318 },
4319 {"textobjects",
4320#ifdef FEAT_TEXTOBJ
4321 1
4322#else
4323 0
4324#endif
4325 },
4326 {"textprop",
4327#ifdef FEAT_PROP_POPUP
4328 1
4329#else
4330 0
4331#endif
4332 },
4333 {"tgetent",
4334#ifdef HAVE_TGETENT
4335 1
4336#else
4337 0
4338#endif
4339 },
4340 {"timers",
4341#ifdef FEAT_TIMERS
4342 1
4343#else
4344 0
4345#endif
4346 },
4347 {"title",
4348#ifdef FEAT_TITLE
4349 1
4350#else
4351 0
4352#endif
4353 },
4354 {"toolbar",
4355#ifdef FEAT_TOOLBAR
4356 1
4357#else
4358 0
4359#endif
4360 },
4361 {"unnamedplus",
4362#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4363 1
4364#else
4365 0
4366#endif
4367 },
4368 {"user-commands", 1}, // was accidentally included in 5.4
4369 {"user_commands", 1},
4370 {"vartabs",
4371#ifdef FEAT_VARTABS
4372 1
4373#else
4374 0
4375#endif
4376 },
4377 {"vertsplit", 1},
4378 {"viminfo",
4379#ifdef FEAT_VIMINFO
4380 1
4381#else
4382 0
4383#endif
4384 },
4385 {"vimscript-1", 1},
4386 {"vimscript-2", 1},
4387 {"vimscript-3", 1},
4388 {"vimscript-4", 1},
4389 {"virtualedit", 1},
4390 {"visual", 1},
4391 {"visualextra", 1},
4392 {"vreplace", 1},
4393 {"vtp",
4394#ifdef FEAT_VTP
4395 1
4396#else
4397 0
4398#endif
4399 },
4400 {"wildignore",
4401#ifdef FEAT_WILDIGN
4402 1
4403#else
4404 0
4405#endif
4406 },
4407 {"wildmenu",
4408#ifdef FEAT_WILDMENU
4409 1
4410#else
4411 0
4412#endif
4413 },
4414 {"windows", 1},
4415 {"winaltkeys",
4416#ifdef FEAT_WAK
4417 1
4418#else
4419 0
4420#endif
4421 },
4422 {"writebackup",
4423#ifdef FEAT_WRITEBACKUP
4424 1
4425#else
4426 0
4427#endif
4428 },
4429 {"xim",
4430#ifdef FEAT_XIM
4431 1
4432#else
4433 0
4434#endif
4435 },
4436 {"xfontset",
4437#ifdef FEAT_XFONTSET
4438 1
4439#else
4440 0
4441#endif
4442 },
4443 {"xpm",
4444#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4445 1
4446#else
4447 0
4448#endif
4449 },
4450 {"xpm_w32", // for backward compatibility
4451#ifdef FEAT_XPM_W32
4452 1
4453#else
4454 0
4455#endif
4456 },
4457 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004458#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004459 1
4460#else
4461 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004462#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004463 },
4464 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004465#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004466 1
4467#else
4468 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004470 },
4471 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004472#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004473 1
4474#else
4475 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004477 },
4478 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004480 1
4481#else
4482 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004483#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004484 },
4485 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004486#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004487 1
4488#else
4489 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004490#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004491 },
4492 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004493 };
4494
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004495 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004496 for (i = 0; has_list[i].name != NULL; ++i)
4497 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004498 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004499 x = TRUE;
4500 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004501 break;
4502 }
4503
Bram Moolenaar79296512020-03-22 16:17:14 +01004504 // features also in has_list[] but sometimes enabled at runtime
4505 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004506 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004507 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004508 {
4509 // intentionally empty
4510 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004511#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004512 else if (STRICMP(name, "balloon_multiline") == 0)
4513 n = multiline_balloon_available();
4514#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004515#ifdef VIMDLL
4516 else if (STRICMP(name, "filterpipe") == 0)
4517 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004518#endif
4519#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4520 else if (STRICMP(name, "iconv") == 0)
4521 n = iconv_enabled(FALSE);
4522#endif
4523#ifdef DYNAMIC_LUA
4524 else if (STRICMP(name, "lua") == 0)
4525 n = lua_enabled(FALSE);
4526#endif
4527#ifdef DYNAMIC_MZSCHEME
4528 else if (STRICMP(name, "mzscheme") == 0)
4529 n = mzscheme_enabled(FALSE);
4530#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004531#ifdef DYNAMIC_PERL
4532 else if (STRICMP(name, "perl") == 0)
4533 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004535#ifdef DYNAMIC_PYTHON
4536 else if (STRICMP(name, "python") == 0)
4537 n = python_enabled(FALSE);
4538#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004539#ifdef DYNAMIC_PYTHON3
4540 else if (STRICMP(name, "python3") == 0)
4541 n = python3_enabled(FALSE);
4542#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004543#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4544 else if (STRICMP(name, "pythonx") == 0)
4545 {
4546# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4547 if (p_pyx == 0)
4548 n = python3_enabled(FALSE) || python_enabled(FALSE);
4549 else if (p_pyx == 3)
4550 n = python3_enabled(FALSE);
4551 else if (p_pyx == 2)
4552 n = python_enabled(FALSE);
4553# elif defined(DYNAMIC_PYTHON)
4554 n = python_enabled(FALSE);
4555# elif defined(DYNAMIC_PYTHON3)
4556 n = python3_enabled(FALSE);
4557# endif
4558 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004559#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004560#ifdef DYNAMIC_RUBY
4561 else if (STRICMP(name, "ruby") == 0)
4562 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004564#ifdef DYNAMIC_TCL
4565 else if (STRICMP(name, "tcl") == 0)
4566 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004567#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004568#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004569 else if (STRICMP(name, "terminal") == 0)
4570 n = terminal_enabled();
4571#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004572 }
4573
Bram Moolenaar79296512020-03-22 16:17:14 +01004574 // features not in has_list[]
4575 if (x == FALSE)
4576 {
4577 if (STRNICMP(name, "patch", 5) == 0)
4578 {
4579 x = TRUE;
4580 if (name[5] == '-'
4581 && STRLEN(name) >= 11
4582 && vim_isdigit(name[6])
4583 && vim_isdigit(name[8])
4584 && vim_isdigit(name[10]))
4585 {
4586 int major = atoi((char *)name + 6);
4587 int minor = atoi((char *)name + 8);
4588
4589 // Expect "patch-9.9.01234".
4590 n = (major < VIM_VERSION_MAJOR
4591 || (major == VIM_VERSION_MAJOR
4592 && (minor < VIM_VERSION_MINOR
4593 || (minor == VIM_VERSION_MINOR
4594 && has_patch(atoi((char *)name + 10))))));
4595 }
4596 else
4597 n = has_patch(atoi((char *)name + 5));
4598 }
4599 else if (STRICMP(name, "vim_starting") == 0)
4600 {
4601 x = TRUE;
4602 n = (starting != 0);
4603 }
4604 else if (STRICMP(name, "ttyin") == 0)
4605 {
4606 x = TRUE;
4607 n = mch_input_isatty();
4608 }
4609 else if (STRICMP(name, "ttyout") == 0)
4610 {
4611 x = TRUE;
4612 n = stdout_isatty;
4613 }
4614 else if (STRICMP(name, "multi_byte_encoding") == 0)
4615 {
4616 x = TRUE;
4617 n = has_mbyte;
4618 }
4619 else if (STRICMP(name, "gui_running") == 0)
4620 {
4621 x = TRUE;
4622#ifdef FEAT_GUI
4623 n = (gui.in_use || gui.starting);
4624#endif
4625 }
4626 else if (STRICMP(name, "browse") == 0)
4627 {
4628 x = TRUE;
4629#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4630 n = gui.in_use; // gui_mch_browse() works when GUI is running
4631#endif
4632 }
4633 else if (STRICMP(name, "syntax_items") == 0)
4634 {
4635 x = TRUE;
4636#ifdef FEAT_SYN_HL
4637 n = syntax_present(curwin);
4638#endif
4639 }
4640 else if (STRICMP(name, "vcon") == 0)
4641 {
4642 x = TRUE;
4643#ifdef FEAT_VTP
4644 n = is_term_win32() && has_vtp_working();
4645#endif
4646 }
4647 else if (STRICMP(name, "netbeans_enabled") == 0)
4648 {
4649 x = TRUE;
4650#ifdef FEAT_NETBEANS_INTG
4651 n = netbeans_active();
4652#endif
4653 }
4654 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4655 {
4656 x = TRUE;
4657#ifdef FEAT_MOUSE_GPM
4658 n = gpm_enabled();
4659#endif
4660 }
4661 else if (STRICMP(name, "conpty") == 0)
4662 {
4663 x = TRUE;
4664#if defined(FEAT_TERMINAL) && defined(MSWIN)
4665 n = use_conpty();
4666#endif
4667 }
4668 else if (STRICMP(name, "clipboard_working") == 0)
4669 {
4670 x = TRUE;
4671#ifdef FEAT_CLIPBOARD
4672 n = clip_star.available;
4673#endif
4674 }
4675 }
4676
4677 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4678 // return whether feature could ever be enabled
4679 rettv->vval.v_number = x;
4680 else
4681 // return whether feature is enabled
4682 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004683}
4684
4685/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686 * "haslocaldir()" function
4687 */
4688 static void
4689f_haslocaldir(typval_T *argvars, typval_T *rettv)
4690{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004691 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004692 win_T *wp = NULL;
4693
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004694 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4695
4696 // Check for window-local and tab-local directories
4697 if (wp != NULL && wp->w_localdir != NULL)
4698 rettv->vval.v_number = 1;
4699 else if (tp != NULL && tp->tp_localdir != NULL)
4700 rettv->vval.v_number = 2;
4701 else
4702 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004703}
4704
4705/*
4706 * "hasmapto()" function
4707 */
4708 static void
4709f_hasmapto(typval_T *argvars, typval_T *rettv)
4710{
4711 char_u *name;
4712 char_u *mode;
4713 char_u buf[NUMBUFLEN];
4714 int abbr = FALSE;
4715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004716 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717 if (argvars[1].v_type == VAR_UNKNOWN)
4718 mode = (char_u *)"nvo";
4719 else
4720 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004721 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004722 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004723 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004724 }
4725
4726 if (map_to_exists(name, mode, abbr))
4727 rettv->vval.v_number = TRUE;
4728 else
4729 rettv->vval.v_number = FALSE;
4730}
4731
4732/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 * "highlightID(name)" function
4734 */
4735 static void
4736f_hlID(typval_T *argvars, typval_T *rettv)
4737{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004738 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004739}
4740
4741/*
4742 * "highlight_exists()" function
4743 */
4744 static void
4745f_hlexists(typval_T *argvars, typval_T *rettv)
4746{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004747 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748}
4749
4750/*
4751 * "hostname()" function
4752 */
4753 static void
4754f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4755{
4756 char_u hostname[256];
4757
4758 mch_get_host_name(hostname, 256);
4759 rettv->v_type = VAR_STRING;
4760 rettv->vval.v_string = vim_strsave(hostname);
4761}
4762
4763/*
4764 * iconv() function
4765 */
4766 static void
4767f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4768{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004769 char_u buf1[NUMBUFLEN];
4770 char_u buf2[NUMBUFLEN];
4771 char_u *from, *to, *str;
4772 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004773
4774 rettv->v_type = VAR_STRING;
4775 rettv->vval.v_string = NULL;
4776
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004777 str = tv_get_string(&argvars[0]);
4778 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4779 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004780 vimconv.vc_type = CONV_NONE;
4781 convert_setup(&vimconv, from, to);
4782
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004783 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004784 if (vimconv.vc_type == CONV_NONE)
4785 rettv->vval.v_string = vim_strsave(str);
4786 else
4787 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4788
4789 convert_setup(&vimconv, NULL, NULL);
4790 vim_free(from);
4791 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004792}
4793
4794/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004795 * "index()" function
4796 */
4797 static void
4798f_index(typval_T *argvars, typval_T *rettv)
4799{
4800 list_T *l;
4801 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004802 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004803 long idx = 0;
4804 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004805 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004806
4807 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004808 if (argvars[0].v_type == VAR_BLOB)
4809 {
4810 typval_T tv;
4811 int start = 0;
4812
4813 if (argvars[2].v_type != VAR_UNKNOWN)
4814 {
4815 start = tv_get_number_chk(&argvars[2], &error);
4816 if (error)
4817 return;
4818 }
4819 b = argvars[0].vval.v_blob;
4820 if (b == NULL)
4821 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004822 if (start < 0)
4823 {
4824 start = blob_len(b) + start;
4825 if (start < 0)
4826 start = 0;
4827 }
4828
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004829 for (idx = start; idx < blob_len(b); ++idx)
4830 {
4831 tv.v_type = VAR_NUMBER;
4832 tv.vval.v_number = blob_get(b, idx);
4833 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4834 {
4835 rettv->vval.v_number = idx;
4836 return;
4837 }
4838 }
4839 return;
4840 }
4841 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004842 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004843 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844 return;
4845 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004847 l = argvars[0].vval.v_list;
4848 if (l != NULL)
4849 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004850 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004851 item = l->lv_first;
4852 if (argvars[2].v_type != VAR_UNKNOWN)
4853 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004854 // Start at specified item. Use the cached index that list_find()
4855 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004856 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004857 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004858 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004859 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004860 if (error)
4861 item = NULL;
4862 }
4863
4864 for ( ; item != NULL; item = item->li_next, ++idx)
4865 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4866 {
4867 rettv->vval.v_number = idx;
4868 break;
4869 }
4870 }
4871}
4872
4873static int inputsecret_flag = 0;
4874
4875/*
4876 * "input()" function
4877 * Also handles inputsecret() when inputsecret is set.
4878 */
4879 static void
4880f_input(typval_T *argvars, typval_T *rettv)
4881{
4882 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4883}
4884
4885/*
4886 * "inputdialog()" function
4887 */
4888 static void
4889f_inputdialog(typval_T *argvars, typval_T *rettv)
4890{
4891#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004892 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004893 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4894 {
4895 char_u *message;
4896 char_u buf[NUMBUFLEN];
4897 char_u *defstr = (char_u *)"";
4898
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004899 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004900 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004901 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004902 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4903 else
4904 IObuff[0] = NUL;
4905 if (message != NULL && defstr != NULL
4906 && do_dialog(VIM_QUESTION, NULL, message,
4907 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4908 rettv->vval.v_string = vim_strsave(IObuff);
4909 else
4910 {
4911 if (message != NULL && defstr != NULL
4912 && argvars[1].v_type != VAR_UNKNOWN
4913 && argvars[2].v_type != VAR_UNKNOWN)
4914 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004915 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004916 else
4917 rettv->vval.v_string = NULL;
4918 }
4919 rettv->v_type = VAR_STRING;
4920 }
4921 else
4922#endif
4923 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4924}
4925
4926/*
4927 * "inputlist()" function
4928 */
4929 static void
4930f_inputlist(typval_T *argvars, typval_T *rettv)
4931{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004932 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933 listitem_T *li;
4934 int selected;
4935 int mouse_used;
4936
4937#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004938 // While starting up, there is no place to enter text. When running tests
4939 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004940 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004941 return;
4942#endif
4943 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4944 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004945 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946 return;
4947 }
4948
4949 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004950 msg_row = Rows - 1; // for when 'cmdheight' > 1
4951 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004952 msg_scroll = TRUE;
4953 msg_clr_eos();
4954
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004955 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004956 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02004957 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004959 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004960 msg_putchar('\n');
4961 }
4962
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004963 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004964 selected = prompt_for_number(&mouse_used);
4965 if (mouse_used)
4966 selected -= lines_left;
4967
4968 rettv->vval.v_number = selected;
4969}
4970
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004971static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4972
4973/*
4974 * "inputrestore()" function
4975 */
4976 static void
4977f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4978{
4979 if (ga_userinput.ga_len > 0)
4980 {
4981 --ga_userinput.ga_len;
4982 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4983 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004984 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004985 }
4986 else if (p_verbose > 1)
4987 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004988 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004989 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004990 }
4991}
4992
4993/*
4994 * "inputsave()" function
4995 */
4996 static void
4997f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4998{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004999 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000 if (ga_grow(&ga_userinput, 1) == OK)
5001 {
5002 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5003 + ga_userinput.ga_len);
5004 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005005 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005006 }
5007 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005008 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005009}
5010
5011/*
5012 * "inputsecret()" function
5013 */
5014 static void
5015f_inputsecret(typval_T *argvars, typval_T *rettv)
5016{
5017 ++cmdline_star;
5018 ++inputsecret_flag;
5019 f_input(argvars, rettv);
5020 --cmdline_star;
5021 --inputsecret_flag;
5022}
5023
5024/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005025 * "interrupt()" function
5026 */
5027 static void
5028f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5029{
5030 got_int = TRUE;
5031}
5032
5033/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034 * "invert(expr)" function
5035 */
5036 static void
5037f_invert(typval_T *argvars, typval_T *rettv)
5038{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005039 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005040}
5041
5042/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005043 * "islocked()" function
5044 */
5045 static void
5046f_islocked(typval_T *argvars, typval_T *rettv)
5047{
5048 lval_T lv;
5049 char_u *end;
5050 dictitem_T *di;
5051
5052 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005053 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005054 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005055 if (end != NULL && lv.ll_name != NULL)
5056 {
5057 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005058 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005059 else
5060 {
5061 if (lv.ll_tv == NULL)
5062 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005063 di = find_var(lv.ll_name, NULL, TRUE);
5064 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005066 // Consider a variable locked when:
5067 // 1. the variable itself is locked
5068 // 2. the value of the variable is locked.
5069 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005070 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5071 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005072 }
5073 }
5074 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005075 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005077 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005078 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005079 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005080 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5081 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005082 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005083 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5084 }
5085 }
5086
5087 clear_lval(&lv);
5088}
5089
5090#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5091/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005092 * "isinf()" function
5093 */
5094 static void
5095f_isinf(typval_T *argvars, typval_T *rettv)
5096{
5097 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5098 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5099}
5100
5101/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 * "isnan()" function
5103 */
5104 static void
5105f_isnan(typval_T *argvars, typval_T *rettv)
5106{
5107 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5108 && isnan(argvars[0].vval.v_float);
5109}
5110#endif
5111
5112/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113 * "last_buffer_nr()" function.
5114 */
5115 static void
5116f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5117{
5118 int n = 0;
5119 buf_T *buf;
5120
Bram Moolenaar29323592016-07-24 22:04:11 +02005121 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005122 if (n < buf->b_fnum)
5123 n = buf->b_fnum;
5124
5125 rettv->vval.v_number = n;
5126}
5127
5128/*
5129 * "len()" function
5130 */
5131 static void
5132f_len(typval_T *argvars, typval_T *rettv)
5133{
5134 switch (argvars[0].v_type)
5135 {
5136 case VAR_STRING:
5137 case VAR_NUMBER:
5138 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005139 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005140 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005141 case VAR_BLOB:
5142 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5143 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005144 case VAR_LIST:
5145 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5146 break;
5147 case VAR_DICT:
5148 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5149 break;
5150 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005151 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005152 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005153 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005154 case VAR_SPECIAL:
5155 case VAR_FLOAT:
5156 case VAR_FUNC:
5157 case VAR_PARTIAL:
5158 case VAR_JOB:
5159 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005160 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005161 break;
5162 }
5163}
5164
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005165 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005166libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005167{
5168#ifdef FEAT_LIBCALL
5169 char_u *string_in;
5170 char_u **string_result;
5171 int nr_result;
5172#endif
5173
5174 rettv->v_type = type;
5175 if (type != VAR_NUMBER)
5176 rettv->vval.v_string = NULL;
5177
5178 if (check_restricted() || check_secure())
5179 return;
5180
5181#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005182 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005183 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5184 {
5185 string_in = NULL;
5186 if (argvars[2].v_type == VAR_STRING)
5187 string_in = argvars[2].vval.v_string;
5188 if (type == VAR_NUMBER)
5189 string_result = NULL;
5190 else
5191 string_result = &rettv->vval.v_string;
5192 if (mch_libcall(argvars[0].vval.v_string,
5193 argvars[1].vval.v_string,
5194 string_in,
5195 argvars[2].vval.v_number,
5196 string_result,
5197 &nr_result) == OK
5198 && type == VAR_NUMBER)
5199 rettv->vval.v_number = nr_result;
5200 }
5201#endif
5202}
5203
5204/*
5205 * "libcall()" function
5206 */
5207 static void
5208f_libcall(typval_T *argvars, typval_T *rettv)
5209{
5210 libcall_common(argvars, rettv, VAR_STRING);
5211}
5212
5213/*
5214 * "libcallnr()" function
5215 */
5216 static void
5217f_libcallnr(typval_T *argvars, typval_T *rettv)
5218{
5219 libcall_common(argvars, rettv, VAR_NUMBER);
5220}
5221
5222/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005223 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005224 */
5225 static void
5226f_line(typval_T *argvars, typval_T *rettv)
5227{
5228 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005229 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005230 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005231 int id;
5232 tabpage_T *tp;
5233 win_T *wp;
5234 win_T *save_curwin;
5235 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005236
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005237 if (argvars[1].v_type != VAR_UNKNOWN)
5238 {
5239 // use window specified in the second argument
5240 id = (int)tv_get_number(&argvars[1]);
5241 wp = win_id2wp_tp(id, &tp);
5242 if (wp != NULL && tp != NULL)
5243 {
5244 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5245 == OK)
5246 {
5247 check_cursor();
5248 fp = var2fpos(&argvars[0], TRUE, &fnum);
5249 }
5250 restore_win_noblock(save_curwin, save_curtab, TRUE);
5251 }
5252 }
5253 else
5254 // use current window
5255 fp = var2fpos(&argvars[0], TRUE, &fnum);
5256
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005257 if (fp != NULL)
5258 lnum = fp->lnum;
5259 rettv->vval.v_number = lnum;
5260}
5261
5262/*
5263 * "line2byte(lnum)" function
5264 */
5265 static void
5266f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5267{
5268#ifndef FEAT_BYTEOFF
5269 rettv->vval.v_number = -1;
5270#else
5271 linenr_T lnum;
5272
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005273 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005274 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5275 rettv->vval.v_number = -1;
5276 else
5277 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5278 if (rettv->vval.v_number >= 0)
5279 ++rettv->vval.v_number;
5280#endif
5281}
5282
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005283#ifdef FEAT_FLOAT
5284/*
5285 * "log()" function
5286 */
5287 static void
5288f_log(typval_T *argvars, typval_T *rettv)
5289{
5290 float_T f = 0.0;
5291
5292 rettv->v_type = VAR_FLOAT;
5293 if (get_float_arg(argvars, &f) == OK)
5294 rettv->vval.v_float = log(f);
5295 else
5296 rettv->vval.v_float = 0.0;
5297}
5298
5299/*
5300 * "log10()" function
5301 */
5302 static void
5303f_log10(typval_T *argvars, typval_T *rettv)
5304{
5305 float_T f = 0.0;
5306
5307 rettv->v_type = VAR_FLOAT;
5308 if (get_float_arg(argvars, &f) == OK)
5309 rettv->vval.v_float = log10(f);
5310 else
5311 rettv->vval.v_float = 0.0;
5312}
5313#endif
5314
5315#ifdef FEAT_LUA
5316/*
5317 * "luaeval()" function
5318 */
5319 static void
5320f_luaeval(typval_T *argvars, typval_T *rettv)
5321{
5322 char_u *str;
5323 char_u buf[NUMBUFLEN];
5324
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005325 if (check_restricted() || check_secure())
5326 return;
5327
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005328 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005329 do_luaeval(str, argvars + 1, rettv);
5330}
5331#endif
5332
5333/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005334 * "maparg()" function
5335 */
5336 static void
5337f_maparg(typval_T *argvars, typval_T *rettv)
5338{
5339 get_maparg(argvars, rettv, TRUE);
5340}
5341
5342/*
5343 * "mapcheck()" function
5344 */
5345 static void
5346f_mapcheck(typval_T *argvars, typval_T *rettv)
5347{
5348 get_maparg(argvars, rettv, FALSE);
5349}
5350
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005351typedef enum
5352{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005353 MATCH_END, // matchend()
5354 MATCH_MATCH, // match()
5355 MATCH_STR, // matchstr()
5356 MATCH_LIST, // matchlist()
5357 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005358} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005359
5360 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005361find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005362{
5363 char_u *str = NULL;
5364 long len = 0;
5365 char_u *expr = NULL;
5366 char_u *pat;
5367 regmatch_T regmatch;
5368 char_u patbuf[NUMBUFLEN];
5369 char_u strbuf[NUMBUFLEN];
5370 char_u *save_cpo;
5371 long start = 0;
5372 long nth = 1;
5373 colnr_T startcol = 0;
5374 int match = 0;
5375 list_T *l = NULL;
5376 listitem_T *li = NULL;
5377 long idx = 0;
5378 char_u *tofree = NULL;
5379
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005380 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005381 save_cpo = p_cpo;
5382 p_cpo = (char_u *)"";
5383
5384 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005385 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005386 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005387 // type MATCH_LIST: return empty list when there are no matches.
5388 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005389 if (rettv_list_alloc(rettv) == FAIL)
5390 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005391 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005392 && (list_append_string(rettv->vval.v_list,
5393 (char_u *)"", 0) == FAIL
5394 || list_append_number(rettv->vval.v_list,
5395 (varnumber_T)-1) == FAIL
5396 || list_append_number(rettv->vval.v_list,
5397 (varnumber_T)-1) == FAIL
5398 || list_append_number(rettv->vval.v_list,
5399 (varnumber_T)-1) == FAIL))
5400 {
5401 list_free(rettv->vval.v_list);
5402 rettv->vval.v_list = NULL;
5403 goto theend;
5404 }
5405 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005406 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005407 {
5408 rettv->v_type = VAR_STRING;
5409 rettv->vval.v_string = NULL;
5410 }
5411
5412 if (argvars[0].v_type == VAR_LIST)
5413 {
5414 if ((l = argvars[0].vval.v_list) == NULL)
5415 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005416 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 li = l->lv_first;
5418 }
5419 else
5420 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005421 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005422 len = (long)STRLEN(str);
5423 }
5424
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005425 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005426 if (pat == NULL)
5427 goto theend;
5428
5429 if (argvars[2].v_type != VAR_UNKNOWN)
5430 {
5431 int error = FALSE;
5432
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005433 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005434 if (error)
5435 goto theend;
5436 if (l != NULL)
5437 {
5438 li = list_find(l, start);
5439 if (li == NULL)
5440 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005441 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005442 }
5443 else
5444 {
5445 if (start < 0)
5446 start = 0;
5447 if (start > len)
5448 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005449 // When "count" argument is there ignore matches before "start",
5450 // otherwise skip part of the string. Differs when pattern is "^"
5451 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452 if (argvars[3].v_type != VAR_UNKNOWN)
5453 startcol = start;
5454 else
5455 {
5456 str += start;
5457 len -= start;
5458 }
5459 }
5460
5461 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005462 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005463 if (error)
5464 goto theend;
5465 }
5466
5467 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5468 if (regmatch.regprog != NULL)
5469 {
5470 regmatch.rm_ic = p_ic;
5471
5472 for (;;)
5473 {
5474 if (l != NULL)
5475 {
5476 if (li == NULL)
5477 {
5478 match = FALSE;
5479 break;
5480 }
5481 vim_free(tofree);
5482 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5483 if (str == NULL)
5484 break;
5485 }
5486
5487 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5488
5489 if (match && --nth <= 0)
5490 break;
5491 if (l == NULL && !match)
5492 break;
5493
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005494 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005495 if (l != NULL)
5496 {
5497 li = li->li_next;
5498 ++idx;
5499 }
5500 else
5501 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502 startcol = (colnr_T)(regmatch.startp[0]
5503 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504 if (startcol > (colnr_T)len
5505 || str + startcol <= regmatch.startp[0])
5506 {
5507 match = FALSE;
5508 break;
5509 }
5510 }
5511 }
5512
5513 if (match)
5514 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005515 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516 {
5517 listitem_T *li1 = rettv->vval.v_list->lv_first;
5518 listitem_T *li2 = li1->li_next;
5519 listitem_T *li3 = li2->li_next;
5520 listitem_T *li4 = li3->li_next;
5521
5522 vim_free(li1->li_tv.vval.v_string);
5523 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5524 (int)(regmatch.endp[0] - regmatch.startp[0]));
5525 li3->li_tv.vval.v_number =
5526 (varnumber_T)(regmatch.startp[0] - expr);
5527 li4->li_tv.vval.v_number =
5528 (varnumber_T)(regmatch.endp[0] - expr);
5529 if (l != NULL)
5530 li2->li_tv.vval.v_number = (varnumber_T)idx;
5531 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005532 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005533 {
5534 int i;
5535
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005536 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005537 for (i = 0; i < NSUBEXP; ++i)
5538 {
5539 if (regmatch.endp[i] == NULL)
5540 {
5541 if (list_append_string(rettv->vval.v_list,
5542 (char_u *)"", 0) == FAIL)
5543 break;
5544 }
5545 else if (list_append_string(rettv->vval.v_list,
5546 regmatch.startp[i],
5547 (int)(regmatch.endp[i] - regmatch.startp[i]))
5548 == FAIL)
5549 break;
5550 }
5551 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005552 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005553 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005554 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005555 if (l != NULL)
5556 copy_tv(&li->li_tv, rettv);
5557 else
5558 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
5559 (int)(regmatch.endp[0] - regmatch.startp[0]));
5560 }
5561 else if (l != NULL)
5562 rettv->vval.v_number = idx;
5563 else
5564 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005565 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005566 rettv->vval.v_number =
5567 (varnumber_T)(regmatch.startp[0] - str);
5568 else
5569 rettv->vval.v_number =
5570 (varnumber_T)(regmatch.endp[0] - str);
5571 rettv->vval.v_number += (varnumber_T)(str - expr);
5572 }
5573 }
5574 vim_regfree(regmatch.regprog);
5575 }
5576
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005577theend:
5578 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005579 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005580 listitem_remove(rettv->vval.v_list,
5581 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005582 vim_free(tofree);
5583 p_cpo = save_cpo;
5584}
5585
5586/*
5587 * "match()" function
5588 */
5589 static void
5590f_match(typval_T *argvars, typval_T *rettv)
5591{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005592 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005593}
5594
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005595/*
5596 * "matchend()" function
5597 */
5598 static void
5599f_matchend(typval_T *argvars, typval_T *rettv)
5600{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005601 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005602}
5603
5604/*
5605 * "matchlist()" function
5606 */
5607 static void
5608f_matchlist(typval_T *argvars, typval_T *rettv)
5609{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005610 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005611}
5612
5613/*
5614 * "matchstr()" function
5615 */
5616 static void
5617f_matchstr(typval_T *argvars, typval_T *rettv)
5618{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005619 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005620}
5621
5622/*
5623 * "matchstrpos()" function
5624 */
5625 static void
5626f_matchstrpos(typval_T *argvars, typval_T *rettv)
5627{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005628 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005629}
5630
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631 static void
5632max_min(typval_T *argvars, typval_T *rettv, int domax)
5633{
5634 varnumber_T n = 0;
5635 varnumber_T i;
5636 int error = FALSE;
5637
5638 if (argvars[0].v_type == VAR_LIST)
5639 {
5640 list_T *l;
5641 listitem_T *li;
5642
5643 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005644 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005645 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005646 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005647 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005648 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5649 n = l->lv_u.nonmat.lv_start;
5650 else
5651 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5652 * l->lv_u.nonmat.lv_stride;
5653 }
5654 else
5655 {
5656 li = l->lv_first;
5657 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005658 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005659 n = tv_get_number_chk(&li->li_tv, &error);
5660 for (;;)
5661 {
5662 li = li->li_next;
5663 if (li == NULL)
5664 break;
5665 i = tv_get_number_chk(&li->li_tv, &error);
5666 if (domax ? i > n : i < n)
5667 n = i;
5668 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005669 }
5670 }
5671 }
5672 }
5673 else if (argvars[0].v_type == VAR_DICT)
5674 {
5675 dict_T *d;
5676 int first = TRUE;
5677 hashitem_T *hi;
5678 int todo;
5679
5680 d = argvars[0].vval.v_dict;
5681 if (d != NULL)
5682 {
5683 todo = (int)d->dv_hashtab.ht_used;
5684 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5685 {
5686 if (!HASHITEM_EMPTY(hi))
5687 {
5688 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005689 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005690 if (first)
5691 {
5692 n = i;
5693 first = FALSE;
5694 }
5695 else if (domax ? i > n : i < n)
5696 n = i;
5697 }
5698 }
5699 }
5700 }
5701 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005702 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005703 rettv->vval.v_number = error ? 0 : n;
5704}
5705
5706/*
5707 * "max()" function
5708 */
5709 static void
5710f_max(typval_T *argvars, typval_T *rettv)
5711{
5712 max_min(argvars, rettv, TRUE);
5713}
5714
5715/*
5716 * "min()" function
5717 */
5718 static void
5719f_min(typval_T *argvars, typval_T *rettv)
5720{
5721 max_min(argvars, rettv, FALSE);
5722}
5723
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005724#if defined(FEAT_MZSCHEME) || defined(PROTO)
5725/*
5726 * "mzeval()" function
5727 */
5728 static void
5729f_mzeval(typval_T *argvars, typval_T *rettv)
5730{
5731 char_u *str;
5732 char_u buf[NUMBUFLEN];
5733
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005734 if (check_restricted() || check_secure())
5735 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005736 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005737 do_mzeval(str, rettv);
5738}
5739
5740 void
5741mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5742{
5743 typval_T argvars[3];
5744
5745 argvars[0].v_type = VAR_STRING;
5746 argvars[0].vval.v_string = name;
5747 copy_tv(args, &argvars[1]);
5748 argvars[2].v_type = VAR_UNKNOWN;
5749 f_call(argvars, rettv);
5750 clear_tv(&argvars[1]);
5751}
5752#endif
5753
5754/*
5755 * "nextnonblank()" function
5756 */
5757 static void
5758f_nextnonblank(typval_T *argvars, typval_T *rettv)
5759{
5760 linenr_T lnum;
5761
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005762 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005763 {
5764 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5765 {
5766 lnum = 0;
5767 break;
5768 }
5769 if (*skipwhite(ml_get(lnum)) != NUL)
5770 break;
5771 }
5772 rettv->vval.v_number = lnum;
5773}
5774
5775/*
5776 * "nr2char()" function
5777 */
5778 static void
5779f_nr2char(typval_T *argvars, typval_T *rettv)
5780{
5781 char_u buf[NUMBUFLEN];
5782
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 if (has_mbyte)
5784 {
5785 int utf8 = 0;
5786
5787 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005788 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005789 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005790 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005792 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005793 }
5794 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005795 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005796 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005797 buf[1] = NUL;
5798 }
5799 rettv->v_type = VAR_STRING;
5800 rettv->vval.v_string = vim_strsave(buf);
5801}
5802
5803/*
5804 * "or(expr, expr)" function
5805 */
5806 static void
5807f_or(typval_T *argvars, typval_T *rettv)
5808{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005809 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5810 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005811}
5812
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005813#ifdef FEAT_PERL
5814/*
5815 * "perleval()" function
5816 */
5817 static void
5818f_perleval(typval_T *argvars, typval_T *rettv)
5819{
5820 char_u *str;
5821 char_u buf[NUMBUFLEN];
5822
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005823 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005824 do_perleval(str, rettv);
5825}
5826#endif
5827
5828#ifdef FEAT_FLOAT
5829/*
5830 * "pow()" function
5831 */
5832 static void
5833f_pow(typval_T *argvars, typval_T *rettv)
5834{
5835 float_T fx = 0.0, fy = 0.0;
5836
5837 rettv->v_type = VAR_FLOAT;
5838 if (get_float_arg(argvars, &fx) == OK
5839 && get_float_arg(&argvars[1], &fy) == OK)
5840 rettv->vval.v_float = pow(fx, fy);
5841 else
5842 rettv->vval.v_float = 0.0;
5843}
5844#endif
5845
5846/*
5847 * "prevnonblank()" function
5848 */
5849 static void
5850f_prevnonblank(typval_T *argvars, typval_T *rettv)
5851{
5852 linenr_T lnum;
5853
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005854 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005855 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5856 lnum = 0;
5857 else
5858 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5859 --lnum;
5860 rettv->vval.v_number = lnum;
5861}
5862
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005863// This dummy va_list is here because:
5864// - passing a NULL pointer doesn't work when va_list isn't a pointer
5865// - locally in the function results in a "used before set" warning
5866// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005867static va_list ap;
5868
5869/*
5870 * "printf()" function
5871 */
5872 static void
5873f_printf(typval_T *argvars, typval_T *rettv)
5874{
5875 char_u buf[NUMBUFLEN];
5876 int len;
5877 char_u *s;
5878 int saved_did_emsg = did_emsg;
5879 char *fmt;
5880
5881 rettv->v_type = VAR_STRING;
5882 rettv->vval.v_string = NULL;
5883
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005884 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005886 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005887 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005888 if (!did_emsg)
5889 {
5890 s = alloc(len + 1);
5891 if (s != NULL)
5892 {
5893 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005894 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5895 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005896 }
5897 }
5898 did_emsg |= saved_did_emsg;
5899}
5900
5901/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005902 * "pum_getpos()" function
5903 */
5904 static void
5905f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5906{
5907 if (rettv_dict_alloc(rettv) != OK)
5908 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005909 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005910}
5911
5912/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005913 * "pumvisible()" function
5914 */
5915 static void
5916f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5917{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005918 if (pum_visible())
5919 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005920}
5921
5922#ifdef FEAT_PYTHON3
5923/*
5924 * "py3eval()" function
5925 */
5926 static void
5927f_py3eval(typval_T *argvars, typval_T *rettv)
5928{
5929 char_u *str;
5930 char_u buf[NUMBUFLEN];
5931
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005932 if (check_restricted() || check_secure())
5933 return;
5934
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005935 if (p_pyx == 0)
5936 p_pyx = 3;
5937
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005938 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005939 do_py3eval(str, rettv);
5940}
5941#endif
5942
5943#ifdef FEAT_PYTHON
5944/*
5945 * "pyeval()" function
5946 */
5947 static void
5948f_pyeval(typval_T *argvars, typval_T *rettv)
5949{
5950 char_u *str;
5951 char_u buf[NUMBUFLEN];
5952
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005953 if (check_restricted() || check_secure())
5954 return;
5955
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005956 if (p_pyx == 0)
5957 p_pyx = 2;
5958
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005959 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005960 do_pyeval(str, rettv);
5961}
5962#endif
5963
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005964#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5965/*
5966 * "pyxeval()" function
5967 */
5968 static void
5969f_pyxeval(typval_T *argvars, typval_T *rettv)
5970{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005971 if (check_restricted() || check_secure())
5972 return;
5973
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005974# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5975 init_pyxversion();
5976 if (p_pyx == 2)
5977 f_pyeval(argvars, rettv);
5978 else
5979 f_py3eval(argvars, rettv);
5980# elif defined(FEAT_PYTHON)
5981 f_pyeval(argvars, rettv);
5982# elif defined(FEAT_PYTHON3)
5983 f_py3eval(argvars, rettv);
5984# endif
5985}
5986#endif
5987
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005988static UINT32_T srand_seed_for_testing = 0;
5989static int srand_seed_for_testing_is_used = FALSE;
5990
5991 static void
5992f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5993{
5994 if (argvars[0].v_type == VAR_UNKNOWN)
5995 srand_seed_for_testing_is_used = FALSE;
5996 else
5997 {
5998 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5999 srand_seed_for_testing_is_used = TRUE;
6000 }
6001}
6002
6003 static void
6004init_srand(UINT32_T *x)
6005{
6006#ifndef MSWIN
6007 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6008#endif
6009
6010 if (srand_seed_for_testing_is_used)
6011 {
6012 *x = srand_seed_for_testing;
6013 return;
6014 }
6015#ifndef MSWIN
6016 if (dev_urandom_state != FAIL)
6017 {
6018 int fd = open("/dev/urandom", O_RDONLY);
6019 struct {
6020 union {
6021 UINT32_T number;
6022 char bytes[sizeof(UINT32_T)];
6023 } contents;
6024 } buf;
6025
6026 // Attempt reading /dev/urandom.
6027 if (fd == -1)
6028 dev_urandom_state = FAIL;
6029 else
6030 {
6031 buf.contents.number = 0;
6032 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6033 != sizeof(UINT32_T))
6034 dev_urandom_state = FAIL;
6035 else
6036 {
6037 dev_urandom_state = OK;
6038 *x = buf.contents.number;
6039 }
6040 close(fd);
6041 }
6042 }
6043 if (dev_urandom_state != OK)
6044 // Reading /dev/urandom doesn't work, fall back to time().
6045#endif
6046 *x = vim_time();
6047}
6048
6049#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6050#define SPLITMIX32(x, z) ( \
6051 z = (x += 0x9e3779b9), \
6052 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6053 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6054 z ^ (z >> 16) \
6055 )
6056#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6057 result = ROTL(y * 5, 7) * 9; \
6058 t = y << 9; \
6059 z ^= x; \
6060 w ^= y; \
6061 y ^= z, x ^= w; \
6062 z ^= t; \
6063 w = ROTL(w, 11);
6064
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006066 * "rand()" function
6067 */
6068 static void
6069f_rand(typval_T *argvars, typval_T *rettv)
6070{
6071 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006072 static UINT32_T gx, gy, gz, gw;
6073 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006074 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006075 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006076
6077 if (argvars[0].v_type == VAR_UNKNOWN)
6078 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006079 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006080 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006081 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006082 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006083 init_srand(&x);
6084
6085 gx = SPLITMIX32(x, z);
6086 gy = SPLITMIX32(x, z);
6087 gz = SPLITMIX32(x, z);
6088 gw = SPLITMIX32(x, z);
6089 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006090 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006091
6092 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006093 }
6094 else if (argvars[0].v_type == VAR_LIST)
6095 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006096 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006097 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006098 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006099
6100 lx = list_find(l, 0L);
6101 ly = list_find(l, 1L);
6102 lz = list_find(l, 2L);
6103 lw = list_find(l, 3L);
6104 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6105 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6106 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6107 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6108 x = (UINT32_T)lx->li_tv.vval.v_number;
6109 y = (UINT32_T)ly->li_tv.vval.v_number;
6110 z = (UINT32_T)lz->li_tv.vval.v_number;
6111 w = (UINT32_T)lw->li_tv.vval.v_number;
6112
6113 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6114
6115 lx->li_tv.vval.v_number = (varnumber_T)x;
6116 ly->li_tv.vval.v_number = (varnumber_T)y;
6117 lz->li_tv.vval.v_number = (varnumber_T)z;
6118 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006119 }
6120 else
6121 goto theend;
6122
6123 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006124 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006125 return;
6126
6127theend:
6128 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006129 rettv->v_type = VAR_NUMBER;
6130 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006131}
6132
6133/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006134 * "srand()" function
6135 */
6136 static void
6137f_srand(typval_T *argvars, typval_T *rettv)
6138{
6139 UINT32_T x = 0, z;
6140
6141 if (rettv_list_alloc(rettv) == FAIL)
6142 return;
6143 if (argvars[0].v_type == VAR_UNKNOWN)
6144 {
6145 init_srand(&x);
6146 }
6147 else
6148 {
6149 int error = FALSE;
6150
6151 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6152 if (error)
6153 return;
6154 }
6155
6156 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
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}
6161
6162#undef ROTL
6163#undef SPLITMIX32
6164#undef SHUFFLE_XOSHIRO128STARSTAR
6165
6166/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006167 * "range()" function
6168 */
6169 static void
6170f_range(typval_T *argvars, typval_T *rettv)
6171{
6172 varnumber_T start;
6173 varnumber_T end;
6174 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175 int error = FALSE;
6176
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006177 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006178 if (argvars[1].v_type == VAR_UNKNOWN)
6179 {
6180 end = start - 1;
6181 start = 0;
6182 }
6183 else
6184 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006185 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006187 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 }
6189
6190 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006191 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006192 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006193 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006195 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006196 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006198 list_T *list = rettv->vval.v_list;
6199
6200 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006201 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006202 // be called.
6203 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006204 list->lv_u.nonmat.lv_start = start;
6205 list->lv_u.nonmat.lv_end = end;
6206 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006207 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006208 }
6209}
6210
6211/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006212 * Materialize "list".
6213 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006214 */
6215 void
6216range_list_materialize(list_T *list)
6217{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006218 varnumber_T start = list->lv_u.nonmat.lv_start;
6219 varnumber_T end = list->lv_u.nonmat.lv_end;
6220 int stride = list->lv_u.nonmat.lv_stride;
6221 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006222
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006223 list->lv_first = NULL;
6224 list->lv_u.mat.lv_last = NULL;
6225 list->lv_len = 0;
6226 list->lv_u.mat.lv_idx_item = NULL;
6227 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6228 if (list_append_number(list, (varnumber_T)i) == FAIL)
6229 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006230}
6231
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006232/*
6233 * "getreginfo()" function
6234 */
6235 static void
6236f_getreginfo(typval_T *argvars, typval_T *rettv)
6237{
6238 char_u *strregname;
6239 int regname;
6240 char_u buf[NUMBUFLEN + 2];
6241 long reglen = 0;
6242 dict_T *dict;
6243 list_T *list;
6244
6245 if (argvars[0].v_type != VAR_UNKNOWN)
6246 {
6247 strregname = tv_get_string_chk(&argvars[0]);
6248 if (strregname == NULL)
6249 return;
6250 }
6251 else
6252 strregname = get_vim_var_str(VV_REG);
6253
6254 regname = (strregname == NULL ? '"' : *strregname);
6255 if (regname == 0 || regname == '@')
6256 regname = '"';
6257
6258 if (rettv_dict_alloc(rettv) == FAIL)
6259 return;
6260 dict = rettv->vval.v_dict;
6261
6262 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
6263 if (list == NULL)
6264 return;
6265 dict_add_list(dict, "regcontents", list);
6266
6267 buf[0] = NUL;
6268 buf[1] = NUL;
6269 switch (get_reg_type(regname, &reglen))
6270 {
6271 case MLINE: buf[0] = 'V'; break;
6272 case MCHAR: buf[0] = 'v'; break;
6273 case MBLOCK:
6274 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
6275 reglen + 1);
6276 break;
6277 }
6278 dict_add_string(dict, (char *)"regtype", buf);
6279
6280 buf[0] = get_register_name(get_unname_register());
6281 buf[1] = NUL;
6282 if (regname == '"')
6283 dict_add_string(dict, (char *)"points_to", buf);
6284 else
6285 {
6286 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
6287
6288 if (item != NULL)
6289 {
6290 item->di_tv.v_type = VAR_SPECIAL;
6291 item->di_tv.vval.v_number = regname == buf[0]
6292 ? VVAL_TRUE : VVAL_FALSE;
6293 dict_add(dict, item);
6294 }
6295 }
6296}
6297
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006298 static void
6299return_register(int regname, typval_T *rettv)
6300{
6301 char_u buf[2] = {0, 0};
6302
6303 buf[0] = (char_u)regname;
6304 rettv->v_type = VAR_STRING;
6305 rettv->vval.v_string = vim_strsave(buf);
6306}
6307
6308/*
6309 * "reg_executing()" function
6310 */
6311 static void
6312f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6313{
6314 return_register(reg_executing, rettv);
6315}
6316
6317/*
6318 * "reg_recording()" function
6319 */
6320 static void
6321f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6322{
6323 return_register(reg_recording, rettv);
6324}
6325
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006326/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006327 * "rename({from}, {to})" function
6328 */
6329 static void
6330f_rename(typval_T *argvars, typval_T *rettv)
6331{
6332 char_u buf[NUMBUFLEN];
6333
6334 if (check_restricted() || check_secure())
6335 rettv->vval.v_number = -1;
6336 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006337 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6338 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006339}
6340
6341/*
6342 * "repeat()" function
6343 */
6344 static void
6345f_repeat(typval_T *argvars, typval_T *rettv)
6346{
6347 char_u *p;
6348 int n;
6349 int slen;
6350 int len;
6351 char_u *r;
6352 int i;
6353
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006354 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355 if (argvars[0].v_type == VAR_LIST)
6356 {
6357 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6358 while (n-- > 0)
6359 if (list_extend(rettv->vval.v_list,
6360 argvars[0].vval.v_list, NULL) == FAIL)
6361 break;
6362 }
6363 else
6364 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006365 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366 rettv->v_type = VAR_STRING;
6367 rettv->vval.v_string = NULL;
6368
6369 slen = (int)STRLEN(p);
6370 len = slen * n;
6371 if (len <= 0)
6372 return;
6373
6374 r = alloc(len + 1);
6375 if (r != NULL)
6376 {
6377 for (i = 0; i < n; i++)
6378 mch_memmove(r + i * slen, p, (size_t)slen);
6379 r[len] = NUL;
6380 }
6381
6382 rettv->vval.v_string = r;
6383 }
6384}
6385
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006386#define SP_NOMOVE 0x01 // don't move cursor
6387#define SP_REPEAT 0x02 // repeat to find outer pair
6388#define SP_RETCOUNT 0x04 // return matchcount
6389#define SP_SETPCMARK 0x08 // set previous context mark
6390#define SP_START 0x10 // accept match at start position
6391#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6392#define SP_END 0x40 // leave cursor at end of match
6393#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006395/*
6396 * Get flags for a search function.
6397 * Possibly sets "p_ws".
6398 * Returns BACKWARD, FORWARD or zero (for an error).
6399 */
6400 static int
6401get_search_arg(typval_T *varp, int *flagsp)
6402{
6403 int dir = FORWARD;
6404 char_u *flags;
6405 char_u nbuf[NUMBUFLEN];
6406 int mask;
6407
6408 if (varp->v_type != VAR_UNKNOWN)
6409 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006410 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006411 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006412 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006413 while (*flags != NUL)
6414 {
6415 switch (*flags)
6416 {
6417 case 'b': dir = BACKWARD; break;
6418 case 'w': p_ws = TRUE; break;
6419 case 'W': p_ws = FALSE; break;
6420 default: mask = 0;
6421 if (flagsp != NULL)
6422 switch (*flags)
6423 {
6424 case 'c': mask = SP_START; break;
6425 case 'e': mask = SP_END; break;
6426 case 'm': mask = SP_RETCOUNT; break;
6427 case 'n': mask = SP_NOMOVE; break;
6428 case 'p': mask = SP_SUBPAT; break;
6429 case 'r': mask = SP_REPEAT; break;
6430 case 's': mask = SP_SETPCMARK; break;
6431 case 'z': mask = SP_COLUMN; break;
6432 }
6433 if (mask == 0)
6434 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006435 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006436 dir = 0;
6437 }
6438 else
6439 *flagsp |= mask;
6440 }
6441 if (dir == 0)
6442 break;
6443 ++flags;
6444 }
6445 }
6446 return dir;
6447}
6448
6449/*
6450 * Shared by search() and searchpos() functions.
6451 */
6452 static int
6453search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6454{
6455 int flags;
6456 char_u *pat;
6457 pos_T pos;
6458 pos_T save_cursor;
6459 int save_p_ws = p_ws;
6460 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006461 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006463#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006464 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465 long time_limit = 0;
6466#endif
6467 int options = SEARCH_KEEP;
6468 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006469 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006470 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006471 pos_T firstpos;
6472
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006473 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006474 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 if (dir == 0)
6476 goto theend;
6477 flags = *flagsp;
6478 if (flags & SP_START)
6479 options |= SEARCH_START;
6480 if (flags & SP_END)
6481 options |= SEARCH_END;
6482 if (flags & SP_COLUMN)
6483 options |= SEARCH_COL;
6484
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006485 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6487 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006488 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489 if (lnum_stop < 0)
6490 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491 if (argvars[3].v_type != VAR_UNKNOWN)
6492 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006493#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006494 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006495 if (time_limit < 0)
6496 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006497#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02006498 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006499 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500 }
6501
6502#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006503 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 profile_setlimit(time_limit, &tm);
6505#endif
6506
6507 /*
6508 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6509 * Check to make sure only those flags are set.
6510 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6511 * flags cannot be set. Check for that condition also.
6512 */
6513 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6514 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6515 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006516 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006517 goto theend;
6518 }
6519
6520 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006521 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02006522 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006523 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6524#ifdef FEAT_RELTIME
6525 sia.sa_tm = &tm;
6526#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006527
6528 // Repeat until {skip} returns FALSE.
6529 for (;;)
6530 {
6531 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006532 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006533 // finding the first match again means there is no match where {skip}
6534 // evaluates to zero.
6535 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
6536 subpatnum = FAIL;
6537
Bram Moolenaara9c01042020-06-07 14:50:50 +02006538 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006539 // didn't find it or no skip argument
6540 break;
6541 firstpos = pos;
6542
Bram Moolenaara9c01042020-06-07 14:50:50 +02006543 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006544 {
6545 int do_skip;
6546 int err;
6547 pos_T save_pos = curwin->w_cursor;
6548
6549 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006550 err = FALSE;
6551 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006552 curwin->w_cursor = save_pos;
6553 if (err)
6554 {
6555 // Evaluating {skip} caused an error, break here.
6556 subpatnum = FAIL;
6557 break;
6558 }
6559 if (!do_skip)
6560 break;
6561 }
6562 }
6563
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006564 if (subpatnum != FAIL)
6565 {
6566 if (flags & SP_SUBPAT)
6567 retval = subpatnum;
6568 else
6569 retval = pos.lnum;
6570 if (flags & SP_SETPCMARK)
6571 setpcmark();
6572 curwin->w_cursor = pos;
6573 if (match_pos != NULL)
6574 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006575 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006576 match_pos->lnum = pos.lnum;
6577 match_pos->col = pos.col + 1;
6578 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006579 // "/$" will put the cursor after the end of the line, may need to
6580 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006581 check_cursor();
6582 }
6583
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006584 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006585 if (flags & SP_NOMOVE)
6586 curwin->w_cursor = save_cursor;
6587 else
6588 curwin->w_set_curswant = TRUE;
6589theend:
6590 p_ws = save_p_ws;
6591
6592 return retval;
6593}
6594
6595#ifdef FEAT_FLOAT
6596
6597/*
6598 * round() is not in C90, use ceil() or floor() instead.
6599 */
6600 float_T
6601vim_round(float_T f)
6602{
6603 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6604}
6605
6606/*
6607 * "round({float})" function
6608 */
6609 static void
6610f_round(typval_T *argvars, typval_T *rettv)
6611{
6612 float_T f = 0.0;
6613
6614 rettv->v_type = VAR_FLOAT;
6615 if (get_float_arg(argvars, &f) == OK)
6616 rettv->vval.v_float = vim_round(f);
6617 else
6618 rettv->vval.v_float = 0.0;
6619}
6620#endif
6621
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006622#ifdef FEAT_RUBY
6623/*
6624 * "rubyeval()" function
6625 */
6626 static void
6627f_rubyeval(typval_T *argvars, typval_T *rettv)
6628{
6629 char_u *str;
6630 char_u buf[NUMBUFLEN];
6631
6632 str = tv_get_string_buf(&argvars[0], buf);
6633 do_rubyeval(str, rettv);
6634}
6635#endif
6636
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006637/*
6638 * "screenattr()" function
6639 */
6640 static void
6641f_screenattr(typval_T *argvars, typval_T *rettv)
6642{
6643 int row;
6644 int col;
6645 int c;
6646
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006647 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6648 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006649 if (row < 0 || row >= screen_Rows
6650 || col < 0 || col >= screen_Columns)
6651 c = -1;
6652 else
6653 c = ScreenAttrs[LineOffset[row] + col];
6654 rettv->vval.v_number = c;
6655}
6656
6657/*
6658 * "screenchar()" function
6659 */
6660 static void
6661f_screenchar(typval_T *argvars, typval_T *rettv)
6662{
6663 int row;
6664 int col;
6665 int off;
6666 int c;
6667
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006668 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6669 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006670 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006671 c = -1;
6672 else
6673 {
6674 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675 if (enc_utf8 && ScreenLinesUC[off] != 0)
6676 c = ScreenLinesUC[off];
6677 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006678 c = ScreenLines[off];
6679 }
6680 rettv->vval.v_number = c;
6681}
6682
6683/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006684 * "screenchars()" function
6685 */
6686 static void
6687f_screenchars(typval_T *argvars, typval_T *rettv)
6688{
6689 int row;
6690 int col;
6691 int off;
6692 int c;
6693 int i;
6694
6695 if (rettv_list_alloc(rettv) == FAIL)
6696 return;
6697 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6698 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6699 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6700 return;
6701
6702 off = LineOffset[row] + col;
6703 if (enc_utf8 && ScreenLinesUC[off] != 0)
6704 c = ScreenLinesUC[off];
6705 else
6706 c = ScreenLines[off];
6707 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6708
6709 if (enc_utf8)
6710
6711 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6712 list_append_number(rettv->vval.v_list,
6713 (varnumber_T)ScreenLinesC[i][off]);
6714}
6715
6716/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006717 * "screencol()" function
6718 *
6719 * First column is 1 to be consistent with virtcol().
6720 */
6721 static void
6722f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6723{
6724 rettv->vval.v_number = screen_screencol() + 1;
6725}
6726
6727/*
6728 * "screenrow()" function
6729 */
6730 static void
6731f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6732{
6733 rettv->vval.v_number = screen_screenrow() + 1;
6734}
6735
6736/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006737 * "screenstring()" function
6738 */
6739 static void
6740f_screenstring(typval_T *argvars, typval_T *rettv)
6741{
6742 int row;
6743 int col;
6744 int off;
6745 int c;
6746 int i;
6747 char_u buf[MB_MAXBYTES + 1];
6748 int buflen = 0;
6749
6750 rettv->vval.v_string = NULL;
6751 rettv->v_type = VAR_STRING;
6752
6753 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6754 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6755 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6756 return;
6757
6758 off = LineOffset[row] + col;
6759 if (enc_utf8 && ScreenLinesUC[off] != 0)
6760 c = ScreenLinesUC[off];
6761 else
6762 c = ScreenLines[off];
6763 buflen += mb_char2bytes(c, buf);
6764
6765 if (enc_utf8)
6766 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6767 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6768
6769 buf[buflen] = NUL;
6770 rettv->vval.v_string = vim_strsave(buf);
6771}
6772
6773/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774 * "search()" function
6775 */
6776 static void
6777f_search(typval_T *argvars, typval_T *rettv)
6778{
6779 int flags = 0;
6780
6781 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6782}
6783
6784/*
6785 * "searchdecl()" function
6786 */
6787 static void
6788f_searchdecl(typval_T *argvars, typval_T *rettv)
6789{
6790 int locally = 1;
6791 int thisblock = 0;
6792 int error = FALSE;
6793 char_u *name;
6794
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006795 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006797 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006798 if (argvars[1].v_type != VAR_UNKNOWN)
6799 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006800 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006801 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006802 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006803 }
6804 if (!error && name != NULL)
6805 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6806 locally, thisblock, SEARCH_KEEP) == FAIL;
6807}
6808
6809/*
6810 * Used by searchpair() and searchpairpos()
6811 */
6812 static int
6813searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6814{
6815 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006816 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006817 int save_p_ws = p_ws;
6818 int dir;
6819 int flags = 0;
6820 char_u nbuf1[NUMBUFLEN];
6821 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006822 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006823 long lnum_stop = 0;
6824 long time_limit = 0;
6825
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006826 // Get the three pattern arguments: start, middle, end. Will result in an
6827 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006828 spat = tv_get_string_chk(&argvars[0]);
6829 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6830 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006832 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006833
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006834 // Handle the optional fourth argument: flags
6835 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836 if (dir == 0)
6837 goto theend;
6838
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006839 // Don't accept SP_END or SP_SUBPAT.
6840 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006841 if ((flags & (SP_END | SP_SUBPAT)) != 0
6842 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6843 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006844 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006845 goto theend;
6846 }
6847
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006848 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006849 if (flags & SP_REPEAT)
6850 p_ws = FALSE;
6851
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006852 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006853 if (argvars[3].v_type == VAR_UNKNOWN
6854 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006855 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006856 else
6857 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02006858 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01006859 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02006860
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006861 if (argvars[5].v_type != VAR_UNKNOWN)
6862 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006863 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006864 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006865 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006866 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006867 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006868 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869#ifdef FEAT_RELTIME
6870 if (argvars[6].v_type != VAR_UNKNOWN)
6871 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006872 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006873 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006874 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006875 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006876 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006877 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 }
6879#endif
6880 }
6881 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882
6883 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6884 match_pos, lnum_stop, time_limit);
6885
6886theend:
6887 p_ws = save_p_ws;
6888
6889 return retval;
6890}
6891
6892/*
6893 * "searchpair()" function
6894 */
6895 static void
6896f_searchpair(typval_T *argvars, typval_T *rettv)
6897{
6898 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6899}
6900
6901/*
6902 * "searchpairpos()" function
6903 */
6904 static void
6905f_searchpairpos(typval_T *argvars, typval_T *rettv)
6906{
6907 pos_T match_pos;
6908 int lnum = 0;
6909 int col = 0;
6910
6911 if (rettv_list_alloc(rettv) == FAIL)
6912 return;
6913
6914 if (searchpair_cmn(argvars, &match_pos) > 0)
6915 {
6916 lnum = match_pos.lnum;
6917 col = match_pos.col;
6918 }
6919
6920 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6921 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6922}
6923
6924/*
6925 * Search for a start/middle/end thing.
6926 * Used by searchpair(), see its documentation for the details.
6927 * Returns 0 or -1 for no match,
6928 */
6929 long
6930do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006931 char_u *spat, // start pattern
6932 char_u *mpat, // middle pattern
6933 char_u *epat, // end pattern
6934 int dir, // BACKWARD or FORWARD
6935 typval_T *skip, // skip expression
6936 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006937 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006938 linenr_T lnum_stop, // stop at this line if not zero
6939 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006940{
6941 char_u *save_cpo;
6942 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6943 long retval = 0;
6944 pos_T pos;
6945 pos_T firstpos;
6946 pos_T foundpos;
6947 pos_T save_cursor;
6948 pos_T save_pos;
6949 int n;
6950 int r;
6951 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006952 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006953 int err;
6954 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006955#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006956 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006957#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006958
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006959 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960 save_cpo = p_cpo;
6961 p_cpo = empty_option;
6962
6963#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006964 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006965 profile_setlimit(time_limit, &tm);
6966#endif
6967
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006968 // Make two search patterns: start/end (pat2, for in nested pairs) and
6969 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006970 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6971 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006972 if (pat2 == NULL || pat3 == NULL)
6973 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006974 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 if (*mpat == NUL)
6976 STRCPY(pat3, pat2);
6977 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006978 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006979 spat, epat, mpat);
6980 if (flags & SP_START)
6981 options |= SEARCH_START;
6982
Bram Moolenaar48570482017-10-30 21:48:41 +01006983 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02006984 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01006985
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986 save_cursor = curwin->w_cursor;
6987 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006988 CLEAR_POS(&firstpos);
6989 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006990 pat = pat3;
6991 for (;;)
6992 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006993 searchit_arg_T sia;
6994
Bram Moolenaara80faa82020-04-12 19:37:17 +02006995 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006996 sia.sa_stop_lnum = lnum_stop;
6997#ifdef FEAT_RELTIME
6998 sia.sa_tm = &tm;
6999#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007000 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007001 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007002 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007003 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007004 break;
7005
7006 if (firstpos.lnum == 0)
7007 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007008 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007009 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007010 // Found the same position again. Can happen with a pattern that
7011 // has "\zs" at the end and searching backwards. Advance one
7012 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007013 if (dir == BACKWARD)
7014 decl(&pos);
7015 else
7016 incl(&pos);
7017 }
7018 foundpos = pos;
7019
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007020 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007021 options &= ~SEARCH_START;
7022
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007023 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007024 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025 {
7026 save_pos = curwin->w_cursor;
7027 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007028 err = FALSE;
7029 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007030 curwin->w_cursor = save_pos;
7031 if (err)
7032 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007033 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 curwin->w_cursor = save_cursor;
7035 retval = -1;
7036 break;
7037 }
7038 if (r)
7039 continue;
7040 }
7041
7042 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7043 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007044 // Found end when searching backwards or start when searching
7045 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007046 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007047 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048 }
7049 else
7050 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007051 // Found end when searching forward or start when searching
7052 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007053 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007054 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007055 }
7056
7057 if (nest == 0)
7058 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007059 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007060 if (flags & SP_RETCOUNT)
7061 ++retval;
7062 else
7063 retval = pos.lnum;
7064 if (flags & SP_SETPCMARK)
7065 setpcmark();
7066 curwin->w_cursor = pos;
7067 if (!(flags & SP_REPEAT))
7068 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007069 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007070 }
7071 }
7072
7073 if (match_pos != NULL)
7074 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007075 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007076 match_pos->lnum = curwin->w_cursor.lnum;
7077 match_pos->col = curwin->w_cursor.col + 1;
7078 }
7079
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007080 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007081 if ((flags & SP_NOMOVE) || retval == 0)
7082 curwin->w_cursor = save_cursor;
7083
7084theend:
7085 vim_free(pat2);
7086 vim_free(pat3);
7087 if (p_cpo == empty_option)
7088 p_cpo = save_cpo;
7089 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007090 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007091 free_string_option(save_cpo);
7092
7093 return retval;
7094}
7095
7096/*
7097 * "searchpos()" function
7098 */
7099 static void
7100f_searchpos(typval_T *argvars, typval_T *rettv)
7101{
7102 pos_T match_pos;
7103 int lnum = 0;
7104 int col = 0;
7105 int n;
7106 int flags = 0;
7107
7108 if (rettv_list_alloc(rettv) == FAIL)
7109 return;
7110
7111 n = search_cmn(argvars, &match_pos, &flags);
7112 if (n > 0)
7113 {
7114 lnum = match_pos.lnum;
7115 col = match_pos.col;
7116 }
7117
7118 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7119 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7120 if (flags & SP_SUBPAT)
7121 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7122}
7123
7124 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007125f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7126{
7127 dict_T *d;
7128 dictitem_T *di;
7129 char_u *csearch;
7130
7131 if (argvars[0].v_type != VAR_DICT)
7132 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007133 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007134 return;
7135 }
7136
7137 if ((d = argvars[0].vval.v_dict) != NULL)
7138 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007139 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007140 if (csearch != NULL)
7141 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 if (enc_utf8)
7143 {
7144 int pcc[MAX_MCO];
7145 int c = utfc_ptr2char(csearch, pcc);
7146
7147 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7148 }
7149 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007151 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007152 }
7153
7154 di = dict_find(d, (char_u *)"forward", -1);
7155 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007156 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007157 ? FORWARD : BACKWARD);
7158
7159 di = dict_find(d, (char_u *)"until", -1);
7160 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007161 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007162 }
7163}
7164
7165/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007166 * "setenv()" function
7167 */
7168 static void
7169f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7170{
7171 char_u namebuf[NUMBUFLEN];
7172 char_u valbuf[NUMBUFLEN];
7173 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7174
7175 if (argvars[1].v_type == VAR_SPECIAL
7176 && argvars[1].vval.v_number == VVAL_NULL)
7177 vim_unsetenv(name);
7178 else
7179 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7180}
7181
7182/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007183 * "setfperm({fname}, {mode})" function
7184 */
7185 static void
7186f_setfperm(typval_T *argvars, typval_T *rettv)
7187{
7188 char_u *fname;
7189 char_u modebuf[NUMBUFLEN];
7190 char_u *mode_str;
7191 int i;
7192 int mask;
7193 int mode = 0;
7194
7195 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007196 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 if (fname == NULL)
7198 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007199 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007200 if (mode_str == NULL)
7201 return;
7202 if (STRLEN(mode_str) != 9)
7203 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007204 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007205 return;
7206 }
7207
7208 mask = 1;
7209 for (i = 8; i >= 0; --i)
7210 {
7211 if (mode_str[i] != '-')
7212 mode |= mask;
7213 mask = mask << 1;
7214 }
7215 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7216}
7217
7218/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007219 * "setpos()" function
7220 */
7221 static void
7222f_setpos(typval_T *argvars, typval_T *rettv)
7223{
7224 pos_T pos;
7225 int fnum;
7226 char_u *name;
7227 colnr_T curswant = -1;
7228
7229 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007230 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007231 if (name != NULL)
7232 {
7233 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7234 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007235 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 pos.col = 0;
7237 if (name[0] == '.' && name[1] == NUL)
7238 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007239 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007240 curwin->w_cursor = pos;
7241 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007242 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007243 curwin->w_curswant = curswant - 1;
7244 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007245 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007246 check_cursor();
7247 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007248 }
7249 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7250 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007251 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007252 if (setmark_pos(name[1], &pos, fnum) == OK)
7253 rettv->vval.v_number = 0;
7254 }
7255 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007256 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007257 }
7258 }
7259}
7260
7261/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007262 * "setreg()" function
7263 */
7264 static void
7265f_setreg(typval_T *argvars, typval_T *rettv)
7266{
7267 int regname;
7268 char_u *strregname;
7269 char_u *stropt;
7270 char_u *strval;
7271 int append;
7272 char_u yank_type;
7273 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007274 typval_T *regcontents;
7275 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007276
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007277 pointreg = 0;
7278 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007279 block_len = -1;
7280 yank_type = MAUTO;
7281 append = FALSE;
7282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007283 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007284 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285
7286 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007287 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 regname = *strregname;
7289 if (regname == 0 || regname == '@')
7290 regname = '"';
7291
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007292 if (argvars[1].v_type == VAR_DICT)
7293 {
7294 dict_T *d = argvars[1].vval.v_dict;
7295 dictitem_T *di = dict_find(d, (char_u *)"regcontents", -1);
7296 if (di != NULL)
7297 regcontents = &di->di_tv;
7298
7299 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
7300 if (stropt != NULL)
7301 switch (*stropt)
7302 {
7303 case 'v': // character-wise selection
7304 yank_type = MCHAR;
7305 break;
7306 case 'V': // line-wise selection
7307 yank_type = MLINE;
7308 break;
7309 case Ctrl_V: // block-wise selection
7310 yank_type = MBLOCK;
7311 if (VIM_ISDIGIT(stropt[1]))
7312 {
7313 ++stropt;
7314 block_len = getdigits(&stropt) - 1;
7315 --stropt;
7316 }
7317 break;
7318 }
7319
7320 if (regname == '"')
7321 {
7322 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
7323 if (stropt != NULL)
7324 {
7325 pointreg = *stropt;
7326 regname = pointreg;
7327 }
7328 }
7329 else if (dict_get_number(d, (char_u *)"isunnamed"))
7330 pointreg = regname;
7331 }
7332 else
7333 regcontents = &argvars[1];
7334
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007335 if (argvars[2].v_type != VAR_UNKNOWN)
7336 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007337 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007338 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007339 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007340 for (; *stropt != NUL; ++stropt)
7341 switch (*stropt)
7342 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007343 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 append = TRUE;
7345 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007346 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347 yank_type = MCHAR;
7348 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007349 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350 yank_type = MLINE;
7351 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007352 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007353 yank_type = MBLOCK;
7354 if (VIM_ISDIGIT(stropt[1]))
7355 {
7356 ++stropt;
7357 block_len = getdigits(&stropt) - 1;
7358 --stropt;
7359 }
7360 break;
7361 }
7362 }
7363
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007364 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365 {
7366 char_u **lstval;
7367 char_u **allocval;
7368 char_u buf[NUMBUFLEN];
7369 char_u **curval;
7370 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007371 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007372 listitem_T *li;
7373 int len;
7374
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007375 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007376 len = ll == NULL ? 0 : ll->lv_len;
7377
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007378 // First half: use for pointers to result lines; second half: use for
7379 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007380 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007381 if (lstval == NULL)
7382 return;
7383 curval = lstval;
7384 allocval = lstval + len + 2;
7385 curallocval = allocval;
7386
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007387 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007389 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007390 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007391 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007392 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007393 if (strval == NULL)
7394 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007395 if (strval == buf)
7396 {
7397 // Need to make a copy, next tv_get_string_buf_chk() will
7398 // overwrite the string.
7399 strval = vim_strsave(buf);
7400 if (strval == NULL)
7401 goto free_lstval;
7402 *curallocval++ = strval;
7403 }
7404 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007406 }
7407 *curval++ = NULL;
7408
7409 write_reg_contents_lst(regname, lstval, -1,
7410 append, yank_type, block_len);
7411free_lstval:
7412 while (curallocval > allocval)
7413 vim_free(*--curallocval);
7414 vim_free(lstval);
7415 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007416 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007417 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007418 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007419 if (strval == NULL)
7420 return;
7421 write_reg_contents_ex(regname, strval, -1,
7422 append, yank_type, block_len);
7423 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007424 if (pointreg != 0)
7425 get_yank_register(pointreg, TRUE);
7426
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427 rettv->vval.v_number = 0;
7428}
7429
7430/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007431 * "settagstack()" function
7432 */
7433 static void
7434f_settagstack(typval_T *argvars, typval_T *rettv)
7435{
7436 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7437 win_T *wp;
7438 dict_T *d;
7439 int action = 'r';
7440
7441 rettv->vval.v_number = -1;
7442
7443 // first argument: window number or id
7444 wp = find_win_by_nr_or_id(&argvars[0]);
7445 if (wp == NULL)
7446 return;
7447
7448 // second argument: dict with items to set in the tag stack
7449 if (argvars[1].v_type != VAR_DICT)
7450 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007451 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007452 return;
7453 }
7454 d = argvars[1].vval.v_dict;
7455 if (d == NULL)
7456 return;
7457
7458 // third argument: action - 'a' for append and 'r' for replace.
7459 // default is to replace the stack.
7460 if (argvars[2].v_type == VAR_UNKNOWN)
7461 action = 'r';
7462 else if (argvars[2].v_type == VAR_STRING)
7463 {
7464 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007465 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007466 if (actstr == NULL)
7467 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007468 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7469 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007470 action = *actstr;
7471 else
7472 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007473 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007474 return;
7475 }
7476 }
7477 else
7478 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007479 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007480 return;
7481 }
7482
7483 if (set_tagstack(wp, d, action) == OK)
7484 rettv->vval.v_number = 0;
7485}
7486
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007487#ifdef FEAT_CRYPT
7488/*
7489 * "sha256({string})" function
7490 */
7491 static void
7492f_sha256(typval_T *argvars, typval_T *rettv)
7493{
7494 char_u *p;
7495
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007496 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007497 rettv->vval.v_string = vim_strsave(
7498 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7499 rettv->v_type = VAR_STRING;
7500}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007501#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502
7503/*
7504 * "shellescape({string})" function
7505 */
7506 static void
7507f_shellescape(typval_T *argvars, typval_T *rettv)
7508{
Bram Moolenaar20615522017-06-05 18:46:26 +02007509 int do_special = non_zero_arg(&argvars[1]);
7510
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007512 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513 rettv->v_type = VAR_STRING;
7514}
7515
7516/*
7517 * shiftwidth() function
7518 */
7519 static void
7520f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7521{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007522 rettv->vval.v_number = 0;
7523
7524 if (argvars[0].v_type != VAR_UNKNOWN)
7525 {
7526 long col;
7527
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007528 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007529 if (col < 0)
7530 return; // type error; errmsg already given
7531#ifdef FEAT_VARTABS
7532 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7533 return;
7534#endif
7535 }
7536
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537 rettv->vval.v_number = get_sw_value(curbuf);
7538}
7539
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540#ifdef FEAT_FLOAT
7541/*
7542 * "sin()" function
7543 */
7544 static void
7545f_sin(typval_T *argvars, typval_T *rettv)
7546{
7547 float_T f = 0.0;
7548
7549 rettv->v_type = VAR_FLOAT;
7550 if (get_float_arg(argvars, &f) == OK)
7551 rettv->vval.v_float = sin(f);
7552 else
7553 rettv->vval.v_float = 0.0;
7554}
7555
7556/*
7557 * "sinh()" function
7558 */
7559 static void
7560f_sinh(typval_T *argvars, typval_T *rettv)
7561{
7562 float_T f = 0.0;
7563
7564 rettv->v_type = VAR_FLOAT;
7565 if (get_float_arg(argvars, &f) == OK)
7566 rettv->vval.v_float = sinh(f);
7567 else
7568 rettv->vval.v_float = 0.0;
7569}
7570#endif
7571
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007572/*
7573 * "soundfold({word})" function
7574 */
7575 static void
7576f_soundfold(typval_T *argvars, typval_T *rettv)
7577{
7578 char_u *s;
7579
7580 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007581 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007582#ifdef FEAT_SPELL
7583 rettv->vval.v_string = eval_soundfold(s);
7584#else
7585 rettv->vval.v_string = vim_strsave(s);
7586#endif
7587}
7588
7589/*
7590 * "spellbadword()" function
7591 */
7592 static void
7593f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7594{
7595 char_u *word = (char_u *)"";
7596 hlf_T attr = HLF_COUNT;
7597 int len = 0;
7598
7599 if (rettv_list_alloc(rettv) == FAIL)
7600 return;
7601
7602#ifdef FEAT_SPELL
7603 if (argvars[0].v_type == VAR_UNKNOWN)
7604 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007605 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007606 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7607 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007608 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007609 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007610 curwin->w_set_curswant = TRUE;
7611 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007612 }
7613 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7614 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007615 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007616 int capcol = -1;
7617
7618 if (str != NULL)
7619 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007620 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007621 while (*str != NUL)
7622 {
7623 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7624 if (attr != HLF_COUNT)
7625 {
7626 word = str;
7627 break;
7628 }
7629 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007630 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007631 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632 }
7633 }
7634 }
7635#endif
7636
7637 list_append_string(rettv->vval.v_list, word, len);
7638 list_append_string(rettv->vval.v_list, (char_u *)(
7639 attr == HLF_SPB ? "bad" :
7640 attr == HLF_SPR ? "rare" :
7641 attr == HLF_SPL ? "local" :
7642 attr == HLF_SPC ? "caps" :
7643 ""), -1);
7644}
7645
7646/*
7647 * "spellsuggest()" function
7648 */
7649 static void
7650f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7651{
7652#ifdef FEAT_SPELL
7653 char_u *str;
7654 int typeerr = FALSE;
7655 int maxcount;
7656 garray_T ga;
7657 int i;
7658 listitem_T *li;
7659 int need_capital = FALSE;
7660#endif
7661
7662 if (rettv_list_alloc(rettv) == FAIL)
7663 return;
7664
7665#ifdef FEAT_SPELL
7666 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7667 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007668 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007669 if (argvars[1].v_type != VAR_UNKNOWN)
7670 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007671 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 if (maxcount <= 0)
7673 return;
7674 if (argvars[2].v_type != VAR_UNKNOWN)
7675 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007676 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007677 if (typeerr)
7678 return;
7679 }
7680 }
7681 else
7682 maxcount = 25;
7683
7684 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7685
7686 for (i = 0; i < ga.ga_len; ++i)
7687 {
7688 str = ((char_u **)ga.ga_data)[i];
7689
7690 li = listitem_alloc();
7691 if (li == NULL)
7692 vim_free(str);
7693 else
7694 {
7695 li->li_tv.v_type = VAR_STRING;
7696 li->li_tv.v_lock = 0;
7697 li->li_tv.vval.v_string = str;
7698 list_append(rettv->vval.v_list, li);
7699 }
7700 }
7701 ga_clear(&ga);
7702 }
7703#endif
7704}
7705
7706 static void
7707f_split(typval_T *argvars, typval_T *rettv)
7708{
7709 char_u *str;
7710 char_u *end;
7711 char_u *pat = NULL;
7712 regmatch_T regmatch;
7713 char_u patbuf[NUMBUFLEN];
7714 char_u *save_cpo;
7715 int match;
7716 colnr_T col = 0;
7717 int keepempty = FALSE;
7718 int typeerr = FALSE;
7719
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007720 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007721 save_cpo = p_cpo;
7722 p_cpo = (char_u *)"";
7723
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007724 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725 if (argvars[1].v_type != VAR_UNKNOWN)
7726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007727 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728 if (pat == NULL)
7729 typeerr = TRUE;
7730 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007731 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007732 }
7733 if (pat == NULL || *pat == NUL)
7734 pat = (char_u *)"[\\x01- ]\\+";
7735
7736 if (rettv_list_alloc(rettv) == FAIL)
7737 return;
7738 if (typeerr)
7739 return;
7740
7741 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7742 if (regmatch.regprog != NULL)
7743 {
7744 regmatch.rm_ic = FALSE;
7745 while (*str != NUL || keepempty)
7746 {
7747 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007748 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749 else
7750 match = vim_regexec_nl(&regmatch, str, col);
7751 if (match)
7752 end = regmatch.startp[0];
7753 else
7754 end = str + STRLEN(str);
7755 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7756 && *str != NUL && match && end < regmatch.endp[0]))
7757 {
7758 if (list_append_string(rettv->vval.v_list, str,
7759 (int)(end - str)) == FAIL)
7760 break;
7761 }
7762 if (!match)
7763 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007764 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765 if (regmatch.endp[0] > str)
7766 col = 0;
7767 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007768 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007769 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770 str = regmatch.endp[0];
7771 }
7772
7773 vim_regfree(regmatch.regprog);
7774 }
7775
7776 p_cpo = save_cpo;
7777}
7778
7779#ifdef FEAT_FLOAT
7780/*
7781 * "sqrt()" function
7782 */
7783 static void
7784f_sqrt(typval_T *argvars, typval_T *rettv)
7785{
7786 float_T f = 0.0;
7787
7788 rettv->v_type = VAR_FLOAT;
7789 if (get_float_arg(argvars, &f) == OK)
7790 rettv->vval.v_float = sqrt(f);
7791 else
7792 rettv->vval.v_float = 0.0;
7793}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007794#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007796#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007797/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798 * "str2float()" function
7799 */
7800 static void
7801f_str2float(typval_T *argvars, typval_T *rettv)
7802{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007803 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007804 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805
Bram Moolenaar08243d22017-01-10 16:12:29 +01007806 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807 p = skipwhite(p + 1);
7808 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007809 if (isneg)
7810 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007811 rettv->v_type = VAR_FLOAT;
7812}
7813#endif
7814
7815/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007816 * "str2list()" function
7817 */
7818 static void
7819f_str2list(typval_T *argvars, typval_T *rettv)
7820{
7821 char_u *p;
7822 int utf8 = FALSE;
7823
7824 if (rettv_list_alloc(rettv) == FAIL)
7825 return;
7826
7827 if (argvars[1].v_type != VAR_UNKNOWN)
7828 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7829
7830 p = tv_get_string(&argvars[0]);
7831
7832 if (has_mbyte || utf8)
7833 {
7834 int (*ptr2len)(char_u *);
7835 int (*ptr2char)(char_u *);
7836
7837 if (utf8 || enc_utf8)
7838 {
7839 ptr2len = utf_ptr2len;
7840 ptr2char = utf_ptr2char;
7841 }
7842 else
7843 {
7844 ptr2len = mb_ptr2len;
7845 ptr2char = mb_ptr2char;
7846 }
7847
7848 for ( ; *p != NUL; p += (*ptr2len)(p))
7849 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7850 }
7851 else
7852 for ( ; *p != NUL; ++p)
7853 list_append_number(rettv->vval.v_list, *p);
7854}
7855
7856/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857 * "str2nr()" function
7858 */
7859 static void
7860f_str2nr(typval_T *argvars, typval_T *rettv)
7861{
7862 int base = 10;
7863 char_u *p;
7864 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007865 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007866 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867
7868 if (argvars[1].v_type != VAR_UNKNOWN)
7869 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007870 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871 if (base != 2 && base != 8 && base != 10 && base != 16)
7872 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007873 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 return;
7875 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007876 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7877 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007878 }
7879
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007880 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007881 isneg = (*p == '-');
7882 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007883 p = skipwhite(p + 1);
7884 switch (base)
7885 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007886 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02007887 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007888 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007889 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007890 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7891 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007892 if (isneg)
7893 rettv->vval.v_number = -n;
7894 else
7895 rettv->vval.v_number = n;
7896
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897}
7898
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007899/*
7900 * "strgetchar()" function
7901 */
7902 static void
7903f_strgetchar(typval_T *argvars, typval_T *rettv)
7904{
7905 char_u *str;
7906 int len;
7907 int error = FALSE;
7908 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007909 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910
7911 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007912 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007913 if (str == NULL)
7914 return;
7915 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007916 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007917 if (error)
7918 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007919
Bram Moolenaar13505972019-01-24 15:04:48 +01007920 while (charidx >= 0 && byteidx < len)
7921 {
7922 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007923 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007924 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7925 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007926 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007927 --charidx;
7928 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007929 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007930}
7931
7932/*
7933 * "stridx()" function
7934 */
7935 static void
7936f_stridx(typval_T *argvars, typval_T *rettv)
7937{
7938 char_u buf[NUMBUFLEN];
7939 char_u *needle;
7940 char_u *haystack;
7941 char_u *save_haystack;
7942 char_u *pos;
7943 int start_idx;
7944
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007945 needle = tv_get_string_chk(&argvars[1]);
7946 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007947 rettv->vval.v_number = -1;
7948 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007949 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950
7951 if (argvars[2].v_type != VAR_UNKNOWN)
7952 {
7953 int error = FALSE;
7954
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007955 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007956 if (error || start_idx >= (int)STRLEN(haystack))
7957 return;
7958 if (start_idx >= 0)
7959 haystack += start_idx;
7960 }
7961
7962 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7963 if (pos != NULL)
7964 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7965}
7966
7967/*
7968 * "string()" function
7969 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007970 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007971f_string(typval_T *argvars, typval_T *rettv)
7972{
7973 char_u *tofree;
7974 char_u numbuf[NUMBUFLEN];
7975
7976 rettv->v_type = VAR_STRING;
7977 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7978 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007979 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980 if (rettv->vval.v_string != NULL && tofree == NULL)
7981 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7982}
7983
7984/*
7985 * "strlen()" function
7986 */
7987 static void
7988f_strlen(typval_T *argvars, typval_T *rettv)
7989{
7990 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007991 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992}
7993
7994/*
7995 * "strchars()" function
7996 */
7997 static void
7998f_strchars(typval_T *argvars, typval_T *rettv)
7999{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008000 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008001 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002 varnumber_T len = 0;
8003 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004
8005 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008006 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008008 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 else
8010 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8012 while (*s != NUL)
8013 {
8014 func_mb_ptr2char_adv(&s);
8015 ++len;
8016 }
8017 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008018 }
8019}
8020
8021/*
8022 * "strdisplaywidth()" function
8023 */
8024 static void
8025f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8026{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008027 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008028 int col = 0;
8029
8030 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008031 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008032
8033 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8034}
8035
8036/*
8037 * "strwidth()" function
8038 */
8039 static void
8040f_strwidth(typval_T *argvars, typval_T *rettv)
8041{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008042 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008043
Bram Moolenaar13505972019-01-24 15:04:48 +01008044 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008045}
8046
8047/*
8048 * "strcharpart()" function
8049 */
8050 static void
8051f_strcharpart(typval_T *argvars, typval_T *rettv)
8052{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053 char_u *p;
8054 int nchar;
8055 int nbyte = 0;
8056 int charlen;
8057 int len = 0;
8058 int slen;
8059 int error = FALSE;
8060
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008061 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008062 slen = (int)STRLEN(p);
8063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008064 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008065 if (!error)
8066 {
8067 if (nchar > 0)
8068 while (nchar > 0 && nbyte < slen)
8069 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008070 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008071 --nchar;
8072 }
8073 else
8074 nbyte = nchar;
8075 if (argvars[2].v_type != VAR_UNKNOWN)
8076 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008077 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078 while (charlen > 0 && nbyte + len < slen)
8079 {
8080 int off = nbyte + len;
8081
8082 if (off < 0)
8083 len += 1;
8084 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008085 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 --charlen;
8087 }
8088 }
8089 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008090 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008091 }
8092
8093 /*
8094 * Only return the overlap between the specified part and the actual
8095 * string.
8096 */
8097 if (nbyte < 0)
8098 {
8099 len += nbyte;
8100 nbyte = 0;
8101 }
8102 else if (nbyte > slen)
8103 nbyte = slen;
8104 if (len < 0)
8105 len = 0;
8106 else if (nbyte + len > slen)
8107 len = slen - nbyte;
8108
8109 rettv->v_type = VAR_STRING;
8110 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111}
8112
8113/*
8114 * "strpart()" function
8115 */
8116 static void
8117f_strpart(typval_T *argvars, typval_T *rettv)
8118{
8119 char_u *p;
8120 int n;
8121 int len;
8122 int slen;
8123 int error = FALSE;
8124
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008125 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008126 slen = (int)STRLEN(p);
8127
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008128 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008129 if (error)
8130 len = 0;
8131 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008132 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008134 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008135
8136 /*
8137 * Only return the overlap between the specified part and the actual
8138 * string.
8139 */
8140 if (n < 0)
8141 {
8142 len += n;
8143 n = 0;
8144 }
8145 else if (n > slen)
8146 n = slen;
8147 if (len < 0)
8148 len = 0;
8149 else if (n + len > slen)
8150 len = slen - n;
8151
8152 rettv->v_type = VAR_STRING;
8153 rettv->vval.v_string = vim_strnsave(p + n, len);
8154}
8155
8156/*
8157 * "strridx()" function
8158 */
8159 static void
8160f_strridx(typval_T *argvars, typval_T *rettv)
8161{
8162 char_u buf[NUMBUFLEN];
8163 char_u *needle;
8164 char_u *haystack;
8165 char_u *rest;
8166 char_u *lastmatch = NULL;
8167 int haystack_len, end_idx;
8168
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008169 needle = tv_get_string_chk(&argvars[1]);
8170 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008171
8172 rettv->vval.v_number = -1;
8173 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008174 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008175
8176 haystack_len = (int)STRLEN(haystack);
8177 if (argvars[2].v_type != VAR_UNKNOWN)
8178 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008179 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008180 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008181 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008182 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008183 }
8184 else
8185 end_idx = haystack_len;
8186
8187 if (*needle == NUL)
8188 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008189 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 lastmatch = haystack + end_idx;
8191 }
8192 else
8193 {
8194 for (rest = haystack; *rest != '\0'; ++rest)
8195 {
8196 rest = (char_u *)strstr((char *)rest, (char *)needle);
8197 if (rest == NULL || rest > haystack + end_idx)
8198 break;
8199 lastmatch = rest;
8200 }
8201 }
8202
8203 if (lastmatch == NULL)
8204 rettv->vval.v_number = -1;
8205 else
8206 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8207}
8208
8209/*
8210 * "strtrans()" function
8211 */
8212 static void
8213f_strtrans(typval_T *argvars, typval_T *rettv)
8214{
8215 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008216 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008217}
8218
8219/*
8220 * "submatch()" function
8221 */
8222 static void
8223f_submatch(typval_T *argvars, typval_T *rettv)
8224{
8225 int error = FALSE;
8226 int no;
8227 int retList = 0;
8228
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008229 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008230 if (error)
8231 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008232 if (no < 0 || no >= NSUBEXP)
8233 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008234 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008235 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008236 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008237 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008238 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239 if (error)
8240 return;
8241
8242 if (retList == 0)
8243 {
8244 rettv->v_type = VAR_STRING;
8245 rettv->vval.v_string = reg_submatch(no);
8246 }
8247 else
8248 {
8249 rettv->v_type = VAR_LIST;
8250 rettv->vval.v_list = reg_submatch_list(no);
8251 }
8252}
8253
8254/*
8255 * "substitute()" function
8256 */
8257 static void
8258f_substitute(typval_T *argvars, typval_T *rettv)
8259{
8260 char_u patbuf[NUMBUFLEN];
8261 char_u subbuf[NUMBUFLEN];
8262 char_u flagsbuf[NUMBUFLEN];
8263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008264 char_u *str = tv_get_string_chk(&argvars[0]);
8265 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008266 char_u *sub = NULL;
8267 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008268 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008269
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008270 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8271 expr = &argvars[2];
8272 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008273 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008274
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008275 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008276 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8277 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008278 rettv->vval.v_string = NULL;
8279 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008280 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281}
8282
8283/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008284 * "swapinfo(swap_filename)" function
8285 */
8286 static void
8287f_swapinfo(typval_T *argvars, typval_T *rettv)
8288{
8289 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008290 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008291}
8292
8293/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008294 * "swapname(expr)" function
8295 */
8296 static void
8297f_swapname(typval_T *argvars, typval_T *rettv)
8298{
8299 buf_T *buf;
8300
8301 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008302 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008303 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8304 || buf->b_ml.ml_mfp->mf_fname == NULL)
8305 rettv->vval.v_string = NULL;
8306 else
8307 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8308}
8309
8310/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008311 * "synID(lnum, col, trans)" function
8312 */
8313 static void
8314f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8315{
8316 int id = 0;
8317#ifdef FEAT_SYN_HL
8318 linenr_T lnum;
8319 colnr_T col;
8320 int trans;
8321 int transerr = FALSE;
8322
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008323 lnum = tv_get_lnum(argvars); // -1 on type error
8324 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008325 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008326
8327 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8328 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8329 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8330#endif
8331
8332 rettv->vval.v_number = id;
8333}
8334
8335/*
8336 * "synIDattr(id, what [, mode])" function
8337 */
8338 static void
8339f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8340{
8341 char_u *p = NULL;
8342#ifdef FEAT_SYN_HL
8343 int id;
8344 char_u *what;
8345 char_u *mode;
8346 char_u modebuf[NUMBUFLEN];
8347 int modec;
8348
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008349 id = (int)tv_get_number(&argvars[0]);
8350 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008351 if (argvars[2].v_type != VAR_UNKNOWN)
8352 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008353 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008354 modec = TOLOWER_ASC(mode[0]);
8355 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008356 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008357 }
8358 else
8359 {
8360#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8361 if (USE_24BIT)
8362 modec = 'g';
8363 else
8364#endif
8365 if (t_colors > 1)
8366 modec = 'c';
8367 else
8368 modec = 't';
8369 }
8370
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371 switch (TOLOWER_ASC(what[0]))
8372 {
8373 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008374 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008375 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008376 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008377 p = highlight_has_attr(id, HL_BOLD, modec);
8378 break;
8379
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008380 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008381 p = highlight_color(id, what, modec);
8382 break;
8383
8384 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008385 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008387 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 p = highlight_has_attr(id, HL_ITALIC, modec);
8389 break;
8390
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008391 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008392 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008393 break;
8394
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008395 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008396 p = highlight_has_attr(id, HL_INVERSE, modec);
8397 break;
8398
8399 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008400 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008401 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008402 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008403 else if (TOLOWER_ASC(what[1]) == 't' &&
8404 TOLOWER_ASC(what[2]) == 'r')
8405 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008406 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008407 p = highlight_has_attr(id, HL_STANDOUT, modec);
8408 break;
8409
8410 case 'u':
8411 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008412 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008413 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8414 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008415 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008416 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8417 break;
8418 }
8419
8420 if (p != NULL)
8421 p = vim_strsave(p);
8422#endif
8423 rettv->v_type = VAR_STRING;
8424 rettv->vval.v_string = p;
8425}
8426
8427/*
8428 * "synIDtrans(id)" function
8429 */
8430 static void
8431f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8432{
8433 int id;
8434
8435#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008436 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008437
8438 if (id > 0)
8439 id = syn_get_final_id(id);
8440 else
8441#endif
8442 id = 0;
8443
8444 rettv->vval.v_number = id;
8445}
8446
8447/*
8448 * "synconcealed(lnum, col)" function
8449 */
8450 static void
8451f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8452{
8453#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8454 linenr_T lnum;
8455 colnr_T col;
8456 int syntax_flags = 0;
8457 int cchar;
8458 int matchid = 0;
8459 char_u str[NUMBUFLEN];
8460#endif
8461
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008462 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463
8464#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008465 lnum = tv_get_lnum(argvars); // -1 on type error
8466 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008467
Bram Moolenaara80faa82020-04-12 19:37:17 +02008468 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008469
8470 if (rettv_list_alloc(rettv) != FAIL)
8471 {
8472 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8473 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8474 && curwin->w_p_cole > 0)
8475 {
8476 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8477 syntax_flags = get_syntax_info(&matchid);
8478
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008479 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8481 {
8482 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008483 if (cchar == NUL && curwin->w_p_cole == 1)
8484 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008485 if (cchar != NUL)
8486 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008487 if (has_mbyte)
8488 (*mb_char2bytes)(cchar, str);
8489 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490 str[0] = cchar;
8491 }
8492 }
8493 }
8494
8495 list_append_number(rettv->vval.v_list,
8496 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008497 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008498 list_append_string(rettv->vval.v_list, str, -1);
8499 list_append_number(rettv->vval.v_list, matchid);
8500 }
8501#endif
8502}
8503
8504/*
8505 * "synstack(lnum, col)" function
8506 */
8507 static void
8508f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8509{
8510#ifdef FEAT_SYN_HL
8511 linenr_T lnum;
8512 colnr_T col;
8513 int i;
8514 int id;
8515#endif
8516
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008517 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008518
8519#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008520 lnum = tv_get_lnum(argvars); // -1 on type error
8521 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008522
8523 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8524 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8525 && rettv_list_alloc(rettv) != FAIL)
8526 {
8527 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8528 for (i = 0; ; ++i)
8529 {
8530 id = syn_get_stack_item(i);
8531 if (id < 0)
8532 break;
8533 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8534 break;
8535 }
8536 }
8537#endif
8538}
8539
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008540/*
8541 * "tabpagebuflist()" function
8542 */
8543 static void
8544f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8545{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008546 tabpage_T *tp;
8547 win_T *wp = NULL;
8548
8549 if (argvars[0].v_type == VAR_UNKNOWN)
8550 wp = firstwin;
8551 else
8552 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008553 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008554 if (tp != NULL)
8555 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8556 }
8557 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8558 {
8559 for (; wp != NULL; wp = wp->w_next)
8560 if (list_append_number(rettv->vval.v_list,
8561 wp->w_buffer->b_fnum) == FAIL)
8562 break;
8563 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008564}
8565
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008566/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008567 * "tagfiles()" function
8568 */
8569 static void
8570f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8571{
8572 char_u *fname;
8573 tagname_T tn;
8574 int first;
8575
8576 if (rettv_list_alloc(rettv) == FAIL)
8577 return;
8578 fname = alloc(MAXPATHL);
8579 if (fname == NULL)
8580 return;
8581
8582 for (first = TRUE; ; first = FALSE)
8583 if (get_tagfname(&tn, first, fname) == FAIL
8584 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8585 break;
8586 tagname_free(&tn);
8587 vim_free(fname);
8588}
8589
8590/*
8591 * "taglist()" function
8592 */
8593 static void
8594f_taglist(typval_T *argvars, typval_T *rettv)
8595{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008596 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008597 char_u *tag_pattern;
8598
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008599 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008600
8601 rettv->vval.v_number = FALSE;
8602 if (*tag_pattern == NUL)
8603 return;
8604
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008605 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008606 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008608 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008609}
8610
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008611#ifdef FEAT_FLOAT
8612/*
8613 * "tan()" function
8614 */
8615 static void
8616f_tan(typval_T *argvars, typval_T *rettv)
8617{
8618 float_T f = 0.0;
8619
8620 rettv->v_type = VAR_FLOAT;
8621 if (get_float_arg(argvars, &f) == OK)
8622 rettv->vval.v_float = tan(f);
8623 else
8624 rettv->vval.v_float = 0.0;
8625}
8626
8627/*
8628 * "tanh()" function
8629 */
8630 static void
8631f_tanh(typval_T *argvars, typval_T *rettv)
8632{
8633 float_T f = 0.0;
8634
8635 rettv->v_type = VAR_FLOAT;
8636 if (get_float_arg(argvars, &f) == OK)
8637 rettv->vval.v_float = tanh(f);
8638 else
8639 rettv->vval.v_float = 0.0;
8640}
8641#endif
8642
8643/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644 * "tolower(string)" function
8645 */
8646 static void
8647f_tolower(typval_T *argvars, typval_T *rettv)
8648{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008649 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008650 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008651}
8652
8653/*
8654 * "toupper(string)" function
8655 */
8656 static void
8657f_toupper(typval_T *argvars, typval_T *rettv)
8658{
8659 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008660 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008661}
8662
8663/*
8664 * "tr(string, fromstr, tostr)" function
8665 */
8666 static void
8667f_tr(typval_T *argvars, typval_T *rettv)
8668{
8669 char_u *in_str;
8670 char_u *fromstr;
8671 char_u *tostr;
8672 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008673 int inlen;
8674 int fromlen;
8675 int tolen;
8676 int idx;
8677 char_u *cpstr;
8678 int cplen;
8679 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008680 char_u buf[NUMBUFLEN];
8681 char_u buf2[NUMBUFLEN];
8682 garray_T ga;
8683
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008684 in_str = tv_get_string(&argvars[0]);
8685 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8686 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008687
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008688 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689 rettv->v_type = VAR_STRING;
8690 rettv->vval.v_string = NULL;
8691 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008692 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008693 ga_init2(&ga, (int)sizeof(char), 80);
8694
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008695 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008696 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008697 if (STRLEN(fromstr) != STRLEN(tostr))
8698 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008699error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008700 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008701 ga_clear(&ga);
8702 return;
8703 }
8704
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008705 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008706 while (*in_str != NUL)
8707 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008708 if (has_mbyte)
8709 {
8710 inlen = (*mb_ptr2len)(in_str);
8711 cpstr = in_str;
8712 cplen = inlen;
8713 idx = 0;
8714 for (p = fromstr; *p != NUL; p += fromlen)
8715 {
8716 fromlen = (*mb_ptr2len)(p);
8717 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8718 {
8719 for (p = tostr; *p != NUL; p += tolen)
8720 {
8721 tolen = (*mb_ptr2len)(p);
8722 if (idx-- == 0)
8723 {
8724 cplen = tolen;
8725 cpstr = p;
8726 break;
8727 }
8728 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008729 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008730 goto error;
8731 break;
8732 }
8733 ++idx;
8734 }
8735
8736 if (first && cpstr == in_str)
8737 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008738 // Check that fromstr and tostr have the same number of
8739 // (multi-byte) characters. Done only once when a character
8740 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008741 first = FALSE;
8742 for (p = tostr; *p != NUL; p += tolen)
8743 {
8744 tolen = (*mb_ptr2len)(p);
8745 --idx;
8746 }
8747 if (idx != 0)
8748 goto error;
8749 }
8750
8751 (void)ga_grow(&ga, cplen);
8752 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8753 ga.ga_len += cplen;
8754
8755 in_str += inlen;
8756 }
8757 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008758 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008759 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008760 p = vim_strchr(fromstr, *in_str);
8761 if (p != NULL)
8762 ga_append(&ga, tostr[p - fromstr]);
8763 else
8764 ga_append(&ga, *in_str);
8765 ++in_str;
8766 }
8767 }
8768
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008769 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008770 (void)ga_grow(&ga, 1);
8771 ga_append(&ga, NUL);
8772
8773 rettv->vval.v_string = ga.ga_data;
8774}
8775
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008776/*
8777 * "trim({expr})" function
8778 */
8779 static void
8780f_trim(typval_T *argvars, typval_T *rettv)
8781{
8782 char_u buf1[NUMBUFLEN];
8783 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008784 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008785 char_u *mask = NULL;
8786 char_u *tail;
8787 char_u *prev;
8788 char_u *p;
8789 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008790 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008791
8792 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008793 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008794 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008795 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008796
8797 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008798 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008799 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008800
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008801 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008802 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008803 int error = 0;
8804
8805 // leading or trailing characters to trim
8806 dir = (int)tv_get_number_chk(&argvars[2], &error);
8807 if (error)
8808 return;
8809 if (dir < 0 || dir > 2)
8810 {
8811 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8812 return;
8813 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008814 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008815 }
8816
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008817 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008818 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008819 // Trim leading characters
8820 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008821 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008822 c1 = PTR2CHAR(head);
8823 if (mask == NULL)
8824 {
8825 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008826 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008827 }
8828 else
8829 {
8830 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8831 if (c1 == PTR2CHAR(p))
8832 break;
8833 if (*p == NUL)
8834 break;
8835 }
8836 MB_PTR_ADV(head);
8837 }
8838 }
8839
8840 tail = head + STRLEN(head);
8841 if (dir == 0 || dir == 2)
8842 {
8843 // Trim trailing characters
8844 for (; tail > head; tail = prev)
8845 {
8846 prev = tail;
8847 MB_PTR_BACK(head, prev);
8848 c1 = PTR2CHAR(prev);
8849 if (mask == NULL)
8850 {
8851 if (c1 > ' ' && c1 != 0xa0)
8852 break;
8853 }
8854 else
8855 {
8856 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8857 if (c1 == PTR2CHAR(p))
8858 break;
8859 if (*p == NUL)
8860 break;
8861 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008862 }
8863 }
8864 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8865}
8866
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008867#ifdef FEAT_FLOAT
8868/*
8869 * "trunc({float})" function
8870 */
8871 static void
8872f_trunc(typval_T *argvars, typval_T *rettv)
8873{
8874 float_T f = 0.0;
8875
8876 rettv->v_type = VAR_FLOAT;
8877 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008878 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008879 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8880 else
8881 rettv->vval.v_float = 0.0;
8882}
8883#endif
8884
8885/*
8886 * "type(expr)" function
8887 */
8888 static void
8889f_type(typval_T *argvars, typval_T *rettv)
8890{
8891 int n = -1;
8892
8893 switch (argvars[0].v_type)
8894 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008895 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8896 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008897 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008898 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8899 case VAR_LIST: n = VAR_TYPE_LIST; break;
8900 case VAR_DICT: n = VAR_TYPE_DICT; break;
8901 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8902 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8903 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008904 case VAR_JOB: n = VAR_TYPE_JOB; break;
8905 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008906 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008907 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02008908 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008909 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008910 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008911 n = -1;
8912 break;
8913 }
8914 rettv->vval.v_number = n;
8915}
8916
8917/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008918 * "virtcol(string)" function
8919 */
8920 static void
8921f_virtcol(typval_T *argvars, typval_T *rettv)
8922{
8923 colnr_T vcol = 0;
8924 pos_T *fp;
8925 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008926 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008927
8928 fp = var2fpos(&argvars[0], FALSE, &fnum);
8929 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8930 && fnum == curbuf->b_fnum)
8931 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008932 // Limit the column to a valid value, getvvcol() doesn't check.
8933 if (fp->col < 0)
8934 fp->col = 0;
8935 else
8936 {
8937 len = (int)STRLEN(ml_get(fp->lnum));
8938 if (fp->col > len)
8939 fp->col = len;
8940 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008941 getvvcol(curwin, fp, NULL, NULL, &vcol);
8942 ++vcol;
8943 }
8944
8945 rettv->vval.v_number = vcol;
8946}
8947
8948/*
8949 * "visualmode()" function
8950 */
8951 static void
8952f_visualmode(typval_T *argvars, typval_T *rettv)
8953{
8954 char_u str[2];
8955
8956 rettv->v_type = VAR_STRING;
8957 str[0] = curbuf->b_visual_mode_eval;
8958 str[1] = NUL;
8959 rettv->vval.v_string = vim_strsave(str);
8960
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008961 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008962 if (non_zero_arg(&argvars[0]))
8963 curbuf->b_visual_mode_eval = NUL;
8964}
8965
8966/*
8967 * "wildmenumode()" function
8968 */
8969 static void
8970f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8971{
8972#ifdef FEAT_WILDMENU
8973 if (wild_menu_showing)
8974 rettv->vval.v_number = 1;
8975#endif
8976}
8977
8978/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008979 * "windowsversion()" function
8980 */
8981 static void
8982f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8983{
8984 rettv->v_type = VAR_STRING;
8985 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8986}
8987
8988/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008989 * "wordcount()" function
8990 */
8991 static void
8992f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8993{
8994 if (rettv_dict_alloc(rettv) == FAIL)
8995 return;
8996 cursor_pos_info(rettv->vval.v_dict);
8997}
8998
8999/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009000 * "xor(expr, expr)" function
9001 */
9002 static void
9003f_xor(typval_T *argvars, typval_T *rettv)
9004{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009005 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9006 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009007}
9008
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009009#endif // FEAT_EVAL