blob: 53584dc46a257d6a667915ecbafdce3295a70ef0 [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
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200342 static type_T *
343ret_first_arg(int argcount, type_T **argtypes)
344{
345 if (argcount > 0)
346 return argtypes[0];
347 return &t_void;
348}
349
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100350static type_T *ret_f_function(int argcount, type_T **argtypes);
351
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352/*
353 * Array with names and number of arguments of all internal functions
354 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
355 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200356typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200358 char *f_name; // function name
359 char f_min_argc; // minimal number of arguments
360 char f_max_argc; // maximal number of arguments
361 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100362 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
363 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200364 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200365 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200366} funcentry_T;
367
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200368// values for f_argtype; zero means it cannot be used as a method
369#define FEARG_1 1 // base is the first argument
370#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200371#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200372#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200373#define FEARG_LAST 9 // base is the last argument
374
Bram Moolenaar15c47602020-03-26 22:16:48 +0100375#ifdef FEAT_FLOAT
376# define FLOAT_FUNC(name) name
377#else
378# define FLOAT_FUNC(name) NULL
379#endif
380#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
381# define MATH_FUNC(name) name
382#else
383# define MATH_FUNC(name) NULL
384#endif
385#ifdef FEAT_TIMERS
386# define TIMER_FUNC(name) name
387#else
388# define TIMER_FUNC(name) NULL
389#endif
390#ifdef FEAT_JOB_CHANNEL
391# define JOB_FUNC(name) name
392#else
393# define JOB_FUNC(name) NULL
394#endif
395#ifdef FEAT_PROP_POPUP
396# define PROP_FUNC(name) name
397#else
398# define PROP_FUNC(name) NULL
399#endif
400#ifdef FEAT_SIGNS
401# define SIGN_FUNC(name) name
402#else
403# define SIGN_FUNC(name) NULL
404#endif
405#ifdef FEAT_SOUND
406# define SOUND_FUNC(name) name
407#else
408# define SOUND_FUNC(name) NULL
409#endif
410#ifdef FEAT_TERMINAL
411# define TERM_FUNC(name) name
412#else
413# define TERM_FUNC(name) NULL
414#endif
415
Bram Moolenaarac92e252019-08-03 21:58:38 +0200416static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200417{
Bram Moolenaar15c47602020-03-26 22:16:48 +0100418 {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)},
419 {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100420 {"add", 2, 2, FEARG_1, ret_any, f_add},
421 {"and", 2, 2, FEARG_1, ret_number, f_and},
422 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
423 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
424 {"argc", 0, 1, 0, ret_number, f_argc},
425 {"argidx", 0, 0, 0, ret_number, f_argidx},
426 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
427 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100428 {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100429 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
430 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
Bram Moolenaarfb517ba2020-06-03 19:55:35 +0200431 {"assert_equalfile", 2, 3, FEARG_1, ret_number, f_assert_equalfile},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100432 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
433 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
434 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
435 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
436 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
437 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
438 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
439 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
440 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100441 {"atan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_atan)},
442 {"atan2", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_atan2)},
443 {"balloon_gettext", 0, 0, 0, ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100444#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100445 f_balloon_gettext
446#else
447 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100448#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100449 },
450 {"balloon_show", 1, 1, FEARG_1, ret_void,
451#ifdef FEAT_BEVAL
452 f_balloon_show
453#else
454 NULL
455#endif
456 },
457 {"balloon_split", 1, 1, FEARG_1, ret_list_string,
458#if defined(FEAT_BEVAL_TERM)
459 f_balloon_split
460#else
461 NULL
462#endif
463 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100464 {"browse", 4, 4, 0, ret_string, f_browse},
465 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
466 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
467 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
468 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
469 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
470 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
471 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
472 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
473 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
474 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
475 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
476 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
477 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
478 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
479 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
480 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
481 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100482 {"ceil", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_ceil)},
483 {"ch_canread", 1, 1, FEARG_1, ret_number, JOB_FUNC(f_ch_canread)},
484 {"ch_close", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close)},
485 {"ch_close_in", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close_in)},
486 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalexpr)},
487 {"ch_evalraw", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalraw)},
488 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, JOB_FUNC(f_ch_getbufnr)},
489 {"ch_getjob", 1, 1, FEARG_1, ret_job, JOB_FUNC(f_ch_getjob)},
490 {"ch_info", 1, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_ch_info)},
491 {"ch_log", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_log)},
492 {"ch_logfile", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_logfile)},
493 {"ch_open", 1, 2, FEARG_1, ret_channel, JOB_FUNC(f_ch_open)},
494 {"ch_read", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_read)},
495 {"ch_readblob", 1, 2, FEARG_1, ret_blob, JOB_FUNC(f_ch_readblob)},
496 {"ch_readraw", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_readraw)},
497 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendexpr)},
498 {"ch_sendraw", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendraw)},
499 {"ch_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_setoptions)},
500 {"ch_status", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_status)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100501 {"changenr", 0, 0, 0, ret_number, f_changenr},
502 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
503 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
504 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
505 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
506 {"col", 1, 1, FEARG_1, ret_number, f_col},
507 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
508 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
509 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
510 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
511 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
512 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100513 {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)},
514 {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100515 {"count", 2, 4, FEARG_1, ret_number, f_count},
516 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
517 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100518 {"debugbreak", 1, 1, FEARG_1, ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100519#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100520 f_debugbreak
521#else
522 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200523#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100524 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100525 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
526 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
527 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
528 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
529 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
530 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
531 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
532 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
533 {"environ", 0, 0, 0, ret_dict_string, f_environ},
534 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
535 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
536 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
537 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
538 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
539 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
540 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100541 {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100542 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
543 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
544 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
545 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
546 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
547 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
548 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
549 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
550 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
551 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar077a1e62020-06-08 20:50:43 +0200552 {"flatten", 1, 2, FEARG_1, ret_list_any, f_flatten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100553 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)},
554 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)},
555 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100556 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
557 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
558 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
559 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
560 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
561 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
562 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
563 {"foreground", 0, 0, 0, ret_void, f_foreground},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200564 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100565 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
566 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
567 {"get", 2, 3, FEARG_1, ret_any, f_get},
568 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
569 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
570 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
571 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
572 {"getchar", 0, 1, 0, ret_number, f_getchar},
573 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
574 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
575 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
576 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
577 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
578 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
579 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
580 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
581 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
582 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
583 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
584 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
585 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
586 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
587 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
588 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
589 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
590 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
591 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +0200592 {"getmarklist", 0, 1, FEARG_1, ret_list_dict_any, f_getmarklist},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100593 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
594 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
595 {"getpid", 0, 0, 0, ret_number, f_getpid},
596 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
597 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
598 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
Bram Moolenaarbb861e22020-06-07 18:16:36 +0200599 {"getreginfo", 0, 1, FEARG_1, ret_dict_any, f_getreginfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
601 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
602 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
603 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
604 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
605 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
606 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
607 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
608 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
609 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
610 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
611 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
612 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100613 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100614 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
615 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
616 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
617 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
618 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
619 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
620 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
621 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
622 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
623 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
624 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
625 {"hostname", 0, 0, 0, ret_string, f_hostname},
626 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
627 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
628 {"index", 2, 4, FEARG_1, ret_number, f_index},
629 {"input", 1, 3, FEARG_1, ret_string, f_input},
630 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
631 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
632 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
633 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
634 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
635 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
636 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
637 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
638 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100639 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100640 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100641 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100642 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100643 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
644 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
645 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
646 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
647 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
648 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100649 {"join", 1, 2, FEARG_1, ret_string, f_join},
650 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
651 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
652 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
653 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
654 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
655 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
656 {"len", 1, 1, FEARG_1, ret_number, f_len},
657 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
658 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
659 {"line", 1, 2, FEARG_1, ret_number, f_line},
660 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
661 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
662 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
663 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
664 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
665 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
666 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100667 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
668 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
669 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200670#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100671 f_luaeval
672#else
673 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200674#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100675 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100676 {"map", 2, 2, FEARG_1, ret_any, f_map},
677 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
678 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200679 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100680 {"match", 2, 4, FEARG_1, ret_any, f_match},
681 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
682 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
683 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
684 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
685 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
686 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
687 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
688 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
689 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100690 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100691#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100692 f_menu_info
693#else
694 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100695#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100696 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100697 {"min", 1, 1, FEARG_1, ret_any, f_min},
698 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
699 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100700 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200701#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100702 f_mzeval
703#else
704 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200705#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100706 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100707 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
708 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
709 {"or", 2, 2, FEARG_1, ret_number, f_or},
710 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100711 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200712#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100713 f_perleval
714#else
715 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200716#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100717 },
718 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
719 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200720 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100721 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
722 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
723 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
724 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)},
725 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)},
726 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
727 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
728 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
729 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
730 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200731 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100732 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
733 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
734 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
735 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
736 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
737 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
738 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
739 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100740 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
741 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100742 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
743 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
744 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
745 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
746 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
747 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
748 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
749 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
750 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
751 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
752 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
753 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
754 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100755 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
756 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100757 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200758#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100759 f_py3eval
760#else
761 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100763 },
764 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200765#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100766 f_pyeval
767#else
768 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200769#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100770 },
771 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100772#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100773 f_pyxeval
774#else
775 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100776#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100777 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100778 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
779 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +0200780 {"readdir", 1, 3, FEARG_1, ret_list_string, f_readdir},
781 {"readdirex", 1, 3, FEARG_1, ret_list_dict_any, f_readdirex},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100782 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
Bram Moolenaar85629982020-06-01 18:39:20 +0200783 {"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100784 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
785 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
786 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100787 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100788 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
789 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
790 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
791 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
792 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
793 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
794 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
795 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
796 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
797 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
798 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
799 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100800 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
801 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100802#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100803 f_rubyeval
804#else
805 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100806#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100807 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100808 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
809 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
810 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
811 {"screencol", 0, 0, 0, ret_number, f_screencol},
812 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
813 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
814 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200815 {"search", 1, 5, FEARG_1, ret_number, f_search},
Bram Moolenaare8f5ec02020-06-01 17:28:35 +0200816 {"searchcount", 0, 1, FEARG_1, ret_dict_any, f_searchcount},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100817 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
818 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
819 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200820 {"searchpos", 1, 5, FEARG_1, ret_list_number, f_searchpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100821 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
822 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
823 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
824 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
825 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
826 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
827 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
828 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
829 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
830 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
831 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
832 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
833 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
834 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
835 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
836 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
837 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
838 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100839 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200840#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100841 f_sha256
842#else
843 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200844#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100845 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100846 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
847 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100848 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
849 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
850 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
851 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
852 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
853 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
854 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
855 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
856 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200857 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100858 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
859 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200860 {"sort", 1, 3, FEARG_1, ret_first_arg, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100861 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
862 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
863 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
864 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100865 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
866 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
867 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
868 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100869 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100870 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
871 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100872 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100873 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
874 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
875 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
876 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
877 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100878 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200879#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100880 f_strftime
881#else
882 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100884 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100885 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
886 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
887 {"string", 1, 1, FEARG_1, ret_string, f_string},
888 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
889 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100890 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100891#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100892 f_strptime
893#else
894 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100895#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100896 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100897 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
898 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
899 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
900 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
901 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
902 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
903 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
904 {"synID", 3, 3, 0, ret_number, f_synID},
905 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
906 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
907 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
908 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
909 {"system", 1, 2, FEARG_1, ret_string, f_system},
910 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
911 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
912 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
913 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
914 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
915 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100916 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
917 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100918 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100919 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
920 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
921 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
922 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
923 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100924#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100925 f_term_getansicolors
926#else
927 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200928#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100929 },
930 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
931 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
932 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
933 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
934 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
935 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
936 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
937 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
938 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
939 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
940 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
941 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
942 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100943#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100944 f_term_setansicolors
945#else
946 NULL
947#endif
948 },
949 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
950 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
951 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
952 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
953 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
954 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaar0c0eddd2020-06-13 15:47:25 +0200955 {"terminalprops", 0, 0, 0, ret_dict_string, f_terminalprops},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100956 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
957 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
958 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
959 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
960 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
961 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
962 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
963 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100964 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100965 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200966 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100967 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100968 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200969 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100970 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
971 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
972 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
973 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100974 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +0200975#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +0100976 f_test_scrollbar
977#else
978 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +0200979#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100980 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100981 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
982 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
983 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
984 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
985 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100986 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
987 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
988 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
989 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
990 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100991 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
992 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
993 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +0200994 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100995 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100996 {"type", 1, 1, FEARG_1, ret_number, f_type},
997 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
998 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
999 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
1000 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
1001 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
1002 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
1003 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
1004 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
1005 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
1006 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
1007 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
1008 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
1009 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
1010 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
1011 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
1012 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
1013 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
1014 {"wincol", 0, 0, 0, ret_number, f_wincol},
1015 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1016 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1017 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1018 {"winline", 0, 0, 0, ret_number, f_winline},
1019 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1020 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1021 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1022 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1023 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1024 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1025 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1026 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001027};
1028
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001029/*
1030 * Function given to ExpandGeneric() to obtain the list of internal
1031 * or user defined function names.
1032 */
1033 char_u *
1034get_function_name(expand_T *xp, int idx)
1035{
1036 static int intidx = -1;
1037 char_u *name;
1038
1039 if (idx == 0)
1040 intidx = -1;
1041 if (intidx < 0)
1042 {
1043 name = get_user_func_name(xp, idx);
1044 if (name != NULL)
1045 return name;
1046 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001047 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001048 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001049 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001050 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001051 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001052 STRCAT(IObuff, ")");
1053 return IObuff;
1054 }
1055
1056 return NULL;
1057}
1058
1059/*
1060 * Function given to ExpandGeneric() to obtain the list of internal or
1061 * user defined variable or function names.
1062 */
1063 char_u *
1064get_expr_name(expand_T *xp, int idx)
1065{
1066 static int intidx = -1;
1067 char_u *name;
1068
1069 if (idx == 0)
1070 intidx = -1;
1071 if (intidx < 0)
1072 {
1073 name = get_function_name(xp, idx);
1074 if (name != NULL)
1075 return name;
1076 }
1077 return get_user_var_name(xp, ++intidx);
1078}
1079
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001081 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001082 * Return index, or -1 if not found or "implemented" is TRUE and the function
1083 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001084 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001085 static int
1086find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001087{
1088 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001089 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001090 int cmp;
1091 int x;
1092
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001093 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001094
1095 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001096 while (first <= last)
1097 {
1098 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001099 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001100 if (cmp < 0)
1101 last = x - 1;
1102 else if (cmp > 0)
1103 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001104 else if (implemented && global_functions[x].f_func == NULL)
1105 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001106 else
1107 return x;
1108 }
1109 return -1;
1110}
1111
Bram Moolenaar15c47602020-03-26 22:16:48 +01001112/*
1113 * Find internal function "name" in table "global_functions".
1114 * Return index, or -1 if not found or the function is not implemented.
1115 */
1116 int
1117find_internal_func(char_u *name)
1118{
1119 return find_internal_func_opt(name, TRUE);
1120}
1121
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001122 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001123has_internal_func(char_u *name)
1124{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001125 return find_internal_func_opt(name, TRUE) >= 0;
1126}
1127
1128 static int
1129has_internal_func_name(char_u *name)
1130{
1131 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001132}
1133
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001134 char *
1135internal_func_name(int idx)
1136{
1137 return global_functions[idx].f_name;
1138}
1139
1140 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001141internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001142{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001143 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001144}
1145
1146/*
1147 * Check the argument count to use for internal function "idx".
1148 * Returns OK or FAIL;
1149 */
1150 int
1151check_internal_func(int idx, int argcount)
1152{
1153 int res;
1154 char *name;
1155
1156 if (argcount < global_functions[idx].f_min_argc)
1157 res = FCERR_TOOFEW;
1158 else if (argcount > global_functions[idx].f_max_argc)
1159 res = FCERR_TOOMANY;
1160 else
1161 return OK;
1162
1163 name = internal_func_name(idx);
1164 if (res == FCERR_TOOMANY)
1165 semsg(_(e_toomanyarg), name);
1166 else
1167 semsg(_(e_toofewarg), name);
1168 return FAIL;
1169}
1170
Bram Moolenaarac92e252019-08-03 21:58:38 +02001171 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001172call_internal_func(
1173 char_u *name,
1174 int argcount,
1175 typval_T *argvars,
1176 typval_T *rettv)
1177{
1178 int i;
1179
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001180 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001181 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001182 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001183 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001184 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001185 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001186 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001187 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001188 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001189 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001190}
1191
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001192 void
1193call_internal_func_by_idx(
1194 int idx,
1195 typval_T *argvars,
1196 typval_T *rettv)
1197{
1198 global_functions[idx].f_func(argvars, rettv);
1199}
1200
Bram Moolenaarac92e252019-08-03 21:58:38 +02001201/*
1202 * Invoke a method for base->method().
1203 */
1204 int
1205call_internal_method(
1206 char_u *name,
1207 int argcount,
1208 typval_T *argvars,
1209 typval_T *rettv,
1210 typval_T *basetv)
1211{
1212 int i;
1213 int fi;
1214 typval_T argv[MAX_FUNC_ARGS + 1];
1215
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001216 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001217 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001218 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001219 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001220 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001221 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001222 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001223 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001224 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001225
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001226 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001227 {
1228 // base value goes last
1229 for (i = 0; i < argcount; ++i)
1230 argv[i] = argvars[i];
1231 argv[argcount] = *basetv;
1232 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001233 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001234 {
1235 // base value goes second
1236 argv[0] = argvars[0];
1237 argv[1] = *basetv;
1238 for (i = 1; i < argcount; ++i)
1239 argv[i + 1] = argvars[i];
1240 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001241 else if (global_functions[fi].f_argtype == FEARG_3)
1242 {
1243 // base value goes third
1244 argv[0] = argvars[0];
1245 argv[1] = argvars[1];
1246 argv[2] = *basetv;
1247 for (i = 2; i < argcount; ++i)
1248 argv[i + 1] = argvars[i];
1249 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001250 else if (global_functions[fi].f_argtype == FEARG_4)
1251 {
1252 // base value goes fourth
1253 argv[0] = argvars[0];
1254 argv[1] = argvars[1];
1255 argv[2] = argvars[2];
1256 argv[3] = *basetv;
1257 for (i = 3; i < argcount; ++i)
1258 argv[i + 1] = argvars[i];
1259 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001260 else
1261 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001262 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001263 argv[0] = *basetv;
1264 for (i = 0; i < argcount; ++i)
1265 argv[i + 1] = argvars[i];
1266 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001267 argv[argcount + 1].v_type = VAR_UNKNOWN;
1268
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001269 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001270 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001271}
1272
1273/*
1274 * Return TRUE for a non-zero Number and a non-empty String.
1275 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001276 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001277non_zero_arg(typval_T *argvars)
1278{
1279 return ((argvars[0].v_type == VAR_NUMBER
1280 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001281 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001282 && argvars[0].vval.v_number == VVAL_TRUE)
1283 || (argvars[0].v_type == VAR_STRING
1284 && argvars[0].vval.v_string != NULL
1285 && *argvars[0].vval.v_string != NUL));
1286}
1287
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001288#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001289/*
1290 * Get the float value of "argvars[0]" into "f".
1291 * Returns FAIL when the argument is not a Number or Float.
1292 */
1293 static int
1294get_float_arg(typval_T *argvars, float_T *f)
1295{
1296 if (argvars[0].v_type == VAR_FLOAT)
1297 {
1298 *f = argvars[0].vval.v_float;
1299 return OK;
1300 }
1301 if (argvars[0].v_type == VAR_NUMBER)
1302 {
1303 *f = (float_T)argvars[0].vval.v_number;
1304 return OK;
1305 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001306 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 return FAIL;
1308}
1309
1310/*
1311 * "abs(expr)" function
1312 */
1313 static void
1314f_abs(typval_T *argvars, typval_T *rettv)
1315{
1316 if (argvars[0].v_type == VAR_FLOAT)
1317 {
1318 rettv->v_type = VAR_FLOAT;
1319 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1320 }
1321 else
1322 {
1323 varnumber_T n;
1324 int error = FALSE;
1325
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001326 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001327 if (error)
1328 rettv->vval.v_number = -1;
1329 else if (n > 0)
1330 rettv->vval.v_number = n;
1331 else
1332 rettv->vval.v_number = -n;
1333 }
1334}
1335
1336/*
1337 * "acos()" function
1338 */
1339 static void
1340f_acos(typval_T *argvars, typval_T *rettv)
1341{
1342 float_T f = 0.0;
1343
1344 rettv->v_type = VAR_FLOAT;
1345 if (get_float_arg(argvars, &f) == OK)
1346 rettv->vval.v_float = acos(f);
1347 else
1348 rettv->vval.v_float = 0.0;
1349}
1350#endif
1351
1352/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353 * "and(expr, expr)" function
1354 */
1355 static void
1356f_and(typval_T *argvars, typval_T *rettv)
1357{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001358 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1359 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001360}
1361
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362#ifdef FEAT_FLOAT
1363/*
1364 * "asin()" function
1365 */
1366 static void
1367f_asin(typval_T *argvars, typval_T *rettv)
1368{
1369 float_T f = 0.0;
1370
1371 rettv->v_type = VAR_FLOAT;
1372 if (get_float_arg(argvars, &f) == OK)
1373 rettv->vval.v_float = asin(f);
1374 else
1375 rettv->vval.v_float = 0.0;
1376}
1377
1378/*
1379 * "atan()" function
1380 */
1381 static void
1382f_atan(typval_T *argvars, typval_T *rettv)
1383{
1384 float_T f = 0.0;
1385
1386 rettv->v_type = VAR_FLOAT;
1387 if (get_float_arg(argvars, &f) == OK)
1388 rettv->vval.v_float = atan(f);
1389 else
1390 rettv->vval.v_float = 0.0;
1391}
1392
1393/*
1394 * "atan2()" function
1395 */
1396 static void
1397f_atan2(typval_T *argvars, typval_T *rettv)
1398{
1399 float_T fx = 0.0, fy = 0.0;
1400
1401 rettv->v_type = VAR_FLOAT;
1402 if (get_float_arg(argvars, &fx) == OK
1403 && get_float_arg(&argvars[1], &fy) == OK)
1404 rettv->vval.v_float = atan2(fx, fy);
1405 else
1406 rettv->vval.v_float = 0.0;
1407}
1408#endif
1409
1410/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001411 * "balloon_show()" function
1412 */
1413#ifdef FEAT_BEVAL
1414 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001415f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1416{
1417 rettv->v_type = VAR_STRING;
1418 if (balloonEval != NULL)
1419 {
1420 if (balloonEval->msg == NULL)
1421 rettv->vval.v_string = NULL;
1422 else
1423 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1424 }
1425}
1426
1427 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001428f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1429{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001430 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001431 {
1432 if (argvars[0].v_type == VAR_LIST
1433# ifdef FEAT_GUI
1434 && !gui.in_use
1435# endif
1436 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001437 {
1438 list_T *l = argvars[0].vval.v_list;
1439
1440 // empty list removes the balloon
1441 post_balloon(balloonEval, NULL,
1442 l == NULL || l->lv_len == 0 ? NULL : l);
1443 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001444 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001445 {
1446 char_u *mesg = tv_get_string_chk(&argvars[0]);
1447
1448 if (mesg != NULL)
1449 // empty string removes the balloon
1450 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1451 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001452 }
1453}
1454
Bram Moolenaar669a8282017-11-19 20:13:05 +01001455# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001456 static void
1457f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1458{
1459 if (rettv_list_alloc(rettv) == OK)
1460 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001461 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001462
1463 if (msg != NULL)
1464 {
1465 pumitem_T *array;
1466 int size = split_message(msg, &array);
1467 int i;
1468
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001469 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001470 for (i = 1; i < size - 1; ++i)
1471 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001472 while (size > 0)
1473 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001474 vim_free(array);
1475 }
1476 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001477}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001478# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001479#endif
1480
1481/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001482 * Get the buffer from "arg" and give an error and return NULL if it is not
1483 * valid.
1484 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001485 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001486get_buf_arg(typval_T *arg)
1487{
1488 buf_T *buf;
1489
1490 ++emsg_off;
1491 buf = tv_get_buf(arg, FALSE);
1492 --emsg_off;
1493 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001494 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001495 return buf;
1496}
1497
1498/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499 * "byte2line(byte)" function
1500 */
1501 static void
1502f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1503{
1504#ifndef FEAT_BYTEOFF
1505 rettv->vval.v_number = -1;
1506#else
1507 long boff = 0;
1508
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001509 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001510 if (boff < 0)
1511 rettv->vval.v_number = -1;
1512 else
1513 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1514 (linenr_T)0, &boff);
1515#endif
1516}
1517
1518 static void
1519byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1520{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001521 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001522 char_u *str;
1523 varnumber_T idx;
1524
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001525 str = tv_get_string_chk(&argvars[0]);
1526 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001527 rettv->vval.v_number = -1;
1528 if (str == NULL || idx < 0)
1529 return;
1530
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001531 t = str;
1532 for ( ; idx > 0; idx--)
1533 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001534 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535 return;
1536 if (enc_utf8 && comp)
1537 t += utf_ptr2len(t);
1538 else
1539 t += (*mb_ptr2len)(t);
1540 }
1541 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542}
1543
1544/*
1545 * "byteidx()" function
1546 */
1547 static void
1548f_byteidx(typval_T *argvars, typval_T *rettv)
1549{
1550 byteidx(argvars, rettv, FALSE);
1551}
1552
1553/*
1554 * "byteidxcomp()" function
1555 */
1556 static void
1557f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1558{
1559 byteidx(argvars, rettv, TRUE);
1560}
1561
1562/*
1563 * "call(func, arglist [, dict])" function
1564 */
1565 static void
1566f_call(typval_T *argvars, typval_T *rettv)
1567{
1568 char_u *func;
1569 partial_T *partial = NULL;
1570 dict_T *selfdict = NULL;
1571
1572 if (argvars[1].v_type != VAR_LIST)
1573 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001574 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575 return;
1576 }
1577 if (argvars[1].vval.v_list == NULL)
1578 return;
1579
1580 if (argvars[0].v_type == VAR_FUNC)
1581 func = argvars[0].vval.v_string;
1582 else if (argvars[0].v_type == VAR_PARTIAL)
1583 {
1584 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001585 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001586 }
1587 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001588 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001589 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001590 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001591
1592 if (argvars[2].v_type != VAR_UNKNOWN)
1593 {
1594 if (argvars[2].v_type != VAR_DICT)
1595 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001596 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597 return;
1598 }
1599 selfdict = argvars[2].vval.v_dict;
1600 }
1601
1602 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1603}
1604
1605#ifdef FEAT_FLOAT
1606/*
1607 * "ceil({float})" function
1608 */
1609 static void
1610f_ceil(typval_T *argvars, typval_T *rettv)
1611{
1612 float_T f = 0.0;
1613
1614 rettv->v_type = VAR_FLOAT;
1615 if (get_float_arg(argvars, &f) == OK)
1616 rettv->vval.v_float = ceil(f);
1617 else
1618 rettv->vval.v_float = 0.0;
1619}
1620#endif
1621
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622/*
1623 * "changenr()" function
1624 */
1625 static void
1626f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1627{
1628 rettv->vval.v_number = curbuf->b_u_seq_cur;
1629}
1630
1631/*
1632 * "char2nr(string)" function
1633 */
1634 static void
1635f_char2nr(typval_T *argvars, typval_T *rettv)
1636{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001637 if (has_mbyte)
1638 {
1639 int utf8 = 0;
1640
1641 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001642 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001643
1644 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001645 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001647 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648 }
1649 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001650 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651}
1652
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001653 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001654get_optional_window(typval_T *argvars, int idx)
1655{
1656 win_T *win = curwin;
1657
1658 if (argvars[idx].v_type != VAR_UNKNOWN)
1659 {
1660 win = find_win_by_nr_or_id(&argvars[idx]);
1661 if (win == NULL)
1662 {
1663 emsg(_(e_invalwindow));
1664 return NULL;
1665 }
1666 }
1667 return win;
1668}
1669
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001670/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001671 * "col(string)" function
1672 */
1673 static void
1674f_col(typval_T *argvars, typval_T *rettv)
1675{
1676 colnr_T col = 0;
1677 pos_T *fp;
1678 int fnum = curbuf->b_fnum;
1679
1680 fp = var2fpos(&argvars[0], FALSE, &fnum);
1681 if (fp != NULL && fnum == curbuf->b_fnum)
1682 {
1683 if (fp->col == MAXCOL)
1684 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001685 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1687 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1688 else
1689 col = MAXCOL;
1690 }
1691 else
1692 {
1693 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001694 // col(".") when the cursor is on the NUL at the end of the line
1695 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001696 if (virtual_active() && fp == &curwin->w_cursor)
1697 {
1698 char_u *p = ml_get_cursor();
1699
1700 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1701 curwin->w_virtcol - curwin->w_cursor.coladd))
1702 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001703 int l;
1704
1705 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1706 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001707 }
1708 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001709 }
1710 }
1711 rettv->vval.v_number = col;
1712}
1713
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714/*
1715 * "confirm(message, buttons[, default [, type]])" function
1716 */
1717 static void
1718f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1719{
1720#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1721 char_u *message;
1722 char_u *buttons = NULL;
1723 char_u buf[NUMBUFLEN];
1724 char_u buf2[NUMBUFLEN];
1725 int def = 1;
1726 int type = VIM_GENERIC;
1727 char_u *typestr;
1728 int error = FALSE;
1729
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001730 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001731 if (message == NULL)
1732 error = TRUE;
1733 if (argvars[1].v_type != VAR_UNKNOWN)
1734 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001735 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001736 if (buttons == NULL)
1737 error = TRUE;
1738 if (argvars[2].v_type != VAR_UNKNOWN)
1739 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001740 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001741 if (argvars[3].v_type != VAR_UNKNOWN)
1742 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001743 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001744 if (typestr == NULL)
1745 error = TRUE;
1746 else
1747 {
1748 switch (TOUPPER_ASC(*typestr))
1749 {
1750 case 'E': type = VIM_ERROR; break;
1751 case 'Q': type = VIM_QUESTION; break;
1752 case 'I': type = VIM_INFO; break;
1753 case 'W': type = VIM_WARNING; break;
1754 case 'G': type = VIM_GENERIC; break;
1755 }
1756 }
1757 }
1758 }
1759 }
1760
1761 if (buttons == NULL || *buttons == NUL)
1762 buttons = (char_u *)_("&Ok");
1763
1764 if (!error)
1765 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1766 def, NULL, FALSE);
1767#endif
1768}
1769
1770/*
1771 * "copy()" function
1772 */
1773 static void
1774f_copy(typval_T *argvars, typval_T *rettv)
1775{
1776 item_copy(&argvars[0], rettv, FALSE, 0);
1777}
1778
1779#ifdef FEAT_FLOAT
1780/*
1781 * "cos()" function
1782 */
1783 static void
1784f_cos(typval_T *argvars, typval_T *rettv)
1785{
1786 float_T f = 0.0;
1787
1788 rettv->v_type = VAR_FLOAT;
1789 if (get_float_arg(argvars, &f) == OK)
1790 rettv->vval.v_float = cos(f);
1791 else
1792 rettv->vval.v_float = 0.0;
1793}
1794
1795/*
1796 * "cosh()" function
1797 */
1798 static void
1799f_cosh(typval_T *argvars, typval_T *rettv)
1800{
1801 float_T f = 0.0;
1802
1803 rettv->v_type = VAR_FLOAT;
1804 if (get_float_arg(argvars, &f) == OK)
1805 rettv->vval.v_float = cosh(f);
1806 else
1807 rettv->vval.v_float = 0.0;
1808}
1809#endif
1810
1811/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001812 * "cursor(lnum, col)" function, or
1813 * "cursor(list)"
1814 *
1815 * Moves the cursor to the specified line and column.
1816 * Returns 0 when the position could be set, -1 otherwise.
1817 */
1818 static void
1819f_cursor(typval_T *argvars, typval_T *rettv)
1820{
1821 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001823 int set_curswant = TRUE;
1824
1825 rettv->vval.v_number = -1;
1826 if (argvars[1].v_type == VAR_UNKNOWN)
1827 {
1828 pos_T pos;
1829 colnr_T curswant = -1;
1830
1831 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1832 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001833 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834 return;
1835 }
1836 line = pos.lnum;
1837 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001838 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 if (curswant >= 0)
1840 {
1841 curwin->w_curswant = curswant - 1;
1842 set_curswant = FALSE;
1843 }
1844 }
1845 else
1846 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001847 line = tv_get_lnum(argvars);
1848 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001849 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001850 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001851 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001852 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001853 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001854 if (line > 0)
1855 curwin->w_cursor.lnum = line;
1856 if (col > 0)
1857 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001858 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001859
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001860 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001861 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001862 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001863 if (has_mbyte)
1864 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001865
1866 curwin->w_set_curswant = set_curswant;
1867 rettv->vval.v_number = 0;
1868}
1869
Bram Moolenaar4f974752019-02-17 17:44:42 +01001870#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001871/*
1872 * "debugbreak()" function
1873 */
1874 static void
1875f_debugbreak(typval_T *argvars, typval_T *rettv)
1876{
1877 int pid;
1878
1879 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001880 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001881 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001882 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001883 else
1884 {
1885 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1886
1887 if (hProcess != NULL)
1888 {
1889 DebugBreakProcess(hProcess);
1890 CloseHandle(hProcess);
1891 rettv->vval.v_number = OK;
1892 }
1893 }
1894}
1895#endif
1896
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001897/*
1898 * "deepcopy()" function
1899 */
1900 static void
1901f_deepcopy(typval_T *argvars, typval_T *rettv)
1902{
1903 int noref = 0;
1904 int copyID;
1905
1906 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001907 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001909 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001910 else
1911 {
1912 copyID = get_copyID();
1913 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1914 }
1915}
1916
1917/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001918 * "did_filetype()" function
1919 */
1920 static void
1921f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1922{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001924}
1925
1926/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001927 * "echoraw({expr})" function
1928 */
1929 static void
1930f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1931{
1932 char_u *str = tv_get_string_chk(&argvars[0]);
1933
1934 if (str != NULL && *str != NUL)
1935 {
1936 out_str(str);
1937 out_flush();
1938 }
1939}
1940
1941/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942 * "empty({expr})" function
1943 */
1944 static void
1945f_empty(typval_T *argvars, typval_T *rettv)
1946{
1947 int n = FALSE;
1948
1949 switch (argvars[0].v_type)
1950 {
1951 case VAR_STRING:
1952 case VAR_FUNC:
1953 n = argvars[0].vval.v_string == NULL
1954 || *argvars[0].vval.v_string == NUL;
1955 break;
1956 case VAR_PARTIAL:
1957 n = FALSE;
1958 break;
1959 case VAR_NUMBER:
1960 n = argvars[0].vval.v_number == 0;
1961 break;
1962 case VAR_FLOAT:
1963#ifdef FEAT_FLOAT
1964 n = argvars[0].vval.v_float == 0.0;
1965 break;
1966#endif
1967 case VAR_LIST:
1968 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001969 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001970 break;
1971 case VAR_DICT:
1972 n = argvars[0].vval.v_dict == NULL
1973 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1974 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001975 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 case VAR_SPECIAL:
1977 n = argvars[0].vval.v_number != VVAL_TRUE;
1978 break;
1979
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001980 case VAR_BLOB:
1981 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001982 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1983 break;
1984
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985 case VAR_JOB:
1986#ifdef FEAT_JOB_CHANNEL
1987 n = argvars[0].vval.v_job == NULL
1988 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1989 break;
1990#endif
1991 case VAR_CHANNEL:
1992#ifdef FEAT_JOB_CHANNEL
1993 n = argvars[0].vval.v_channel == NULL
1994 || !channel_is_open(argvars[0].vval.v_channel);
1995 break;
1996#endif
1997 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02001998 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001999 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01002000 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002001 n = TRUE;
2002 break;
2003 }
2004
2005 rettv->vval.v_number = n;
2006}
2007
2008/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002009 * "environ()" function
2010 */
2011 static void
2012f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2013{
2014#if !defined(AMIGA)
2015 int i = 0;
2016 char_u *entry, *value;
2017# ifdef MSWIN
2018 extern wchar_t **_wenviron;
2019# else
2020 extern char **environ;
2021# endif
2022
2023 if (rettv_dict_alloc(rettv) != OK)
2024 return;
2025
2026# ifdef MSWIN
2027 if (*_wenviron == NULL)
2028 return;
2029# else
2030 if (*environ == NULL)
2031 return;
2032# endif
2033
2034 for (i = 0; ; ++i)
2035 {
2036# ifdef MSWIN
2037 short_u *p;
2038
2039 if ((p = (short_u *)_wenviron[i]) == NULL)
2040 return;
2041 entry = utf16_to_enc(p, NULL);
2042# else
2043 if ((entry = (char_u *)environ[i]) == NULL)
2044 return;
2045 entry = vim_strsave(entry);
2046# endif
2047 if (entry == NULL) // out of memory
2048 return;
2049 if ((value = vim_strchr(entry, '=')) == NULL)
2050 {
2051 vim_free(entry);
2052 continue;
2053 }
2054 *value++ = NUL;
2055 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2056 vim_free(entry);
2057 }
2058#endif
2059}
2060
2061/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002062 * "escape({string}, {chars})" function
2063 */
2064 static void
2065f_escape(typval_T *argvars, typval_T *rettv)
2066{
2067 char_u buf[NUMBUFLEN];
2068
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002069 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2070 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002071 rettv->v_type = VAR_STRING;
2072}
2073
2074/*
2075 * "eval()" function
2076 */
2077 static void
2078f_eval(typval_T *argvars, typval_T *rettv)
2079{
2080 char_u *s, *p;
2081
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002082 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002083 if (s != NULL)
2084 s = skipwhite(s);
2085
2086 p = s;
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02002087 if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088 {
2089 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002090 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002091 need_clr_eos = FALSE;
2092 rettv->v_type = VAR_NUMBER;
2093 rettv->vval.v_number = 0;
2094 }
2095 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002096 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097}
2098
2099/*
2100 * "eventhandler()" function
2101 */
2102 static void
2103f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2104{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002105 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002106}
2107
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002108static garray_T redir_execute_ga;
2109
2110/*
2111 * Append "value[value_len]" to the execute() output.
2112 */
2113 void
2114execute_redir_str(char_u *value, int value_len)
2115{
2116 int len;
2117
2118 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002119 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002121 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 if (ga_grow(&redir_execute_ga, len) == OK)
2123 {
2124 mch_memmove((char *)redir_execute_ga.ga_data
2125 + redir_execute_ga.ga_len, value, len);
2126 redir_execute_ga.ga_len += len;
2127 }
2128}
2129
2130/*
2131 * Get next line from a list.
2132 * Called by do_cmdline() to get the next line.
2133 * Returns allocated string, or NULL for end of function.
2134 */
2135
2136 static char_u *
2137get_list_line(
2138 int c UNUSED,
2139 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002140 int indent UNUSED,
2141 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002142{
2143 listitem_T **p = (listitem_T **)cookie;
2144 listitem_T *item = *p;
2145 char_u buf[NUMBUFLEN];
2146 char_u *s;
2147
2148 if (item == NULL)
2149 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002150 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002151 *p = item->li_next;
2152 return s == NULL ? NULL : vim_strsave(s);
2153}
2154
2155/*
2156 * "execute()" function
2157 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002158 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002159execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002160{
2161 char_u *cmd = NULL;
2162 list_T *list = NULL;
2163 int save_msg_silent = msg_silent;
2164 int save_emsg_silent = emsg_silent;
2165 int save_emsg_noredir = emsg_noredir;
2166 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002167 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002168 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002169 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002170 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171
2172 rettv->vval.v_string = NULL;
2173 rettv->v_type = VAR_STRING;
2174
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002175 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002177 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002178 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002179 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180 return;
2181 ++list->lv_refcount;
2182 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002183 else if (argvars[arg_off].v_type == VAR_JOB
2184 || argvars[arg_off].v_type == VAR_CHANNEL)
2185 {
2186 emsg(_(e_inval_string));
2187 return;
2188 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002189 else
2190 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002191 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 if (cmd == NULL)
2193 return;
2194 }
2195
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002196 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002197 {
2198 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002199 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002200
2201 if (s == NULL)
2202 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002203 if (*s == NUL)
2204 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002205 if (STRNCMP(s, "silent", 6) == 0)
2206 ++msg_silent;
2207 if (STRCMP(s, "silent!") == 0)
2208 {
2209 emsg_silent = TRUE;
2210 emsg_noredir = TRUE;
2211 }
2212 }
2213 else
2214 ++msg_silent;
2215
2216 if (redir_execute)
2217 save_ga = redir_execute_ga;
2218 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2219 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002220 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002221 if (!echo_output)
2222 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002223
2224 if (cmd != NULL)
2225 do_cmdline_cmd(cmd);
2226 else
2227 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002228 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002229
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002230 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002231 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002232 do_cmdline(NULL, get_list_line, (void *)&item,
2233 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2234 --list->lv_refcount;
2235 }
2236
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002237 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002238 if (ga_grow(&redir_execute_ga, 1) == OK)
2239 {
2240 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2241 rettv->vval.v_string = redir_execute_ga.ga_data;
2242 }
2243 else
2244 {
2245 ga_clear(&redir_execute_ga);
2246 rettv->vval.v_string = NULL;
2247 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002248 msg_silent = save_msg_silent;
2249 emsg_silent = save_emsg_silent;
2250 emsg_noredir = save_emsg_noredir;
2251
2252 redir_execute = save_redir_execute;
2253 if (redir_execute)
2254 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002255 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002257 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002258 if (echo_output)
2259 // When not working silently: put it in column zero. A following
2260 // "echon" will overwrite the message, unavoidably.
2261 msg_col = 0;
2262 else
2263 // When working silently: Put it back where it was, since nothing
2264 // should have been written.
2265 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266}
2267
2268/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002269 * "execute()" function
2270 */
2271 static void
2272f_execute(typval_T *argvars, typval_T *rettv)
2273{
2274 execute_common(argvars, rettv, 0);
2275}
2276
2277/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002278 * "exists()" function
2279 */
2280 static void
2281f_exists(typval_T *argvars, typval_T *rettv)
2282{
2283 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002284 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002285
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002286 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002287 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002288 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002289 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290 if (mch_getenv(p + 1) != NULL)
2291 n = TRUE;
2292 else
2293 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002294 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 p = expand_env_save(p);
2296 if (p != NULL && *p != '$')
2297 n = TRUE;
2298 vim_free(p);
2299 }
2300 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002301 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002302 {
2303 n = (get_option_tv(&p, NULL, TRUE) == OK);
2304 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002305 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002306 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002307 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002309 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002310 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002311 else if (*p == '?') // internal function only
2312 {
2313 n = has_internal_func_name(p + 1);
2314 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002315 else if (*p == ':')
2316 {
2317 n = cmd_exists(p + 1);
2318 }
2319 else if (*p == '#')
2320 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002321 if (p[1] == '#')
2322 n = autocmd_supported(p + 2);
2323 else
2324 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002325 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002326 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002327 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002328 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002329 }
2330
2331 rettv->vval.v_number = n;
2332}
2333
2334#ifdef FEAT_FLOAT
2335/*
2336 * "exp()" function
2337 */
2338 static void
2339f_exp(typval_T *argvars, typval_T *rettv)
2340{
2341 float_T f = 0.0;
2342
2343 rettv->v_type = VAR_FLOAT;
2344 if (get_float_arg(argvars, &f) == OK)
2345 rettv->vval.v_float = exp(f);
2346 else
2347 rettv->vval.v_float = 0.0;
2348}
2349#endif
2350
2351/*
2352 * "expand()" function
2353 */
2354 static void
2355f_expand(typval_T *argvars, typval_T *rettv)
2356{
2357 char_u *s;
2358 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002359 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2361 expand_T xpc;
2362 int error = FALSE;
2363 char_u *result;
2364
2365 rettv->v_type = VAR_STRING;
2366 if (argvars[1].v_type != VAR_UNKNOWN
2367 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002368 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002369 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002370 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002371
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002372 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002373 if (*s == '%' || *s == '#' || *s == '<')
2374 {
2375 ++emsg_off;
2376 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2377 --emsg_off;
2378 if (rettv->v_type == VAR_LIST)
2379 {
2380 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2381 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002382 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002383 }
2384 else
2385 rettv->vval.v_string = result;
2386 }
2387 else
2388 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002389 // When the optional second argument is non-zero, don't remove matches
2390 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002391 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002392 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002393 options |= WILD_KEEP_ALL;
2394 if (!error)
2395 {
2396 ExpandInit(&xpc);
2397 xpc.xp_context = EXPAND_FILES;
2398 if (p_wic)
2399 options += WILD_ICASE;
2400 if (rettv->v_type == VAR_STRING)
2401 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2402 options, WILD_ALL);
2403 else if (rettv_list_alloc(rettv) != FAIL)
2404 {
2405 int i;
2406
2407 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2408 for (i = 0; i < xpc.xp_numfiles; i++)
2409 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2410 ExpandCleanup(&xpc);
2411 }
2412 }
2413 else
2414 rettv->vval.v_string = NULL;
2415 }
2416}
2417
2418/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002419 * "expandcmd()" function
2420 * Expand all the special characters in a command string.
2421 */
2422 static void
2423f_expandcmd(typval_T *argvars, typval_T *rettv)
2424{
2425 exarg_T eap;
2426 char_u *cmdstr;
2427 char *errormsg = NULL;
2428
2429 rettv->v_type = VAR_STRING;
2430 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2431
2432 memset(&eap, 0, sizeof(eap));
2433 eap.cmd = cmdstr;
2434 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002435 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002436 eap.usefilter = FALSE;
2437 eap.nextcmd = NULL;
2438 eap.cmdidx = CMD_USER;
2439
2440 expand_filename(&eap, &cmdstr, &errormsg);
2441 if (errormsg != NULL && *errormsg != NUL)
2442 emsg(errormsg);
2443
2444 rettv->vval.v_string = cmdstr;
2445}
2446
2447/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 * "feedkeys()" function
2449 */
2450 static void
2451f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2452{
2453 int remap = TRUE;
2454 int insert = FALSE;
2455 char_u *keys, *flags;
2456 char_u nbuf[NUMBUFLEN];
2457 int typed = FALSE;
2458 int execute = FALSE;
2459 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002460 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 char_u *keys_esc;
2462
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002463 // This is not allowed in the sandbox. If the commands would still be
2464 // executed in the sandbox it would be OK, but it probably happens later,
2465 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002466 if (check_secure())
2467 return;
2468
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002469 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470
2471 if (argvars[1].v_type != VAR_UNKNOWN)
2472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002473 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002474 for ( ; *flags != NUL; ++flags)
2475 {
2476 switch (*flags)
2477 {
2478 case 'n': remap = FALSE; break;
2479 case 'm': remap = TRUE; break;
2480 case 't': typed = TRUE; break;
2481 case 'i': insert = TRUE; break;
2482 case 'x': execute = TRUE; break;
2483 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002484 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002485 }
2486 }
2487 }
2488
2489 if (*keys != NUL || execute)
2490 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002491 // Need to escape K_SPECIAL and CSI before putting the string in the
2492 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002493 keys_esc = vim_strsave_escape_csi(keys);
2494 if (keys_esc != NULL)
2495 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002496 if (lowlevel)
2497 {
2498#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002499 int idx;
2500 int len = (int)STRLEN(keys);
2501
2502 for (idx = 0; idx < len; ++idx)
2503 {
2504 // if a CTRL-C was typed, set got_int, similar to what
2505 // happens in fill_input_buf()
2506 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2507 got_int = TRUE;
2508 add_to_input_buf(keys + idx, 1);
2509 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002510#else
2511 emsg(_("E980: lowlevel input not supported"));
2512#endif
2513 }
2514 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002515 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002516 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002518 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002519#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002520 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002521#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002522 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002523 typebuf_was_filled = TRUE;
2524 }
2525 vim_free(keys_esc);
2526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002527 if (execute)
2528 {
2529 int save_msg_scroll = msg_scroll;
2530
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002531 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002532 msg_scroll = FALSE;
2533
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002534 if (!dangerous)
2535 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002536 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002537 if (!dangerous)
2538 --ex_normal_busy;
2539
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002540 msg_scroll |= save_msg_scroll;
2541 }
2542 }
2543 }
2544}
2545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002546#ifdef FEAT_FLOAT
2547/*
2548 * "float2nr({float})" function
2549 */
2550 static void
2551f_float2nr(typval_T *argvars, typval_T *rettv)
2552{
2553 float_T f = 0.0;
2554
2555 if (get_float_arg(argvars, &f) == OK)
2556 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002557 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002558 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002559 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002560 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561 else
2562 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563 }
2564}
2565
2566/*
2567 * "floor({float})" function
2568 */
2569 static void
2570f_floor(typval_T *argvars, typval_T *rettv)
2571{
2572 float_T f = 0.0;
2573
2574 rettv->v_type = VAR_FLOAT;
2575 if (get_float_arg(argvars, &f) == OK)
2576 rettv->vval.v_float = floor(f);
2577 else
2578 rettv->vval.v_float = 0.0;
2579}
2580
2581/*
2582 * "fmod()" function
2583 */
2584 static void
2585f_fmod(typval_T *argvars, typval_T *rettv)
2586{
2587 float_T fx = 0.0, fy = 0.0;
2588
2589 rettv->v_type = VAR_FLOAT;
2590 if (get_float_arg(argvars, &fx) == OK
2591 && get_float_arg(&argvars[1], &fy) == OK)
2592 rettv->vval.v_float = fmod(fx, fy);
2593 else
2594 rettv->vval.v_float = 0.0;
2595}
2596#endif
2597
2598/*
2599 * "fnameescape({string})" function
2600 */
2601 static void
2602f_fnameescape(typval_T *argvars, typval_T *rettv)
2603{
2604 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002605 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002606 rettv->v_type = VAR_STRING;
2607}
2608
2609/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002610 * "foreground()" function
2611 */
2612 static void
2613f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2614{
2615#ifdef FEAT_GUI
2616 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002617 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002619 return;
2620 }
2621#endif
2622#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002623 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002624#endif
2625}
2626
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002628common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002629{
2630 char_u *s;
2631 char_u *name;
2632 int use_string = FALSE;
2633 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002634 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002635 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002636
2637 if (argvars[0].v_type == VAR_FUNC)
2638 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002639 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002640 s = argvars[0].vval.v_string;
2641 }
2642 else if (argvars[0].v_type == VAR_PARTIAL
2643 && argvars[0].vval.v_partial != NULL)
2644 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002645 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002646 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002647 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002648 }
2649 else
2650 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002651 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002652 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 use_string = TRUE;
2654 }
2655
Bram Moolenaar843b8842016-08-21 14:36:15 +02002656 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002657 {
2658 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002659 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002660 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2661 if (*name != NUL)
2662 s = NULL;
2663 }
2664
Bram Moolenaar843b8842016-08-21 14:36:15 +02002665 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2666 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002667 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002668 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002669 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002670 ? find_func(trans_name, is_global, NULL) == NULL
2671 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002672 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002673 else
2674 {
2675 int dict_idx = 0;
2676 int arg_idx = 0;
2677 list_T *list = NULL;
2678
2679 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2680 {
2681 char sid_buf[25];
2682 int off = *s == 's' ? 2 : 5;
2683
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002684 // Expand s: and <SID> into <SNR>nr_, so that the function can
2685 // also be called from another script. Using trans_function_name()
2686 // would also work, but some plugins depend on the name being
2687 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002688 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002689 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002690 if (name != NULL)
2691 {
2692 STRCPY(name, sid_buf);
2693 STRCAT(name, s + off);
2694 }
2695 }
2696 else
2697 name = vim_strsave(s);
2698
2699 if (argvars[1].v_type != VAR_UNKNOWN)
2700 {
2701 if (argvars[2].v_type != VAR_UNKNOWN)
2702 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002703 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 arg_idx = 1;
2705 dict_idx = 2;
2706 }
2707 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002708 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709 dict_idx = 1;
2710 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002711 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002712 arg_idx = 1;
2713 if (dict_idx > 0)
2714 {
2715 if (argvars[dict_idx].v_type != VAR_DICT)
2716 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002717 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002718 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002719 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002720 }
2721 if (argvars[dict_idx].vval.v_dict == NULL)
2722 dict_idx = 0;
2723 }
2724 if (arg_idx > 0)
2725 {
2726 if (argvars[arg_idx].v_type != VAR_LIST)
2727 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002728 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002729 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002730 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002731 }
2732 list = argvars[arg_idx].vval.v_list;
2733 if (list == NULL || list->lv_len == 0)
2734 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002735 else if (list->lv_len > MAX_FUNC_ARGS)
2736 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002737 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002738 vim_free(name);
2739 goto theend;
2740 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002741 }
2742 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002743 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002744 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002745 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002746
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002747 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002748 if (pt == NULL)
2749 vim_free(name);
2750 else
2751 {
2752 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2753 {
2754 listitem_T *li;
2755 int i = 0;
2756 int arg_len = 0;
2757 int lv_len = 0;
2758
2759 if (arg_pt != NULL)
2760 arg_len = arg_pt->pt_argc;
2761 if (list != NULL)
2762 lv_len = list->lv_len;
2763 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002764 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002765 if (pt->pt_argv == NULL)
2766 {
2767 vim_free(pt);
2768 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002769 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002771 for (i = 0; i < arg_len; i++)
2772 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2773 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002774 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002775 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002776 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002777 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002778 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002779 }
2780
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002781 // For "function(dict.func, [], dict)" and "func" is a partial
2782 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783 if (dict_idx > 0)
2784 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002785 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002786 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2787 ++pt->pt_dict->dv_refcount;
2788 }
2789 else if (arg_pt != NULL)
2790 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002791 // If the dict was bound automatically the result is also
2792 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002793 pt->pt_dict = arg_pt->pt_dict;
2794 pt->pt_auto = arg_pt->pt_auto;
2795 if (pt->pt_dict != NULL)
2796 ++pt->pt_dict->dv_refcount;
2797 }
2798
2799 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002800 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2801 {
2802 pt->pt_func = arg_pt->pt_func;
2803 func_ptr_ref(pt->pt_func);
2804 vim_free(name);
2805 }
2806 else if (is_funcref)
2807 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002808 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002809 func_ptr_ref(pt->pt_func);
2810 vim_free(name);
2811 }
2812 else
2813 {
2814 pt->pt_name = name;
2815 func_ref(name);
2816 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817 }
2818 rettv->v_type = VAR_PARTIAL;
2819 rettv->vval.v_partial = pt;
2820 }
2821 else
2822 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002823 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002824 rettv->v_type = VAR_FUNC;
2825 rettv->vval.v_string = name;
2826 func_ref(name);
2827 }
2828 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002829theend:
2830 vim_free(trans_name);
2831}
2832
2833/*
2834 * "funcref()" function
2835 */
2836 static void
2837f_funcref(typval_T *argvars, typval_T *rettv)
2838{
2839 common_function(argvars, rettv, TRUE);
2840}
2841
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002842 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002843ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002844{
2845 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2846 return &t_func_any;
Bram Moolenaard77a8522020-04-03 21:59:57 +02002847 return &t_func_void;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002848}
2849
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002850/*
2851 * "function()" function
2852 */
2853 static void
2854f_function(typval_T *argvars, typval_T *rettv)
2855{
2856 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002857}
2858
2859/*
2860 * "garbagecollect()" function
2861 */
2862 static void
2863f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2864{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002865 // This is postponed until we are back at the toplevel, because we may be
2866 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002867 want_garbage_collect = TRUE;
2868
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002869 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002870 garbage_collect_at_exit = TRUE;
2871}
2872
2873/*
2874 * "get()" function
2875 */
2876 static void
2877f_get(typval_T *argvars, typval_T *rettv)
2878{
2879 listitem_T *li;
2880 list_T *l;
2881 dictitem_T *di;
2882 dict_T *d;
2883 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002884 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002885
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002886 if (argvars[0].v_type == VAR_BLOB)
2887 {
2888 int error = FALSE;
2889 int idx = tv_get_number_chk(&argvars[1], &error);
2890
2891 if (!error)
2892 {
2893 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002894 if (idx < 0)
2895 idx = blob_len(argvars[0].vval.v_blob) + idx;
2896 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2897 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002898 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002899 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002900 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002901 tv = rettv;
2902 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002903 }
2904 }
2905 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002906 {
2907 if ((l = argvars[0].vval.v_list) != NULL)
2908 {
2909 int error = FALSE;
2910
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002911 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 if (!error && li != NULL)
2913 tv = &li->li_tv;
2914 }
2915 }
2916 else if (argvars[0].v_type == VAR_DICT)
2917 {
2918 if ((d = argvars[0].vval.v_dict) != NULL)
2919 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002920 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002921 if (di != NULL)
2922 tv = &di->di_tv;
2923 }
2924 }
2925 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2926 {
2927 partial_T *pt;
2928 partial_T fref_pt;
2929
2930 if (argvars[0].v_type == VAR_PARTIAL)
2931 pt = argvars[0].vval.v_partial;
2932 else
2933 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02002934 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002935 fref_pt.pt_name = argvars[0].vval.v_string;
2936 pt = &fref_pt;
2937 }
2938
2939 if (pt != NULL)
2940 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002941 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002942 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002943
2944 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2945 {
2946 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002947 n = partial_name(pt);
2948 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002949 rettv->vval.v_string = NULL;
2950 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002951 {
2952 rettv->vval.v_string = vim_strsave(n);
2953 if (rettv->v_type == VAR_FUNC)
2954 func_ref(rettv->vval.v_string);
2955 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002956 }
2957 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002958 {
2959 what_is_dict = TRUE;
2960 if (pt->pt_dict != NULL)
2961 rettv_dict_set(rettv, pt->pt_dict);
2962 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002963 else if (STRCMP(what, "args") == 0)
2964 {
2965 rettv->v_type = VAR_LIST;
2966 if (rettv_list_alloc(rettv) == OK)
2967 {
2968 int i;
2969
2970 for (i = 0; i < pt->pt_argc; ++i)
2971 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2972 }
2973 }
2974 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002975 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002976
2977 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2978 // third argument
2979 if (!what_is_dict)
2980 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002981 }
2982 }
2983 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002984 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002985
2986 if (tv == NULL)
2987 {
2988 if (argvars[2].v_type != VAR_UNKNOWN)
2989 copy_tv(&argvars[2], rettv);
2990 }
2991 else
2992 copy_tv(tv, rettv);
2993}
2994
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002995/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002996 * "getchangelist()" function
2997 */
2998 static void
2999f_getchangelist(typval_T *argvars, typval_T *rettv)
3000{
3001#ifdef FEAT_JUMPLIST
3002 buf_T *buf;
3003 int i;
3004 list_T *l;
3005 dict_T *d;
3006#endif
3007
3008 if (rettv_list_alloc(rettv) != OK)
3009 return;
3010
3011#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003012 if (argvars[0].v_type == VAR_UNKNOWN)
3013 buf = curbuf;
3014 else
3015 {
3016 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3017 ++emsg_off;
3018 buf = tv_get_buf(&argvars[0], FALSE);
3019 --emsg_off;
3020 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003021 if (buf == NULL)
3022 return;
3023
3024 l = list_alloc();
3025 if (l == NULL)
3026 return;
3027
3028 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3029 return;
3030 /*
3031 * The current window change list index tracks only the position in the
3032 * current buffer change list. For other buffers, use the change list
3033 * length as the current index.
3034 */
3035 list_append_number(rettv->vval.v_list,
3036 (varnumber_T)((buf == curwin->w_buffer)
3037 ? curwin->w_changelistidx : buf->b_changelistlen));
3038
3039 for (i = 0; i < buf->b_changelistlen; ++i)
3040 {
3041 if (buf->b_changelist[i].lnum == 0)
3042 continue;
3043 if ((d = dict_alloc()) == NULL)
3044 return;
3045 if (list_append_dict(l, d) == FAIL)
3046 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003047 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3048 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003049 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003050 }
3051#endif
3052}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003053
3054/*
3055 * "getcharsearch()" function
3056 */
3057 static void
3058f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3059{
3060 if (rettv_dict_alloc(rettv) != FAIL)
3061 {
3062 dict_T *dict = rettv->vval.v_dict;
3063
Bram Moolenaare0be1672018-07-08 16:50:37 +02003064 dict_add_string(dict, "char", last_csearch());
3065 dict_add_number(dict, "forward", last_csearch_forward());
3066 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003067 }
3068}
3069
3070/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003071 * "getenv()" function
3072 */
3073 static void
3074f_getenv(typval_T *argvars, typval_T *rettv)
3075{
3076 int mustfree = FALSE;
3077 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3078
3079 if (p == NULL)
3080 {
3081 rettv->v_type = VAR_SPECIAL;
3082 rettv->vval.v_number = VVAL_NULL;
3083 return;
3084 }
3085 if (!mustfree)
3086 p = vim_strsave(p);
3087 rettv->vval.v_string = p;
3088 rettv->v_type = VAR_STRING;
3089}
3090
3091/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003092 * "getfontname()" function
3093 */
3094 static void
3095f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3096{
3097 rettv->v_type = VAR_STRING;
3098 rettv->vval.v_string = NULL;
3099#ifdef FEAT_GUI
3100 if (gui.in_use)
3101 {
3102 GuiFont font;
3103 char_u *name = NULL;
3104
3105 if (argvars[0].v_type == VAR_UNKNOWN)
3106 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003107 // Get the "Normal" font. Either the name saved by
3108 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003109 font = gui.norm_font;
3110 name = hl_get_font_name();
3111 }
3112 else
3113 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003114 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003115 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003116 return;
3117 font = gui_mch_get_font(name, FALSE);
3118 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003119 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003120 }
3121 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3122 if (argvars[0].v_type != VAR_UNKNOWN)
3123 gui_mch_free_font(font);
3124 }
3125#endif
3126}
3127
3128/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003129 * "getjumplist()" function
3130 */
3131 static void
3132f_getjumplist(typval_T *argvars, typval_T *rettv)
3133{
3134#ifdef FEAT_JUMPLIST
3135 win_T *wp;
3136 int i;
3137 list_T *l;
3138 dict_T *d;
3139#endif
3140
3141 if (rettv_list_alloc(rettv) != OK)
3142 return;
3143
3144#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003145 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003146 if (wp == NULL)
3147 return;
3148
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003149 cleanup_jumplist(wp, TRUE);
3150
Bram Moolenaar4f505882018-02-10 21:06:32 +01003151 l = list_alloc();
3152 if (l == NULL)
3153 return;
3154
3155 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3156 return;
3157 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3158
3159 for (i = 0; i < wp->w_jumplistlen; ++i)
3160 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003161 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3162 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003163 if ((d = dict_alloc()) == NULL)
3164 return;
3165 if (list_append_dict(l, d) == FAIL)
3166 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003167 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3168 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003169 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003170 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003171 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003172 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003173 }
3174#endif
3175}
3176
3177/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003178 * "getpid()" function
3179 */
3180 static void
3181f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3182{
3183 rettv->vval.v_number = mch_get_pid();
3184}
3185
3186 static void
3187getpos_both(
3188 typval_T *argvars,
3189 typval_T *rettv,
3190 int getcurpos)
3191{
3192 pos_T *fp;
3193 list_T *l;
3194 int fnum = -1;
3195
3196 if (rettv_list_alloc(rettv) == OK)
3197 {
3198 l = rettv->vval.v_list;
3199 if (getcurpos)
3200 fp = &curwin->w_cursor;
3201 else
3202 fp = var2fpos(&argvars[0], TRUE, &fnum);
3203 if (fnum != -1)
3204 list_append_number(l, (varnumber_T)fnum);
3205 else
3206 list_append_number(l, (varnumber_T)0);
3207 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3208 : (varnumber_T)0);
3209 list_append_number(l, (fp != NULL)
3210 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3211 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003212 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003213 (varnumber_T)0);
3214 if (getcurpos)
3215 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003216 int save_set_curswant = curwin->w_set_curswant;
3217 colnr_T save_curswant = curwin->w_curswant;
3218 colnr_T save_virtcol = curwin->w_virtcol;
3219
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003220 update_curswant();
3221 list_append_number(l, curwin->w_curswant == MAXCOL ?
3222 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003223
3224 // Do not change "curswant", as it is unexpected that a get
3225 // function has a side effect.
3226 if (save_set_curswant)
3227 {
3228 curwin->w_set_curswant = save_set_curswant;
3229 curwin->w_curswant = save_curswant;
3230 curwin->w_virtcol = save_virtcol;
3231 curwin->w_valid &= ~VALID_VIRTCOL;
3232 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003233 }
3234 }
3235 else
3236 rettv->vval.v_number = FALSE;
3237}
3238
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003239/*
3240 * "getcurpos()" function
3241 */
3242 static void
3243f_getcurpos(typval_T *argvars, typval_T *rettv)
3244{
3245 getpos_both(argvars, rettv, TRUE);
3246}
3247
3248/*
3249 * "getpos(string)" function
3250 */
3251 static void
3252f_getpos(typval_T *argvars, typval_T *rettv)
3253{
3254 getpos_both(argvars, rettv, FALSE);
3255}
3256
3257/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003258 * "getreg()" function
3259 */
3260 static void
3261f_getreg(typval_T *argvars, typval_T *rettv)
3262{
3263 char_u *strregname;
3264 int regname;
3265 int arg2 = FALSE;
3266 int return_list = FALSE;
3267 int error = FALSE;
3268
3269 if (argvars[0].v_type != VAR_UNKNOWN)
3270 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003271 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003272 error = strregname == NULL;
3273 if (argvars[1].v_type != VAR_UNKNOWN)
3274 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003275 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003276 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003277 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003278 }
3279 }
3280 else
3281 strregname = get_vim_var_str(VV_REG);
3282
3283 if (error)
3284 return;
3285
3286 regname = (strregname == NULL ? '"' : *strregname);
3287 if (regname == 0)
3288 regname = '"';
3289
3290 if (return_list)
3291 {
3292 rettv->v_type = VAR_LIST;
3293 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3294 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3295 if (rettv->vval.v_list == NULL)
3296 (void)rettv_list_alloc(rettv);
3297 else
3298 ++rettv->vval.v_list->lv_refcount;
3299 }
3300 else
3301 {
3302 rettv->v_type = VAR_STRING;
3303 rettv->vval.v_string = get_reg_contents(regname,
3304 arg2 ? GREG_EXPR_SRC : 0);
3305 }
3306}
3307
3308/*
3309 * "getregtype()" function
3310 */
3311 static void
3312f_getregtype(typval_T *argvars, typval_T *rettv)
3313{
3314 char_u *strregname;
3315 int regname;
3316 char_u buf[NUMBUFLEN + 2];
3317 long reglen = 0;
3318
3319 if (argvars[0].v_type != VAR_UNKNOWN)
3320 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003321 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003322 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003323 {
3324 rettv->v_type = VAR_STRING;
3325 rettv->vval.v_string = NULL;
3326 return;
3327 }
3328 }
3329 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003330 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003331 strregname = get_vim_var_str(VV_REG);
3332
3333 regname = (strregname == NULL ? '"' : *strregname);
3334 if (regname == 0)
3335 regname = '"';
3336
3337 buf[0] = NUL;
3338 buf[1] = NUL;
3339 switch (get_reg_type(regname, &reglen))
3340 {
3341 case MLINE: buf[0] = 'V'; break;
3342 case MCHAR: buf[0] = 'v'; break;
3343 case MBLOCK:
3344 buf[0] = Ctrl_V;
3345 sprintf((char *)buf + 1, "%ld", reglen + 1);
3346 break;
3347 }
3348 rettv->v_type = VAR_STRING;
3349 rettv->vval.v_string = vim_strsave(buf);
3350}
3351
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003352/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003353 * "gettagstack()" function
3354 */
3355 static void
3356f_gettagstack(typval_T *argvars, typval_T *rettv)
3357{
3358 win_T *wp = curwin; // default is current window
3359
3360 if (rettv_dict_alloc(rettv) != OK)
3361 return;
3362
3363 if (argvars[0].v_type != VAR_UNKNOWN)
3364 {
3365 wp = find_win_by_nr_or_id(&argvars[0]);
3366 if (wp == NULL)
3367 return;
3368 }
3369
3370 get_tagstack(wp, rettv->vval.v_dict);
3371}
3372
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003373// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003374#include "version.h"
3375
3376/*
3377 * "has()" function
3378 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003379 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380f_has(typval_T *argvars, typval_T *rettv)
3381{
3382 int i;
3383 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003384 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003385 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003386 typedef struct {
3387 char *name;
3388 short present;
3389 } has_item_T;
3390 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003392 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003393#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003394 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003395#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003396 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003397#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003398 },
3399 {"arp",
3400#if defined(AMIGA) && defined(FEAT_ARP)
3401 1
3402#else
3403 0
3404#endif
3405 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003406 {"haiku",
3407#ifdef __HAIKU__
3408 1
3409#else
3410 0
3411#endif
3412 },
3413 {"bsd",
3414#if defined(BSD) && !defined(MACOS_X)
3415 1
3416#else
3417 0
3418#endif
3419 },
3420 {"hpux",
3421#ifdef hpux
3422 1
3423#else
3424 0
3425#endif
3426 },
3427 {"linux",
3428#ifdef __linux__
3429 1
3430#else
3431 0
3432#endif
3433 },
3434 {"mac", // Mac OS X (and, once, Mac OS Classic)
3435#ifdef MACOS_X
3436 1
3437#else
3438 0
3439#endif
3440 },
3441 {"osx", // Mac OS X
3442#ifdef MACOS_X
3443 1
3444#else
3445 0
3446#endif
3447 },
3448 {"macunix", // Mac OS X, with the darwin feature
3449#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3450 1
3451#else
3452 0
3453#endif
3454 },
3455 {"osxdarwin", // synonym for macunix
3456#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3457 1
3458#else
3459 0
3460#endif
3461 },
3462 {"qnx",
3463#ifdef __QNX__
3464 1
3465#else
3466 0
3467#endif
3468 },
3469 {"sun",
3470#ifdef SUN_SYSTEM
3471 1
3472#else
3473 0
3474#endif
3475 },
3476 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003477#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003478 1
3479#else
3480 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003481#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003482 },
3483 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003484#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003485 1
3486#else
3487 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003488#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003489 },
3490 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003491#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003492 1
3493#else
3494 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003495#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003496 },
3497 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003498#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003499 1
3500#else
3501 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003502#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003503 },
3504 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003505#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003506 1
3507#else
3508 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003509#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003510 },
3511 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003512#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003513 1
3514#else
3515 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003516#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003517 },
3518 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003519#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003520 1
3521#else
3522 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003523#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003524 },
3525 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003526#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003527 1
3528#else
3529 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003530#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003531 },
3532 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003533#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003534 1
3535#else
3536 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003537#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003538 },
3539 {"autocmd", 1},
3540 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003541#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003542 1
3543#else
3544 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003545#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003546 },
3547 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003548#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003549 1
3550#else
3551 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003552#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003553 },
3554 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003555#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003556 1
3557#else
3558 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003559#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003560 },
3561 {"balloon_multiline",
3562#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3563 // MS-Windows requires runtime check, see below
3564 1
3565#else
3566 0
3567#endif
3568 },
3569 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003570#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003571 1
3572#else
3573 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003574#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003575 },
3576 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003577#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003578 1
3579#else
3580 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003581#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003582 },
3583 {"all_builtin_terms",
3584#if defined(ALL_BUILTIN_TCAPS)
3585 1
3586#else
3587 0
3588#endif
3589 },
3590 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003592 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003593 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003594 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003595#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003596 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003597#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003598 },
3599 {"byte_offset",
3600#ifdef FEAT_BYTEOFF
3601 1
3602#else
3603 0
3604#endif
3605 },
3606 {"channel",
3607#ifdef FEAT_JOB_CHANNEL
3608 1
3609#else
3610 0
3611#endif
3612 },
3613 {"cindent",
3614#ifdef FEAT_CINDENT
3615 1
3616#else
3617 0
3618#endif
3619 },
3620 {"clientserver",
3621#ifdef FEAT_CLIENTSERVER
3622 1
3623#else
3624 0
3625#endif
3626 },
3627 {"clipboard",
3628#ifdef FEAT_CLIPBOARD
3629 1
3630#else
3631 0
3632#endif
3633 },
3634 {"cmdline_compl", 1},
3635 {"cmdline_hist", 1},
3636 {"comments", 1},
3637 {"conceal",
3638#ifdef FEAT_CONCEAL
3639 1
3640#else
3641 0
3642#endif
3643 },
3644 {"cryptv",
3645#ifdef FEAT_CRYPT
3646 1
3647#else
3648 0
3649#endif
3650 },
3651 {"crypt-blowfish",
3652#ifdef FEAT_CRYPT
3653 1
3654#else
3655 0
3656#endif
3657 },
3658 {"crypt-blowfish2",
3659#ifdef FEAT_CRYPT
3660 1
3661#else
3662 0
3663#endif
3664 },
3665 {"cscope",
3666#ifdef FEAT_CSCOPE
3667 1
3668#else
3669 0
3670#endif
3671 },
3672 {"cursorbind", 1},
3673 {"cursorshape",
3674#ifdef CURSOR_SHAPE
3675 1
3676#else
3677 0
3678#endif
3679 },
3680 {"debug",
3681#ifdef DEBUG
3682 1
3683#else
3684 0
3685#endif
3686 },
3687 {"dialog_con",
3688#ifdef FEAT_CON_DIALOG
3689 1
3690#else
3691 0
3692#endif
3693 },
3694 {"dialog_gui",
3695#ifdef FEAT_GUI_DIALOG
3696 1
3697#else
3698 0
3699#endif
3700 },
3701 {"diff",
3702#ifdef FEAT_DIFF
3703 1
3704#else
3705 0
3706#endif
3707 },
3708 {"digraphs",
3709#ifdef FEAT_DIGRAPHS
3710 1
3711#else
3712 0
3713#endif
3714 },
3715 {"directx",
3716#ifdef FEAT_DIRECTX
3717 1
3718#else
3719 0
3720#endif
3721 },
3722 {"dnd",
3723#ifdef FEAT_DND
3724 1
3725#else
3726 0
3727#endif
3728 },
3729 {"emacs_tags",
3730#ifdef FEAT_EMACS_TAGS
3731 1
3732#else
3733 0
3734#endif
3735 },
3736 {"eval", 1}, // always present, of course!
3737 {"ex_extra", 1}, // graduated feature
3738 {"extra_search",
3739#ifdef FEAT_SEARCH_EXTRA
3740 1
3741#else
3742 0
3743#endif
3744 },
3745 {"file_in_path",
3746#ifdef FEAT_SEARCHPATH
3747 1
3748#else
3749 0
3750#endif
3751 },
3752 {"filterpipe",
3753#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3754 1
3755#else
3756 0
3757#endif
3758 },
3759 {"find_in_path",
3760#ifdef FEAT_FIND_ID
3761 1
3762#else
3763 0
3764#endif
3765 },
3766 {"float",
3767#ifdef FEAT_FLOAT
3768 1
3769#else
3770 0
3771#endif
3772 },
3773 {"folding",
3774#ifdef FEAT_FOLDING
3775 1
3776#else
3777 0
3778#endif
3779 },
3780 {"footer",
3781#ifdef FEAT_FOOTER
3782 1
3783#else
3784 0
3785#endif
3786 },
3787 {"fork",
3788#if !defined(USE_SYSTEM) && defined(UNIX)
3789 1
3790#else
3791 0
3792#endif
3793 },
3794 {"gettext",
3795#ifdef FEAT_GETTEXT
3796 1
3797#else
3798 0
3799#endif
3800 },
3801 {"gui",
3802#ifdef FEAT_GUI
3803 1
3804#else
3805 0
3806#endif
3807 },
3808 {"gui_neXtaw",
3809#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3810 1
3811#else
3812 0
3813#endif
3814 },
3815 {"gui_athena",
3816#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3817 1
3818#else
3819 0
3820#endif
3821 },
3822 {"gui_gtk",
3823#ifdef FEAT_GUI_GTK
3824 1
3825#else
3826 0
3827#endif
3828 },
3829 {"gui_gtk2",
3830#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3831 1
3832#else
3833 0
3834#endif
3835 },
3836 {"gui_gtk3",
3837#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3838 1
3839#else
3840 0
3841#endif
3842 },
3843 {"gui_gnome",
3844#ifdef FEAT_GUI_GNOME
3845 1
3846#else
3847 0
3848#endif
3849 },
3850 {"gui_haiku",
3851#ifdef FEAT_GUI_HAIKU
3852 1
3853#else
3854 0
3855#endif
3856 },
3857 {"gui_mac",
3858#ifdef FEAT_GUI_MAC
3859 1
3860#else
3861 0
3862#endif
3863 },
3864 {"gui_motif",
3865#ifdef FEAT_GUI_MOTIF
3866 1
3867#else
3868 0
3869#endif
3870 },
3871 {"gui_photon",
3872#ifdef FEAT_GUI_PHOTON
3873 1
3874#else
3875 0
3876#endif
3877 },
3878 {"gui_win32",
3879#ifdef FEAT_GUI_MSWIN
3880 1
3881#else
3882 0
3883#endif
3884 },
3885 {"iconv",
3886#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3887 1
3888#else
3889 0
3890#endif
3891 },
3892 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003893 {"ipv6",
3894#ifdef FEAT_IPV6
3895 1
3896#else
3897 0
3898#endif
3899 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003900 {"job",
3901#ifdef FEAT_JOB_CHANNEL
3902 1
3903#else
3904 0
3905#endif
3906 },
3907 {"jumplist",
3908#ifdef FEAT_JUMPLIST
3909 1
3910#else
3911 0
3912#endif
3913 },
3914 {"keymap",
3915#ifdef FEAT_KEYMAP
3916 1
3917#else
3918 0
3919#endif
3920 },
3921 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
3922 {"langmap",
3923#ifdef FEAT_LANGMAP
3924 1
3925#else
3926 0
3927#endif
3928 },
3929 {"libcall",
3930#ifdef FEAT_LIBCALL
3931 1
3932#else
3933 0
3934#endif
3935 },
3936 {"linebreak",
3937#ifdef FEAT_LINEBREAK
3938 1
3939#else
3940 0
3941#endif
3942 },
3943 {"lispindent",
3944#ifdef FEAT_LISP
3945 1
3946#else
3947 0
3948#endif
3949 },
3950 {"listcmds", 1},
3951 {"localmap", 1},
3952 {"lua",
3953#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
3954 1
3955#else
3956 0
3957#endif
3958 },
3959 {"menu",
3960#ifdef FEAT_MENU
3961 1
3962#else
3963 0
3964#endif
3965 },
3966 {"mksession",
3967#ifdef FEAT_SESSION
3968 1
3969#else
3970 0
3971#endif
3972 },
3973 {"modify_fname", 1},
3974 {"mouse", 1},
3975 {"mouseshape",
3976#ifdef FEAT_MOUSESHAPE
3977 1
3978#else
3979 0
3980#endif
3981 },
3982 {"mouse_dec",
3983#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
3984 1
3985#else
3986 0
3987#endif
3988 },
3989 {"mouse_gpm",
3990#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
3991 1
3992#else
3993 0
3994#endif
3995 },
3996 {"mouse_jsbterm",
3997#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
3998 1
3999#else
4000 0
4001#endif
4002 },
4003 {"mouse_netterm",
4004#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
4005 1
4006#else
4007 0
4008#endif
4009 },
4010 {"mouse_pterm",
4011#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
4012 1
4013#else
4014 0
4015#endif
4016 },
4017 {"mouse_sgr",
4018#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4019 1
4020#else
4021 0
4022#endif
4023 },
4024 {"mouse_sysmouse",
4025#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4026 1
4027#else
4028 0
4029#endif
4030 },
4031 {"mouse_urxvt",
4032#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4033 1
4034#else
4035 0
4036#endif
4037 },
4038 {"mouse_xterm",
4039#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4040 1
4041#else
4042 0
4043#endif
4044 },
4045 {"multi_byte", 1},
4046 {"multi_byte_ime",
4047#ifdef FEAT_MBYTE_IME
4048 1
4049#else
4050 0
4051#endif
4052 },
4053 {"multi_lang",
4054#ifdef FEAT_MULTI_LANG
4055 1
4056#else
4057 0
4058#endif
4059 },
4060 {"mzscheme",
4061#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4062 1
4063#else
4064 0
4065#endif
4066 },
4067 {"num64", 1},
4068 {"ole",
4069#ifdef FEAT_OLE
4070 1
4071#else
4072 0
4073#endif
4074 },
4075 {"packages",
4076#ifdef FEAT_EVAL
4077 1
4078#else
4079 0
4080#endif
4081 },
4082 {"path_extra",
4083#ifdef FEAT_PATH_EXTRA
4084 1
4085#else
4086 0
4087#endif
4088 },
4089 {"perl",
4090#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4091 1
4092#else
4093 0
4094#endif
4095 },
4096 {"persistent_undo",
4097#ifdef FEAT_PERSISTENT_UNDO
4098 1
4099#else
4100 0
4101#endif
4102 },
4103 {"python_compiled",
4104#if defined(FEAT_PYTHON)
4105 1
4106#else
4107 0
4108#endif
4109 },
4110 {"python_dynamic",
4111#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4112 1
4113#else
4114 0
4115#endif
4116 },
4117 {"python",
4118#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4119 1
4120#else
4121 0
4122#endif
4123 },
4124 {"pythonx",
4125#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4126 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4127 1
4128#else
4129 0
4130#endif
4131 },
4132 {"python3_compiled",
4133#if defined(FEAT_PYTHON3)
4134 1
4135#else
4136 0
4137#endif
4138 },
4139 {"python3_dynamic",
4140#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4141 1
4142#else
4143 0
4144#endif
4145 },
4146 {"python3",
4147#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4148 1
4149#else
4150 0
4151#endif
4152 },
4153 {"popupwin",
4154#ifdef FEAT_PROP_POPUP
4155 1
4156#else
4157 0
4158#endif
4159 },
4160 {"postscript",
4161#ifdef FEAT_POSTSCRIPT
4162 1
4163#else
4164 0
4165#endif
4166 },
4167 {"printer",
4168#ifdef FEAT_PRINTER
4169 1
4170#else
4171 0
4172#endif
4173 },
4174 {"profile",
4175#ifdef FEAT_PROFILE
4176 1
4177#else
4178 0
4179#endif
4180 },
4181 {"reltime",
4182#ifdef FEAT_RELTIME
4183 1
4184#else
4185 0
4186#endif
4187 },
4188 {"quickfix",
4189#ifdef FEAT_QUICKFIX
4190 1
4191#else
4192 0
4193#endif
4194 },
4195 {"rightleft",
4196#ifdef FEAT_RIGHTLEFT
4197 1
4198#else
4199 0
4200#endif
4201 },
4202 {"ruby",
4203#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4204 1
4205#else
4206 0
4207#endif
4208 },
4209 {"scrollbind", 1},
4210 {"showcmd",
4211#ifdef FEAT_CMDL_INFO
4212 1
4213#else
4214 0
4215#endif
4216 },
4217 {"cmdline_info",
4218#ifdef FEAT_CMDL_INFO
4219 1
4220#else
4221 0
4222#endif
4223 },
4224 {"signs",
4225#ifdef FEAT_SIGNS
4226 1
4227#else
4228 0
4229#endif
4230 },
4231 {"smartindent",
4232#ifdef FEAT_SMARTINDENT
4233 1
4234#else
4235 0
4236#endif
4237 },
4238 {"startuptime",
4239#ifdef STARTUPTIME
4240 1
4241#else
4242 0
4243#endif
4244 },
4245 {"statusline",
4246#ifdef FEAT_STL_OPT
4247 1
4248#else
4249 0
4250#endif
4251 },
4252 {"netbeans_intg",
4253#ifdef FEAT_NETBEANS_INTG
4254 1
4255#else
4256 0
4257#endif
4258 },
4259 {"sound",
4260#ifdef FEAT_SOUND
4261 1
4262#else
4263 0
4264#endif
4265 },
4266 {"spell",
4267#ifdef FEAT_SPELL
4268 1
4269#else
4270 0
4271#endif
4272 },
4273 {"syntax",
4274#ifdef FEAT_SYN_HL
4275 1
4276#else
4277 0
4278#endif
4279 },
4280 {"system",
4281#if defined(USE_SYSTEM) || !defined(UNIX)
4282 1
4283#else
4284 0
4285#endif
4286 },
4287 {"tag_binary",
4288#ifdef FEAT_TAG_BINS
4289 1
4290#else
4291 0
4292#endif
4293 },
4294 {"tcl",
4295#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4296 1
4297#else
4298 0
4299#endif
4300 },
4301 {"termguicolors",
4302#ifdef FEAT_TERMGUICOLORS
4303 1
4304#else
4305 0
4306#endif
4307 },
4308 {"terminal",
4309#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4310 1
4311#else
4312 0
4313#endif
4314 },
4315 {"terminfo",
4316#ifdef TERMINFO
4317 1
4318#else
4319 0
4320#endif
4321 },
4322 {"termresponse",
4323#ifdef FEAT_TERMRESPONSE
4324 1
4325#else
4326 0
4327#endif
4328 },
4329 {"textobjects",
4330#ifdef FEAT_TEXTOBJ
4331 1
4332#else
4333 0
4334#endif
4335 },
4336 {"textprop",
4337#ifdef FEAT_PROP_POPUP
4338 1
4339#else
4340 0
4341#endif
4342 },
4343 {"tgetent",
4344#ifdef HAVE_TGETENT
4345 1
4346#else
4347 0
4348#endif
4349 },
4350 {"timers",
4351#ifdef FEAT_TIMERS
4352 1
4353#else
4354 0
4355#endif
4356 },
4357 {"title",
4358#ifdef FEAT_TITLE
4359 1
4360#else
4361 0
4362#endif
4363 },
4364 {"toolbar",
4365#ifdef FEAT_TOOLBAR
4366 1
4367#else
4368 0
4369#endif
4370 },
4371 {"unnamedplus",
4372#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4373 1
4374#else
4375 0
4376#endif
4377 },
4378 {"user-commands", 1}, // was accidentally included in 5.4
4379 {"user_commands", 1},
4380 {"vartabs",
4381#ifdef FEAT_VARTABS
4382 1
4383#else
4384 0
4385#endif
4386 },
4387 {"vertsplit", 1},
4388 {"viminfo",
4389#ifdef FEAT_VIMINFO
4390 1
4391#else
4392 0
4393#endif
4394 },
4395 {"vimscript-1", 1},
4396 {"vimscript-2", 1},
4397 {"vimscript-3", 1},
4398 {"vimscript-4", 1},
4399 {"virtualedit", 1},
4400 {"visual", 1},
4401 {"visualextra", 1},
4402 {"vreplace", 1},
4403 {"vtp",
4404#ifdef FEAT_VTP
4405 1
4406#else
4407 0
4408#endif
4409 },
4410 {"wildignore",
4411#ifdef FEAT_WILDIGN
4412 1
4413#else
4414 0
4415#endif
4416 },
4417 {"wildmenu",
4418#ifdef FEAT_WILDMENU
4419 1
4420#else
4421 0
4422#endif
4423 },
4424 {"windows", 1},
4425 {"winaltkeys",
4426#ifdef FEAT_WAK
4427 1
4428#else
4429 0
4430#endif
4431 },
4432 {"writebackup",
4433#ifdef FEAT_WRITEBACKUP
4434 1
4435#else
4436 0
4437#endif
4438 },
4439 {"xim",
4440#ifdef FEAT_XIM
4441 1
4442#else
4443 0
4444#endif
4445 },
4446 {"xfontset",
4447#ifdef FEAT_XFONTSET
4448 1
4449#else
4450 0
4451#endif
4452 },
4453 {"xpm",
4454#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4455 1
4456#else
4457 0
4458#endif
4459 },
4460 {"xpm_w32", // for backward compatibility
4461#ifdef FEAT_XPM_W32
4462 1
4463#else
4464 0
4465#endif
4466 },
4467 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004468#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004469 1
4470#else
4471 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004472#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004473 },
4474 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004475#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004476 1
4477#else
4478 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004480 },
4481 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004482#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004483 1
4484#else
4485 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004486#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004487 },
4488 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004489#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004490 1
4491#else
4492 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004493#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004494 },
4495 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004496#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004497 1
4498#else
4499 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004500#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004501 },
4502 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004503 };
4504
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004505 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004506 for (i = 0; has_list[i].name != NULL; ++i)
4507 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004508 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004509 x = TRUE;
4510 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004511 break;
4512 }
4513
Bram Moolenaar79296512020-03-22 16:17:14 +01004514 // features also in has_list[] but sometimes enabled at runtime
4515 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004516 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004517 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004518 {
4519 // intentionally empty
4520 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004521#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004522 else if (STRICMP(name, "balloon_multiline") == 0)
4523 n = multiline_balloon_available();
4524#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004525#ifdef VIMDLL
4526 else if (STRICMP(name, "filterpipe") == 0)
4527 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004528#endif
4529#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4530 else if (STRICMP(name, "iconv") == 0)
4531 n = iconv_enabled(FALSE);
4532#endif
4533#ifdef DYNAMIC_LUA
4534 else if (STRICMP(name, "lua") == 0)
4535 n = lua_enabled(FALSE);
4536#endif
4537#ifdef DYNAMIC_MZSCHEME
4538 else if (STRICMP(name, "mzscheme") == 0)
4539 n = mzscheme_enabled(FALSE);
4540#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004541#ifdef DYNAMIC_PERL
4542 else if (STRICMP(name, "perl") == 0)
4543 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004544#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004545#ifdef DYNAMIC_PYTHON
4546 else if (STRICMP(name, "python") == 0)
4547 n = python_enabled(FALSE);
4548#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549#ifdef DYNAMIC_PYTHON3
4550 else if (STRICMP(name, "python3") == 0)
4551 n = python3_enabled(FALSE);
4552#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004553#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4554 else if (STRICMP(name, "pythonx") == 0)
4555 {
4556# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4557 if (p_pyx == 0)
4558 n = python3_enabled(FALSE) || python_enabled(FALSE);
4559 else if (p_pyx == 3)
4560 n = python3_enabled(FALSE);
4561 else if (p_pyx == 2)
4562 n = python_enabled(FALSE);
4563# elif defined(DYNAMIC_PYTHON)
4564 n = python_enabled(FALSE);
4565# elif defined(DYNAMIC_PYTHON3)
4566 n = python3_enabled(FALSE);
4567# endif
4568 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004569#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004570#ifdef DYNAMIC_RUBY
4571 else if (STRICMP(name, "ruby") == 0)
4572 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004573#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004574#ifdef DYNAMIC_TCL
4575 else if (STRICMP(name, "tcl") == 0)
4576 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004577#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004578#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004579 else if (STRICMP(name, "terminal") == 0)
4580 n = terminal_enabled();
4581#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004582 }
4583
Bram Moolenaar79296512020-03-22 16:17:14 +01004584 // features not in has_list[]
4585 if (x == FALSE)
4586 {
4587 if (STRNICMP(name, "patch", 5) == 0)
4588 {
4589 x = TRUE;
4590 if (name[5] == '-'
4591 && STRLEN(name) >= 11
4592 && vim_isdigit(name[6])
4593 && vim_isdigit(name[8])
4594 && vim_isdigit(name[10]))
4595 {
4596 int major = atoi((char *)name + 6);
4597 int minor = atoi((char *)name + 8);
4598
4599 // Expect "patch-9.9.01234".
4600 n = (major < VIM_VERSION_MAJOR
4601 || (major == VIM_VERSION_MAJOR
4602 && (minor < VIM_VERSION_MINOR
4603 || (minor == VIM_VERSION_MINOR
4604 && has_patch(atoi((char *)name + 10))))));
4605 }
4606 else
4607 n = has_patch(atoi((char *)name + 5));
4608 }
4609 else if (STRICMP(name, "vim_starting") == 0)
4610 {
4611 x = TRUE;
4612 n = (starting != 0);
4613 }
4614 else if (STRICMP(name, "ttyin") == 0)
4615 {
4616 x = TRUE;
4617 n = mch_input_isatty();
4618 }
4619 else if (STRICMP(name, "ttyout") == 0)
4620 {
4621 x = TRUE;
4622 n = stdout_isatty;
4623 }
4624 else if (STRICMP(name, "multi_byte_encoding") == 0)
4625 {
4626 x = TRUE;
4627 n = has_mbyte;
4628 }
4629 else if (STRICMP(name, "gui_running") == 0)
4630 {
4631 x = TRUE;
4632#ifdef FEAT_GUI
4633 n = (gui.in_use || gui.starting);
4634#endif
4635 }
4636 else if (STRICMP(name, "browse") == 0)
4637 {
4638 x = TRUE;
4639#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4640 n = gui.in_use; // gui_mch_browse() works when GUI is running
4641#endif
4642 }
4643 else if (STRICMP(name, "syntax_items") == 0)
4644 {
4645 x = TRUE;
4646#ifdef FEAT_SYN_HL
4647 n = syntax_present(curwin);
4648#endif
4649 }
4650 else if (STRICMP(name, "vcon") == 0)
4651 {
4652 x = TRUE;
4653#ifdef FEAT_VTP
4654 n = is_term_win32() && has_vtp_working();
4655#endif
4656 }
4657 else if (STRICMP(name, "netbeans_enabled") == 0)
4658 {
4659 x = TRUE;
4660#ifdef FEAT_NETBEANS_INTG
4661 n = netbeans_active();
4662#endif
4663 }
4664 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4665 {
4666 x = TRUE;
4667#ifdef FEAT_MOUSE_GPM
4668 n = gpm_enabled();
4669#endif
4670 }
4671 else if (STRICMP(name, "conpty") == 0)
4672 {
4673 x = TRUE;
4674#if defined(FEAT_TERMINAL) && defined(MSWIN)
4675 n = use_conpty();
4676#endif
4677 }
4678 else if (STRICMP(name, "clipboard_working") == 0)
4679 {
4680 x = TRUE;
4681#ifdef FEAT_CLIPBOARD
4682 n = clip_star.available;
4683#endif
4684 }
4685 }
4686
4687 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4688 // return whether feature could ever be enabled
4689 rettv->vval.v_number = x;
4690 else
4691 // return whether feature is enabled
4692 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693}
4694
4695/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004696 * "haslocaldir()" function
4697 */
4698 static void
4699f_haslocaldir(typval_T *argvars, typval_T *rettv)
4700{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004701 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702 win_T *wp = NULL;
4703
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004704 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4705
4706 // Check for window-local and tab-local directories
4707 if (wp != NULL && wp->w_localdir != NULL)
4708 rettv->vval.v_number = 1;
4709 else if (tp != NULL && tp->tp_localdir != NULL)
4710 rettv->vval.v_number = 2;
4711 else
4712 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004713}
4714
4715/*
4716 * "hasmapto()" function
4717 */
4718 static void
4719f_hasmapto(typval_T *argvars, typval_T *rettv)
4720{
4721 char_u *name;
4722 char_u *mode;
4723 char_u buf[NUMBUFLEN];
4724 int abbr = FALSE;
4725
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004726 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004727 if (argvars[1].v_type == VAR_UNKNOWN)
4728 mode = (char_u *)"nvo";
4729 else
4730 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004731 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004733 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 }
4735
4736 if (map_to_exists(name, mode, abbr))
4737 rettv->vval.v_number = TRUE;
4738 else
4739 rettv->vval.v_number = FALSE;
4740}
4741
4742/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004743 * "highlightID(name)" function
4744 */
4745 static void
4746f_hlID(typval_T *argvars, typval_T *rettv)
4747{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004748 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004749}
4750
4751/*
4752 * "highlight_exists()" function
4753 */
4754 static void
4755f_hlexists(typval_T *argvars, typval_T *rettv)
4756{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004757 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758}
4759
4760/*
4761 * "hostname()" function
4762 */
4763 static void
4764f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4765{
4766 char_u hostname[256];
4767
4768 mch_get_host_name(hostname, 256);
4769 rettv->v_type = VAR_STRING;
4770 rettv->vval.v_string = vim_strsave(hostname);
4771}
4772
4773/*
4774 * iconv() function
4775 */
4776 static void
4777f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4778{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004779 char_u buf1[NUMBUFLEN];
4780 char_u buf2[NUMBUFLEN];
4781 char_u *from, *to, *str;
4782 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004783
4784 rettv->v_type = VAR_STRING;
4785 rettv->vval.v_string = NULL;
4786
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004787 str = tv_get_string(&argvars[0]);
4788 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4789 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004790 vimconv.vc_type = CONV_NONE;
4791 convert_setup(&vimconv, from, to);
4792
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004793 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004794 if (vimconv.vc_type == CONV_NONE)
4795 rettv->vval.v_string = vim_strsave(str);
4796 else
4797 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4798
4799 convert_setup(&vimconv, NULL, NULL);
4800 vim_free(from);
4801 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004802}
4803
4804/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004805 * "index()" function
4806 */
4807 static void
4808f_index(typval_T *argvars, typval_T *rettv)
4809{
4810 list_T *l;
4811 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004812 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004813 long idx = 0;
4814 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004815 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004816
4817 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004818 if (argvars[0].v_type == VAR_BLOB)
4819 {
4820 typval_T tv;
4821 int start = 0;
4822
4823 if (argvars[2].v_type != VAR_UNKNOWN)
4824 {
4825 start = tv_get_number_chk(&argvars[2], &error);
4826 if (error)
4827 return;
4828 }
4829 b = argvars[0].vval.v_blob;
4830 if (b == NULL)
4831 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004832 if (start < 0)
4833 {
4834 start = blob_len(b) + start;
4835 if (start < 0)
4836 start = 0;
4837 }
4838
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004839 for (idx = start; idx < blob_len(b); ++idx)
4840 {
4841 tv.v_type = VAR_NUMBER;
4842 tv.vval.v_number = blob_get(b, idx);
4843 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4844 {
4845 rettv->vval.v_number = idx;
4846 return;
4847 }
4848 }
4849 return;
4850 }
4851 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004853 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004854 return;
4855 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004856
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004857 l = argvars[0].vval.v_list;
4858 if (l != NULL)
4859 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004860 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861 item = l->lv_first;
4862 if (argvars[2].v_type != VAR_UNKNOWN)
4863 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004864 // Start at specified item. Use the cached index that list_find()
4865 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004866 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004867 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004868 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004869 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004870 if (error)
4871 item = NULL;
4872 }
4873
4874 for ( ; item != NULL; item = item->li_next, ++idx)
4875 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4876 {
4877 rettv->vval.v_number = idx;
4878 break;
4879 }
4880 }
4881}
4882
4883static int inputsecret_flag = 0;
4884
4885/*
4886 * "input()" function
4887 * Also handles inputsecret() when inputsecret is set.
4888 */
4889 static void
4890f_input(typval_T *argvars, typval_T *rettv)
4891{
4892 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4893}
4894
4895/*
4896 * "inputdialog()" function
4897 */
4898 static void
4899f_inputdialog(typval_T *argvars, typval_T *rettv)
4900{
4901#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004902 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4904 {
4905 char_u *message;
4906 char_u buf[NUMBUFLEN];
4907 char_u *defstr = (char_u *)"";
4908
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004909 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004911 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004912 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4913 else
4914 IObuff[0] = NUL;
4915 if (message != NULL && defstr != NULL
4916 && do_dialog(VIM_QUESTION, NULL, message,
4917 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4918 rettv->vval.v_string = vim_strsave(IObuff);
4919 else
4920 {
4921 if (message != NULL && defstr != NULL
4922 && argvars[1].v_type != VAR_UNKNOWN
4923 && argvars[2].v_type != VAR_UNKNOWN)
4924 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004925 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004926 else
4927 rettv->vval.v_string = NULL;
4928 }
4929 rettv->v_type = VAR_STRING;
4930 }
4931 else
4932#endif
4933 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4934}
4935
4936/*
4937 * "inputlist()" function
4938 */
4939 static void
4940f_inputlist(typval_T *argvars, typval_T *rettv)
4941{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004942 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004943 listitem_T *li;
4944 int selected;
4945 int mouse_used;
4946
4947#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004948 // While starting up, there is no place to enter text. When running tests
4949 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004950 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004951 return;
4952#endif
4953 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4954 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004955 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004956 return;
4957 }
4958
4959 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004960 msg_row = Rows - 1; // for when 'cmdheight' > 1
4961 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004962 msg_scroll = TRUE;
4963 msg_clr_eos();
4964
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004965 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004966 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02004967 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004968 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004969 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004970 msg_putchar('\n');
4971 }
4972
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004973 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004974 selected = prompt_for_number(&mouse_used);
4975 if (mouse_used)
4976 selected -= lines_left;
4977
4978 rettv->vval.v_number = selected;
4979}
4980
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004981static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4982
4983/*
4984 * "inputrestore()" function
4985 */
4986 static void
4987f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4988{
4989 if (ga_userinput.ga_len > 0)
4990 {
4991 --ga_userinput.ga_len;
4992 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4993 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004994 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004995 }
4996 else if (p_verbose > 1)
4997 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004998 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004999 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000 }
5001}
5002
5003/*
5004 * "inputsave()" function
5005 */
5006 static void
5007f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5008{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005009 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005010 if (ga_grow(&ga_userinput, 1) == OK)
5011 {
5012 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5013 + ga_userinput.ga_len);
5014 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005015 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005016 }
5017 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005018 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005019}
5020
5021/*
5022 * "inputsecret()" function
5023 */
5024 static void
5025f_inputsecret(typval_T *argvars, typval_T *rettv)
5026{
5027 ++cmdline_star;
5028 ++inputsecret_flag;
5029 f_input(argvars, rettv);
5030 --cmdline_star;
5031 --inputsecret_flag;
5032}
5033
5034/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005035 * "interrupt()" function
5036 */
5037 static void
5038f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5039{
5040 got_int = TRUE;
5041}
5042
5043/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044 * "invert(expr)" function
5045 */
5046 static void
5047f_invert(typval_T *argvars, typval_T *rettv)
5048{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005049 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005050}
5051
5052/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053 * "islocked()" function
5054 */
5055 static void
5056f_islocked(typval_T *argvars, typval_T *rettv)
5057{
5058 lval_T lv;
5059 char_u *end;
5060 dictitem_T *di;
5061
5062 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005063 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005064 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065 if (end != NULL && lv.ll_name != NULL)
5066 {
5067 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005068 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005069 else
5070 {
5071 if (lv.ll_tv == NULL)
5072 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005073 di = find_var(lv.ll_name, NULL, TRUE);
5074 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005076 // Consider a variable locked when:
5077 // 1. the variable itself is locked
5078 // 2. the value of the variable is locked.
5079 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005080 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5081 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005082 }
5083 }
5084 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005085 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005086 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005087 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005088 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005089 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005090 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5091 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005092 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005093 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5094 }
5095 }
5096
5097 clear_lval(&lv);
5098}
5099
5100#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5101/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005102 * "isinf()" function
5103 */
5104 static void
5105f_isinf(typval_T *argvars, typval_T *rettv)
5106{
5107 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5108 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5109}
5110
5111/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005112 * "isnan()" function
5113 */
5114 static void
5115f_isnan(typval_T *argvars, typval_T *rettv)
5116{
5117 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5118 && isnan(argvars[0].vval.v_float);
5119}
5120#endif
5121
5122/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005123 * "last_buffer_nr()" function.
5124 */
5125 static void
5126f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5127{
5128 int n = 0;
5129 buf_T *buf;
5130
Bram Moolenaar29323592016-07-24 22:04:11 +02005131 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005132 if (n < buf->b_fnum)
5133 n = buf->b_fnum;
5134
5135 rettv->vval.v_number = n;
5136}
5137
5138/*
5139 * "len()" function
5140 */
5141 static void
5142f_len(typval_T *argvars, typval_T *rettv)
5143{
5144 switch (argvars[0].v_type)
5145 {
5146 case VAR_STRING:
5147 case VAR_NUMBER:
5148 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005149 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005150 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005151 case VAR_BLOB:
5152 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5153 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005154 case VAR_LIST:
5155 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5156 break;
5157 case VAR_DICT:
5158 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5159 break;
5160 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005161 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005162 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005163 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005164 case VAR_SPECIAL:
5165 case VAR_FLOAT:
5166 case VAR_FUNC:
5167 case VAR_PARTIAL:
5168 case VAR_JOB:
5169 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005170 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171 break;
5172 }
5173}
5174
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005175 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005176libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005177{
5178#ifdef FEAT_LIBCALL
5179 char_u *string_in;
5180 char_u **string_result;
5181 int nr_result;
5182#endif
5183
5184 rettv->v_type = type;
5185 if (type != VAR_NUMBER)
5186 rettv->vval.v_string = NULL;
5187
5188 if (check_restricted() || check_secure())
5189 return;
5190
5191#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005192 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5194 {
5195 string_in = NULL;
5196 if (argvars[2].v_type == VAR_STRING)
5197 string_in = argvars[2].vval.v_string;
5198 if (type == VAR_NUMBER)
5199 string_result = NULL;
5200 else
5201 string_result = &rettv->vval.v_string;
5202 if (mch_libcall(argvars[0].vval.v_string,
5203 argvars[1].vval.v_string,
5204 string_in,
5205 argvars[2].vval.v_number,
5206 string_result,
5207 &nr_result) == OK
5208 && type == VAR_NUMBER)
5209 rettv->vval.v_number = nr_result;
5210 }
5211#endif
5212}
5213
5214/*
5215 * "libcall()" function
5216 */
5217 static void
5218f_libcall(typval_T *argvars, typval_T *rettv)
5219{
5220 libcall_common(argvars, rettv, VAR_STRING);
5221}
5222
5223/*
5224 * "libcallnr()" function
5225 */
5226 static void
5227f_libcallnr(typval_T *argvars, typval_T *rettv)
5228{
5229 libcall_common(argvars, rettv, VAR_NUMBER);
5230}
5231
5232/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005233 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005234 */
5235 static void
5236f_line(typval_T *argvars, typval_T *rettv)
5237{
5238 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005239 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005240 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005241 int id;
5242 tabpage_T *tp;
5243 win_T *wp;
5244 win_T *save_curwin;
5245 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005246
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005247 if (argvars[1].v_type != VAR_UNKNOWN)
5248 {
5249 // use window specified in the second argument
5250 id = (int)tv_get_number(&argvars[1]);
5251 wp = win_id2wp_tp(id, &tp);
5252 if (wp != NULL && tp != NULL)
5253 {
5254 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5255 == OK)
5256 {
5257 check_cursor();
5258 fp = var2fpos(&argvars[0], TRUE, &fnum);
5259 }
5260 restore_win_noblock(save_curwin, save_curtab, TRUE);
5261 }
5262 }
5263 else
5264 // use current window
5265 fp = var2fpos(&argvars[0], TRUE, &fnum);
5266
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005267 if (fp != NULL)
5268 lnum = fp->lnum;
5269 rettv->vval.v_number = lnum;
5270}
5271
5272/*
5273 * "line2byte(lnum)" function
5274 */
5275 static void
5276f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5277{
5278#ifndef FEAT_BYTEOFF
5279 rettv->vval.v_number = -1;
5280#else
5281 linenr_T lnum;
5282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005283 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005284 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5285 rettv->vval.v_number = -1;
5286 else
5287 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5288 if (rettv->vval.v_number >= 0)
5289 ++rettv->vval.v_number;
5290#endif
5291}
5292
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005293#ifdef FEAT_FLOAT
5294/*
5295 * "log()" function
5296 */
5297 static void
5298f_log(typval_T *argvars, typval_T *rettv)
5299{
5300 float_T f = 0.0;
5301
5302 rettv->v_type = VAR_FLOAT;
5303 if (get_float_arg(argvars, &f) == OK)
5304 rettv->vval.v_float = log(f);
5305 else
5306 rettv->vval.v_float = 0.0;
5307}
5308
5309/*
5310 * "log10()" function
5311 */
5312 static void
5313f_log10(typval_T *argvars, typval_T *rettv)
5314{
5315 float_T f = 0.0;
5316
5317 rettv->v_type = VAR_FLOAT;
5318 if (get_float_arg(argvars, &f) == OK)
5319 rettv->vval.v_float = log10(f);
5320 else
5321 rettv->vval.v_float = 0.0;
5322}
5323#endif
5324
5325#ifdef FEAT_LUA
5326/*
5327 * "luaeval()" function
5328 */
5329 static void
5330f_luaeval(typval_T *argvars, typval_T *rettv)
5331{
5332 char_u *str;
5333 char_u buf[NUMBUFLEN];
5334
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005335 if (check_restricted() || check_secure())
5336 return;
5337
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005338 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005339 do_luaeval(str, argvars + 1, rettv);
5340}
5341#endif
5342
5343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005344 * "maparg()" function
5345 */
5346 static void
5347f_maparg(typval_T *argvars, typval_T *rettv)
5348{
5349 get_maparg(argvars, rettv, TRUE);
5350}
5351
5352/*
5353 * "mapcheck()" function
5354 */
5355 static void
5356f_mapcheck(typval_T *argvars, typval_T *rettv)
5357{
5358 get_maparg(argvars, rettv, FALSE);
5359}
5360
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005361typedef enum
5362{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005363 MATCH_END, // matchend()
5364 MATCH_MATCH, // match()
5365 MATCH_STR, // matchstr()
5366 MATCH_LIST, // matchlist()
5367 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005368} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005369
5370 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005371find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005372{
5373 char_u *str = NULL;
5374 long len = 0;
5375 char_u *expr = NULL;
5376 char_u *pat;
5377 regmatch_T regmatch;
5378 char_u patbuf[NUMBUFLEN];
5379 char_u strbuf[NUMBUFLEN];
5380 char_u *save_cpo;
5381 long start = 0;
5382 long nth = 1;
5383 colnr_T startcol = 0;
5384 int match = 0;
5385 list_T *l = NULL;
5386 listitem_T *li = NULL;
5387 long idx = 0;
5388 char_u *tofree = NULL;
5389
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005390 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005391 save_cpo = p_cpo;
5392 p_cpo = (char_u *)"";
5393
5394 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005395 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005396 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005397 // type MATCH_LIST: return empty list when there are no matches.
5398 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005399 if (rettv_list_alloc(rettv) == FAIL)
5400 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005401 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005402 && (list_append_string(rettv->vval.v_list,
5403 (char_u *)"", 0) == FAIL
5404 || list_append_number(rettv->vval.v_list,
5405 (varnumber_T)-1) == FAIL
5406 || list_append_number(rettv->vval.v_list,
5407 (varnumber_T)-1) == FAIL
5408 || list_append_number(rettv->vval.v_list,
5409 (varnumber_T)-1) == FAIL))
5410 {
5411 list_free(rettv->vval.v_list);
5412 rettv->vval.v_list = NULL;
5413 goto theend;
5414 }
5415 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005416 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 {
5418 rettv->v_type = VAR_STRING;
5419 rettv->vval.v_string = NULL;
5420 }
5421
5422 if (argvars[0].v_type == VAR_LIST)
5423 {
5424 if ((l = argvars[0].vval.v_list) == NULL)
5425 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005426 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005427 li = l->lv_first;
5428 }
5429 else
5430 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005431 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005432 len = (long)STRLEN(str);
5433 }
5434
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005435 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005436 if (pat == NULL)
5437 goto theend;
5438
5439 if (argvars[2].v_type != VAR_UNKNOWN)
5440 {
5441 int error = FALSE;
5442
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005443 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005444 if (error)
5445 goto theend;
5446 if (l != NULL)
5447 {
5448 li = list_find(l, start);
5449 if (li == NULL)
5450 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005451 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452 }
5453 else
5454 {
5455 if (start < 0)
5456 start = 0;
5457 if (start > len)
5458 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005459 // When "count" argument is there ignore matches before "start",
5460 // otherwise skip part of the string. Differs when pattern is "^"
5461 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005462 if (argvars[3].v_type != VAR_UNKNOWN)
5463 startcol = start;
5464 else
5465 {
5466 str += start;
5467 len -= start;
5468 }
5469 }
5470
5471 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005472 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473 if (error)
5474 goto theend;
5475 }
5476
5477 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5478 if (regmatch.regprog != NULL)
5479 {
5480 regmatch.rm_ic = p_ic;
5481
5482 for (;;)
5483 {
5484 if (l != NULL)
5485 {
5486 if (li == NULL)
5487 {
5488 match = FALSE;
5489 break;
5490 }
5491 vim_free(tofree);
5492 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5493 if (str == NULL)
5494 break;
5495 }
5496
5497 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5498
5499 if (match && --nth <= 0)
5500 break;
5501 if (l == NULL && !match)
5502 break;
5503
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005504 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005505 if (l != NULL)
5506 {
5507 li = li->li_next;
5508 ++idx;
5509 }
5510 else
5511 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005512 startcol = (colnr_T)(regmatch.startp[0]
5513 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514 if (startcol > (colnr_T)len
5515 || str + startcol <= regmatch.startp[0])
5516 {
5517 match = FALSE;
5518 break;
5519 }
5520 }
5521 }
5522
5523 if (match)
5524 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005525 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005526 {
5527 listitem_T *li1 = rettv->vval.v_list->lv_first;
5528 listitem_T *li2 = li1->li_next;
5529 listitem_T *li3 = li2->li_next;
5530 listitem_T *li4 = li3->li_next;
5531
5532 vim_free(li1->li_tv.vval.v_string);
5533 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005534 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005535 li3->li_tv.vval.v_number =
5536 (varnumber_T)(regmatch.startp[0] - expr);
5537 li4->li_tv.vval.v_number =
5538 (varnumber_T)(regmatch.endp[0] - expr);
5539 if (l != NULL)
5540 li2->li_tv.vval.v_number = (varnumber_T)idx;
5541 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005542 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005543 {
5544 int i;
5545
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005546 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005547 for (i = 0; i < NSUBEXP; ++i)
5548 {
5549 if (regmatch.endp[i] == NULL)
5550 {
5551 if (list_append_string(rettv->vval.v_list,
5552 (char_u *)"", 0) == FAIL)
5553 break;
5554 }
5555 else if (list_append_string(rettv->vval.v_list,
5556 regmatch.startp[i],
5557 (int)(regmatch.endp[i] - regmatch.startp[i]))
5558 == FAIL)
5559 break;
5560 }
5561 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005562 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005563 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005564 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005565 if (l != NULL)
5566 copy_tv(&li->li_tv, rettv);
5567 else
5568 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005569 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005570 }
5571 else if (l != NULL)
5572 rettv->vval.v_number = idx;
5573 else
5574 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005575 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005576 rettv->vval.v_number =
5577 (varnumber_T)(regmatch.startp[0] - str);
5578 else
5579 rettv->vval.v_number =
5580 (varnumber_T)(regmatch.endp[0] - str);
5581 rettv->vval.v_number += (varnumber_T)(str - expr);
5582 }
5583 }
5584 vim_regfree(regmatch.regprog);
5585 }
5586
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005587theend:
5588 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005589 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005590 listitem_remove(rettv->vval.v_list,
5591 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005592 vim_free(tofree);
5593 p_cpo = save_cpo;
5594}
5595
5596/*
5597 * "match()" function
5598 */
5599 static void
5600f_match(typval_T *argvars, typval_T *rettv)
5601{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005602 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005603}
5604
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605/*
5606 * "matchend()" function
5607 */
5608 static void
5609f_matchend(typval_T *argvars, typval_T *rettv)
5610{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005611 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005612}
5613
5614/*
5615 * "matchlist()" function
5616 */
5617 static void
5618f_matchlist(typval_T *argvars, typval_T *rettv)
5619{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005620 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005621}
5622
5623/*
5624 * "matchstr()" function
5625 */
5626 static void
5627f_matchstr(typval_T *argvars, typval_T *rettv)
5628{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005629 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630}
5631
5632/*
5633 * "matchstrpos()" function
5634 */
5635 static void
5636f_matchstrpos(typval_T *argvars, typval_T *rettv)
5637{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005638 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639}
5640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005641 static void
5642max_min(typval_T *argvars, typval_T *rettv, int domax)
5643{
5644 varnumber_T n = 0;
5645 varnumber_T i;
5646 int error = FALSE;
5647
5648 if (argvars[0].v_type == VAR_LIST)
5649 {
5650 list_T *l;
5651 listitem_T *li;
5652
5653 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005654 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005655 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005656 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005657 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005658 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5659 n = l->lv_u.nonmat.lv_start;
5660 else
5661 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5662 * l->lv_u.nonmat.lv_stride;
5663 }
5664 else
5665 {
5666 li = l->lv_first;
5667 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005668 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005669 n = tv_get_number_chk(&li->li_tv, &error);
5670 for (;;)
5671 {
5672 li = li->li_next;
5673 if (li == NULL)
5674 break;
5675 i = tv_get_number_chk(&li->li_tv, &error);
5676 if (domax ? i > n : i < n)
5677 n = i;
5678 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005679 }
5680 }
5681 }
5682 }
5683 else if (argvars[0].v_type == VAR_DICT)
5684 {
5685 dict_T *d;
5686 int first = TRUE;
5687 hashitem_T *hi;
5688 int todo;
5689
5690 d = argvars[0].vval.v_dict;
5691 if (d != NULL)
5692 {
5693 todo = (int)d->dv_hashtab.ht_used;
5694 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5695 {
5696 if (!HASHITEM_EMPTY(hi))
5697 {
5698 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005699 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005700 if (first)
5701 {
5702 n = i;
5703 first = FALSE;
5704 }
5705 else if (domax ? i > n : i < n)
5706 n = i;
5707 }
5708 }
5709 }
5710 }
5711 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005712 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005713 rettv->vval.v_number = error ? 0 : n;
5714}
5715
5716/*
5717 * "max()" function
5718 */
5719 static void
5720f_max(typval_T *argvars, typval_T *rettv)
5721{
5722 max_min(argvars, rettv, TRUE);
5723}
5724
5725/*
5726 * "min()" function
5727 */
5728 static void
5729f_min(typval_T *argvars, typval_T *rettv)
5730{
5731 max_min(argvars, rettv, FALSE);
5732}
5733
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734#if defined(FEAT_MZSCHEME) || defined(PROTO)
5735/*
5736 * "mzeval()" function
5737 */
5738 static void
5739f_mzeval(typval_T *argvars, typval_T *rettv)
5740{
5741 char_u *str;
5742 char_u buf[NUMBUFLEN];
5743
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005744 if (check_restricted() || check_secure())
5745 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005746 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005747 do_mzeval(str, rettv);
5748}
5749
5750 void
5751mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5752{
5753 typval_T argvars[3];
5754
5755 argvars[0].v_type = VAR_STRING;
5756 argvars[0].vval.v_string = name;
5757 copy_tv(args, &argvars[1]);
5758 argvars[2].v_type = VAR_UNKNOWN;
5759 f_call(argvars, rettv);
5760 clear_tv(&argvars[1]);
5761}
5762#endif
5763
5764/*
5765 * "nextnonblank()" function
5766 */
5767 static void
5768f_nextnonblank(typval_T *argvars, typval_T *rettv)
5769{
5770 linenr_T lnum;
5771
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005772 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005773 {
5774 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5775 {
5776 lnum = 0;
5777 break;
5778 }
5779 if (*skipwhite(ml_get(lnum)) != NUL)
5780 break;
5781 }
5782 rettv->vval.v_number = lnum;
5783}
5784
5785/*
5786 * "nr2char()" function
5787 */
5788 static void
5789f_nr2char(typval_T *argvars, typval_T *rettv)
5790{
5791 char_u buf[NUMBUFLEN];
5792
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005793 if (has_mbyte)
5794 {
5795 int utf8 = 0;
5796
5797 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005798 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005800 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005802 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005803 }
5804 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005805 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005806 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005807 buf[1] = NUL;
5808 }
5809 rettv->v_type = VAR_STRING;
5810 rettv->vval.v_string = vim_strsave(buf);
5811}
5812
5813/*
5814 * "or(expr, expr)" function
5815 */
5816 static void
5817f_or(typval_T *argvars, typval_T *rettv)
5818{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005819 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5820 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005821}
5822
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005823#ifdef FEAT_PERL
5824/*
5825 * "perleval()" function
5826 */
5827 static void
5828f_perleval(typval_T *argvars, typval_T *rettv)
5829{
5830 char_u *str;
5831 char_u buf[NUMBUFLEN];
5832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005833 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005834 do_perleval(str, rettv);
5835}
5836#endif
5837
5838#ifdef FEAT_FLOAT
5839/*
5840 * "pow()" function
5841 */
5842 static void
5843f_pow(typval_T *argvars, typval_T *rettv)
5844{
5845 float_T fx = 0.0, fy = 0.0;
5846
5847 rettv->v_type = VAR_FLOAT;
5848 if (get_float_arg(argvars, &fx) == OK
5849 && get_float_arg(&argvars[1], &fy) == OK)
5850 rettv->vval.v_float = pow(fx, fy);
5851 else
5852 rettv->vval.v_float = 0.0;
5853}
5854#endif
5855
5856/*
5857 * "prevnonblank()" function
5858 */
5859 static void
5860f_prevnonblank(typval_T *argvars, typval_T *rettv)
5861{
5862 linenr_T lnum;
5863
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005864 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005865 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5866 lnum = 0;
5867 else
5868 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5869 --lnum;
5870 rettv->vval.v_number = lnum;
5871}
5872
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005873// This dummy va_list is here because:
5874// - passing a NULL pointer doesn't work when va_list isn't a pointer
5875// - locally in the function results in a "used before set" warning
5876// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005877static va_list ap;
5878
5879/*
5880 * "printf()" function
5881 */
5882 static void
5883f_printf(typval_T *argvars, typval_T *rettv)
5884{
5885 char_u buf[NUMBUFLEN];
5886 int len;
5887 char_u *s;
5888 int saved_did_emsg = did_emsg;
5889 char *fmt;
5890
5891 rettv->v_type = VAR_STRING;
5892 rettv->vval.v_string = NULL;
5893
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005894 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005895 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005896 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005897 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005898 if (!did_emsg)
5899 {
5900 s = alloc(len + 1);
5901 if (s != NULL)
5902 {
5903 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005904 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5905 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005906 }
5907 }
5908 did_emsg |= saved_did_emsg;
5909}
5910
5911/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005912 * "pum_getpos()" function
5913 */
5914 static void
5915f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5916{
5917 if (rettv_dict_alloc(rettv) != OK)
5918 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005919 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005920}
5921
5922/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005923 * "pumvisible()" function
5924 */
5925 static void
5926f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5927{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005928 if (pum_visible())
5929 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005930}
5931
5932#ifdef FEAT_PYTHON3
5933/*
5934 * "py3eval()" function
5935 */
5936 static void
5937f_py3eval(typval_T *argvars, typval_T *rettv)
5938{
5939 char_u *str;
5940 char_u buf[NUMBUFLEN];
5941
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005942 if (check_restricted() || check_secure())
5943 return;
5944
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005945 if (p_pyx == 0)
5946 p_pyx = 3;
5947
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005948 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005949 do_py3eval(str, rettv);
5950}
5951#endif
5952
5953#ifdef FEAT_PYTHON
5954/*
5955 * "pyeval()" function
5956 */
5957 static void
5958f_pyeval(typval_T *argvars, typval_T *rettv)
5959{
5960 char_u *str;
5961 char_u buf[NUMBUFLEN];
5962
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005963 if (check_restricted() || check_secure())
5964 return;
5965
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005966 if (p_pyx == 0)
5967 p_pyx = 2;
5968
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005969 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005970 do_pyeval(str, rettv);
5971}
5972#endif
5973
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005974#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5975/*
5976 * "pyxeval()" function
5977 */
5978 static void
5979f_pyxeval(typval_T *argvars, typval_T *rettv)
5980{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005981 if (check_restricted() || check_secure())
5982 return;
5983
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005984# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5985 init_pyxversion();
5986 if (p_pyx == 2)
5987 f_pyeval(argvars, rettv);
5988 else
5989 f_py3eval(argvars, rettv);
5990# elif defined(FEAT_PYTHON)
5991 f_pyeval(argvars, rettv);
5992# elif defined(FEAT_PYTHON3)
5993 f_py3eval(argvars, rettv);
5994# endif
5995}
5996#endif
5997
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005998static UINT32_T srand_seed_for_testing = 0;
5999static int srand_seed_for_testing_is_used = FALSE;
6000
6001 static void
6002f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
6003{
6004 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006005 srand_seed_for_testing_is_used = FALSE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006006 else
6007 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006008 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
6009 srand_seed_for_testing_is_used = TRUE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006010 }
6011}
6012
6013 static void
6014init_srand(UINT32_T *x)
6015{
6016#ifndef MSWIN
6017 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6018#endif
6019
6020 if (srand_seed_for_testing_is_used)
6021 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006022 *x = srand_seed_for_testing;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006023 return;
6024 }
6025#ifndef MSWIN
6026 if (dev_urandom_state != FAIL)
6027 {
6028 int fd = open("/dev/urandom", O_RDONLY);
6029 struct {
6030 union {
6031 UINT32_T number;
6032 char bytes[sizeof(UINT32_T)];
6033 } contents;
6034 } buf;
6035
6036 // Attempt reading /dev/urandom.
6037 if (fd == -1)
6038 dev_urandom_state = FAIL;
6039 else
6040 {
6041 buf.contents.number = 0;
6042 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6043 != sizeof(UINT32_T))
6044 dev_urandom_state = FAIL;
6045 else
6046 {
6047 dev_urandom_state = OK;
6048 *x = buf.contents.number;
6049 }
6050 close(fd);
6051 }
6052 }
6053 if (dev_urandom_state != OK)
6054 // Reading /dev/urandom doesn't work, fall back to time().
6055#endif
6056 *x = vim_time();
6057}
6058
6059#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6060#define SPLITMIX32(x, z) ( \
6061 z = (x += 0x9e3779b9), \
6062 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6063 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6064 z ^ (z >> 16) \
6065 )
6066#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6067 result = ROTL(y * 5, 7) * 9; \
6068 t = y << 9; \
6069 z ^= x; \
6070 w ^= y; \
6071 y ^= z, x ^= w; \
6072 z ^= t; \
6073 w = ROTL(w, 11);
6074
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006076 * "rand()" function
6077 */
6078 static void
6079f_rand(typval_T *argvars, typval_T *rettv)
6080{
6081 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006082 static UINT32_T gx, gy, gz, gw;
6083 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006084 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006085 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006086
6087 if (argvars[0].v_type == VAR_UNKNOWN)
6088 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006089 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006090 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006091 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006092 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006093 init_srand(&x);
6094
6095 gx = SPLITMIX32(x, z);
6096 gy = SPLITMIX32(x, z);
6097 gz = SPLITMIX32(x, z);
6098 gw = SPLITMIX32(x, z);
6099 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006100 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006101
6102 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006103 }
6104 else if (argvars[0].v_type == VAR_LIST)
6105 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006106 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006107 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006108 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006109
6110 lx = list_find(l, 0L);
6111 ly = list_find(l, 1L);
6112 lz = list_find(l, 2L);
6113 lw = list_find(l, 3L);
6114 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6115 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6116 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6117 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6118 x = (UINT32_T)lx->li_tv.vval.v_number;
6119 y = (UINT32_T)ly->li_tv.vval.v_number;
6120 z = (UINT32_T)lz->li_tv.vval.v_number;
6121 w = (UINT32_T)lw->li_tv.vval.v_number;
6122
6123 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6124
6125 lx->li_tv.vval.v_number = (varnumber_T)x;
6126 ly->li_tv.vval.v_number = (varnumber_T)y;
6127 lz->li_tv.vval.v_number = (varnumber_T)z;
6128 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006129 }
6130 else
6131 goto theend;
6132
6133 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006134 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006135 return;
6136
6137theend:
6138 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006139 rettv->v_type = VAR_NUMBER;
6140 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006141}
6142
6143/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006144 * "srand()" function
6145 */
6146 static void
6147f_srand(typval_T *argvars, typval_T *rettv)
6148{
6149 UINT32_T x = 0, z;
6150
6151 if (rettv_list_alloc(rettv) == FAIL)
6152 return;
6153 if (argvars[0].v_type == VAR_UNKNOWN)
6154 {
6155 init_srand(&x);
6156 }
6157 else
6158 {
6159 int error = FALSE;
6160
6161 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6162 if (error)
6163 return;
6164 }
6165
6166 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6167 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6168 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6169 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6170}
6171
6172#undef ROTL
6173#undef SPLITMIX32
6174#undef SHUFFLE_XOSHIRO128STARSTAR
6175
6176/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006177 * "range()" function
6178 */
6179 static void
6180f_range(typval_T *argvars, typval_T *rettv)
6181{
6182 varnumber_T start;
6183 varnumber_T end;
6184 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 int error = FALSE;
6186
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006187 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 if (argvars[1].v_type == VAR_UNKNOWN)
6189 {
6190 end = start - 1;
6191 start = 0;
6192 }
6193 else
6194 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006195 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006197 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198 }
6199
6200 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006201 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006202 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006203 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006204 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006205 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006206 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006207 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006208 list_T *list = rettv->vval.v_list;
6209
6210 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006211 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006212 // be called.
6213 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006214 list->lv_u.nonmat.lv_start = start;
6215 list->lv_u.nonmat.lv_end = end;
6216 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006217 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006218 }
6219}
6220
6221/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006222 * Materialize "list".
6223 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006224 */
6225 void
6226range_list_materialize(list_T *list)
6227{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006228 varnumber_T start = list->lv_u.nonmat.lv_start;
6229 varnumber_T end = list->lv_u.nonmat.lv_end;
6230 int stride = list->lv_u.nonmat.lv_stride;
6231 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006232
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006233 list->lv_first = NULL;
6234 list->lv_u.mat.lv_last = NULL;
6235 list->lv_len = 0;
6236 list->lv_u.mat.lv_idx_item = NULL;
6237 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6238 if (list_append_number(list, (varnumber_T)i) == FAIL)
6239 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006240}
6241
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006242/*
6243 * "getreginfo()" function
6244 */
6245 static void
6246f_getreginfo(typval_T *argvars, typval_T *rettv)
6247{
6248 char_u *strregname;
6249 int regname;
6250 char_u buf[NUMBUFLEN + 2];
6251 long reglen = 0;
6252 dict_T *dict;
6253 list_T *list;
6254
6255 if (argvars[0].v_type != VAR_UNKNOWN)
6256 {
6257 strregname = tv_get_string_chk(&argvars[0]);
6258 if (strregname == NULL)
6259 return;
6260 }
6261 else
6262 strregname = get_vim_var_str(VV_REG);
6263
6264 regname = (strregname == NULL ? '"' : *strregname);
6265 if (regname == 0 || regname == '@')
6266 regname = '"';
6267
6268 if (rettv_dict_alloc(rettv) == FAIL)
6269 return;
6270 dict = rettv->vval.v_dict;
6271
6272 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
6273 if (list == NULL)
6274 return;
6275 dict_add_list(dict, "regcontents", list);
6276
6277 buf[0] = NUL;
6278 buf[1] = NUL;
6279 switch (get_reg_type(regname, &reglen))
6280 {
6281 case MLINE: buf[0] = 'V'; break;
6282 case MCHAR: buf[0] = 'v'; break;
6283 case MBLOCK:
6284 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
6285 reglen + 1);
6286 break;
6287 }
6288 dict_add_string(dict, (char *)"regtype", buf);
6289
6290 buf[0] = get_register_name(get_unname_register());
6291 buf[1] = NUL;
6292 if (regname == '"')
6293 dict_add_string(dict, (char *)"points_to", buf);
6294 else
6295 {
6296 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
6297
6298 if (item != NULL)
6299 {
6300 item->di_tv.v_type = VAR_SPECIAL;
6301 item->di_tv.vval.v_number = regname == buf[0]
6302 ? VVAL_TRUE : VVAL_FALSE;
6303 dict_add(dict, item);
6304 }
6305 }
6306}
6307
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006308 static void
6309return_register(int regname, typval_T *rettv)
6310{
6311 char_u buf[2] = {0, 0};
6312
6313 buf[0] = (char_u)regname;
6314 rettv->v_type = VAR_STRING;
6315 rettv->vval.v_string = vim_strsave(buf);
6316}
6317
6318/*
6319 * "reg_executing()" function
6320 */
6321 static void
6322f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6323{
6324 return_register(reg_executing, rettv);
6325}
6326
6327/*
6328 * "reg_recording()" function
6329 */
6330 static void
6331f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6332{
6333 return_register(reg_recording, rettv);
6334}
6335
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006336/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337 * "rename({from}, {to})" function
6338 */
6339 static void
6340f_rename(typval_T *argvars, typval_T *rettv)
6341{
6342 char_u buf[NUMBUFLEN];
6343
6344 if (check_restricted() || check_secure())
6345 rettv->vval.v_number = -1;
6346 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006347 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6348 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006349}
6350
6351/*
6352 * "repeat()" function
6353 */
6354 static void
6355f_repeat(typval_T *argvars, typval_T *rettv)
6356{
6357 char_u *p;
6358 int n;
6359 int slen;
6360 int len;
6361 char_u *r;
6362 int i;
6363
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006364 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365 if (argvars[0].v_type == VAR_LIST)
6366 {
6367 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6368 while (n-- > 0)
6369 if (list_extend(rettv->vval.v_list,
6370 argvars[0].vval.v_list, NULL) == FAIL)
6371 break;
6372 }
6373 else
6374 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006375 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376 rettv->v_type = VAR_STRING;
6377 rettv->vval.v_string = NULL;
6378
6379 slen = (int)STRLEN(p);
6380 len = slen * n;
6381 if (len <= 0)
6382 return;
6383
6384 r = alloc(len + 1);
6385 if (r != NULL)
6386 {
6387 for (i = 0; i < n; i++)
6388 mch_memmove(r + i * slen, p, (size_t)slen);
6389 r[len] = NUL;
6390 }
6391
6392 rettv->vval.v_string = r;
6393 }
6394}
6395
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006396#define SP_NOMOVE 0x01 // don't move cursor
6397#define SP_REPEAT 0x02 // repeat to find outer pair
6398#define SP_RETCOUNT 0x04 // return matchcount
6399#define SP_SETPCMARK 0x08 // set previous context mark
6400#define SP_START 0x10 // accept match at start position
6401#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6402#define SP_END 0x40 // leave cursor at end of match
6403#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006404
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006405/*
6406 * Get flags for a search function.
6407 * Possibly sets "p_ws".
6408 * Returns BACKWARD, FORWARD or zero (for an error).
6409 */
6410 static int
6411get_search_arg(typval_T *varp, int *flagsp)
6412{
6413 int dir = FORWARD;
6414 char_u *flags;
6415 char_u nbuf[NUMBUFLEN];
6416 int mask;
6417
6418 if (varp->v_type != VAR_UNKNOWN)
6419 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006420 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006422 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006423 while (*flags != NUL)
6424 {
6425 switch (*flags)
6426 {
6427 case 'b': dir = BACKWARD; break;
6428 case 'w': p_ws = TRUE; break;
6429 case 'W': p_ws = FALSE; break;
6430 default: mask = 0;
6431 if (flagsp != NULL)
6432 switch (*flags)
6433 {
6434 case 'c': mask = SP_START; break;
6435 case 'e': mask = SP_END; break;
6436 case 'm': mask = SP_RETCOUNT; break;
6437 case 'n': mask = SP_NOMOVE; break;
6438 case 'p': mask = SP_SUBPAT; break;
6439 case 'r': mask = SP_REPEAT; break;
6440 case 's': mask = SP_SETPCMARK; break;
6441 case 'z': mask = SP_COLUMN; break;
6442 }
6443 if (mask == 0)
6444 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006445 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006446 dir = 0;
6447 }
6448 else
6449 *flagsp |= mask;
6450 }
6451 if (dir == 0)
6452 break;
6453 ++flags;
6454 }
6455 }
6456 return dir;
6457}
6458
6459/*
6460 * Shared by search() and searchpos() functions.
6461 */
6462 static int
6463search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6464{
6465 int flags;
6466 char_u *pat;
6467 pos_T pos;
6468 pos_T save_cursor;
6469 int save_p_ws = p_ws;
6470 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006471 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006474 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 long time_limit = 0;
6476#endif
6477 int options = SEARCH_KEEP;
6478 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006479 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006480 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006481 pos_T firstpos;
6482
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006483 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006484 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485 if (dir == 0)
6486 goto theend;
6487 flags = *flagsp;
6488 if (flags & SP_START)
6489 options |= SEARCH_START;
6490 if (flags & SP_END)
6491 options |= SEARCH_END;
6492 if (flags & SP_COLUMN)
6493 options |= SEARCH_COL;
6494
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006495 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6497 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006498 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499 if (lnum_stop < 0)
6500 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 if (argvars[3].v_type != VAR_UNKNOWN)
6502 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006503#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006504 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505 if (time_limit < 0)
6506 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02006508 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006509 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006510 }
6511
6512#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006513 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514 profile_setlimit(time_limit, &tm);
6515#endif
6516
6517 /*
6518 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6519 * Check to make sure only those flags are set.
6520 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6521 * flags cannot be set. Check for that condition also.
6522 */
6523 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6524 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6525 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006526 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527 goto theend;
6528 }
6529
6530 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006531 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02006532 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006533 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6534#ifdef FEAT_RELTIME
6535 sia.sa_tm = &tm;
6536#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006537
6538 // Repeat until {skip} returns FALSE.
6539 for (;;)
6540 {
6541 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006542 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006543 // finding the first match again means there is no match where {skip}
6544 // evaluates to zero.
6545 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
6546 subpatnum = FAIL;
6547
Bram Moolenaara9c01042020-06-07 14:50:50 +02006548 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006549 // didn't find it or no skip argument
6550 break;
6551 firstpos = pos;
6552
Bram Moolenaara9c01042020-06-07 14:50:50 +02006553 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006554 {
6555 int do_skip;
6556 int err;
6557 pos_T save_pos = curwin->w_cursor;
6558
6559 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006560 err = FALSE;
6561 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006562 curwin->w_cursor = save_pos;
6563 if (err)
6564 {
6565 // Evaluating {skip} caused an error, break here.
6566 subpatnum = FAIL;
6567 break;
6568 }
6569 if (!do_skip)
6570 break;
6571 }
6572 }
6573
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574 if (subpatnum != FAIL)
6575 {
6576 if (flags & SP_SUBPAT)
6577 retval = subpatnum;
6578 else
6579 retval = pos.lnum;
6580 if (flags & SP_SETPCMARK)
6581 setpcmark();
6582 curwin->w_cursor = pos;
6583 if (match_pos != NULL)
6584 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006585 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 match_pos->lnum = pos.lnum;
6587 match_pos->col = pos.col + 1;
6588 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006589 // "/$" will put the cursor after the end of the line, may need to
6590 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006591 check_cursor();
6592 }
6593
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006594 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006595 if (flags & SP_NOMOVE)
6596 curwin->w_cursor = save_cursor;
6597 else
6598 curwin->w_set_curswant = TRUE;
6599theend:
6600 p_ws = save_p_ws;
6601
6602 return retval;
6603}
6604
6605#ifdef FEAT_FLOAT
6606
6607/*
6608 * round() is not in C90, use ceil() or floor() instead.
6609 */
6610 float_T
6611vim_round(float_T f)
6612{
6613 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6614}
6615
6616/*
6617 * "round({float})" function
6618 */
6619 static void
6620f_round(typval_T *argvars, typval_T *rettv)
6621{
6622 float_T f = 0.0;
6623
6624 rettv->v_type = VAR_FLOAT;
6625 if (get_float_arg(argvars, &f) == OK)
6626 rettv->vval.v_float = vim_round(f);
6627 else
6628 rettv->vval.v_float = 0.0;
6629}
6630#endif
6631
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006632#ifdef FEAT_RUBY
6633/*
6634 * "rubyeval()" function
6635 */
6636 static void
6637f_rubyeval(typval_T *argvars, typval_T *rettv)
6638{
6639 char_u *str;
6640 char_u buf[NUMBUFLEN];
6641
6642 str = tv_get_string_buf(&argvars[0], buf);
6643 do_rubyeval(str, rettv);
6644}
6645#endif
6646
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006647/*
6648 * "screenattr()" function
6649 */
6650 static void
6651f_screenattr(typval_T *argvars, typval_T *rettv)
6652{
6653 int row;
6654 int col;
6655 int c;
6656
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006657 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6658 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006659 if (row < 0 || row >= screen_Rows
6660 || col < 0 || col >= screen_Columns)
6661 c = -1;
6662 else
6663 c = ScreenAttrs[LineOffset[row] + col];
6664 rettv->vval.v_number = c;
6665}
6666
6667/*
6668 * "screenchar()" function
6669 */
6670 static void
6671f_screenchar(typval_T *argvars, typval_T *rettv)
6672{
6673 int row;
6674 int col;
6675 int off;
6676 int c;
6677
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006678 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6679 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006680 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006681 c = -1;
6682 else
6683 {
6684 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685 if (enc_utf8 && ScreenLinesUC[off] != 0)
6686 c = ScreenLinesUC[off];
6687 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688 c = ScreenLines[off];
6689 }
6690 rettv->vval.v_number = c;
6691}
6692
6693/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006694 * "screenchars()" function
6695 */
6696 static void
6697f_screenchars(typval_T *argvars, typval_T *rettv)
6698{
6699 int row;
6700 int col;
6701 int off;
6702 int c;
6703 int i;
6704
6705 if (rettv_list_alloc(rettv) == FAIL)
6706 return;
6707 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6708 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6709 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6710 return;
6711
6712 off = LineOffset[row] + col;
6713 if (enc_utf8 && ScreenLinesUC[off] != 0)
6714 c = ScreenLinesUC[off];
6715 else
6716 c = ScreenLines[off];
6717 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6718
6719 if (enc_utf8)
6720
6721 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6722 list_append_number(rettv->vval.v_list,
6723 (varnumber_T)ScreenLinesC[i][off]);
6724}
6725
6726/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006727 * "screencol()" function
6728 *
6729 * First column is 1 to be consistent with virtcol().
6730 */
6731 static void
6732f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6733{
6734 rettv->vval.v_number = screen_screencol() + 1;
6735}
6736
6737/*
6738 * "screenrow()" function
6739 */
6740 static void
6741f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6742{
6743 rettv->vval.v_number = screen_screenrow() + 1;
6744}
6745
6746/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006747 * "screenstring()" function
6748 */
6749 static void
6750f_screenstring(typval_T *argvars, typval_T *rettv)
6751{
6752 int row;
6753 int col;
6754 int off;
6755 int c;
6756 int i;
6757 char_u buf[MB_MAXBYTES + 1];
6758 int buflen = 0;
6759
6760 rettv->vval.v_string = NULL;
6761 rettv->v_type = VAR_STRING;
6762
6763 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6764 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6765 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6766 return;
6767
6768 off = LineOffset[row] + col;
6769 if (enc_utf8 && ScreenLinesUC[off] != 0)
6770 c = ScreenLinesUC[off];
6771 else
6772 c = ScreenLines[off];
6773 buflen += mb_char2bytes(c, buf);
6774
6775 if (enc_utf8)
6776 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6777 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6778
6779 buf[buflen] = NUL;
6780 rettv->vval.v_string = vim_strsave(buf);
6781}
6782
6783/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006784 * "search()" function
6785 */
6786 static void
6787f_search(typval_T *argvars, typval_T *rettv)
6788{
6789 int flags = 0;
6790
6791 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6792}
6793
6794/*
6795 * "searchdecl()" function
6796 */
6797 static void
6798f_searchdecl(typval_T *argvars, typval_T *rettv)
6799{
6800 int locally = 1;
6801 int thisblock = 0;
6802 int error = FALSE;
6803 char_u *name;
6804
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006805 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006806
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006807 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006808 if (argvars[1].v_type != VAR_UNKNOWN)
6809 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006810 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006811 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006812 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006813 }
6814 if (!error && name != NULL)
6815 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6816 locally, thisblock, SEARCH_KEEP) == FAIL;
6817}
6818
6819/*
6820 * Used by searchpair() and searchpairpos()
6821 */
6822 static int
6823searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6824{
6825 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006826 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006827 int save_p_ws = p_ws;
6828 int dir;
6829 int flags = 0;
6830 char_u nbuf1[NUMBUFLEN];
6831 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006832 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006833 long lnum_stop = 0;
6834 long time_limit = 0;
6835
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006836 // Get the three pattern arguments: start, middle, end. Will result in an
6837 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006838 spat = tv_get_string_chk(&argvars[0]);
6839 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6840 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006841 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006842 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006843
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006844 // Handle the optional fourth argument: flags
6845 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006846 if (dir == 0)
6847 goto theend;
6848
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006849 // Don't accept SP_END or SP_SUBPAT.
6850 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 if ((flags & (SP_END | SP_SUBPAT)) != 0
6852 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6853 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006854 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006855 goto theend;
6856 }
6857
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006858 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006859 if (flags & SP_REPEAT)
6860 p_ws = FALSE;
6861
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006862 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006863 if (argvars[3].v_type == VAR_UNKNOWN
6864 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006865 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 else
6867 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02006868 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01006869 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02006870
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006871 if (argvars[5].v_type != VAR_UNKNOWN)
6872 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006873 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006875 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006876 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006878 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879#ifdef FEAT_RELTIME
6880 if (argvars[6].v_type != VAR_UNKNOWN)
6881 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006882 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006884 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006885 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006886 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006887 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006888 }
6889#endif
6890 }
6891 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892
6893 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6894 match_pos, lnum_stop, time_limit);
6895
6896theend:
6897 p_ws = save_p_ws;
6898
6899 return retval;
6900}
6901
6902/*
6903 * "searchpair()" function
6904 */
6905 static void
6906f_searchpair(typval_T *argvars, typval_T *rettv)
6907{
6908 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6909}
6910
6911/*
6912 * "searchpairpos()" function
6913 */
6914 static void
6915f_searchpairpos(typval_T *argvars, typval_T *rettv)
6916{
6917 pos_T match_pos;
6918 int lnum = 0;
6919 int col = 0;
6920
6921 if (rettv_list_alloc(rettv) == FAIL)
6922 return;
6923
6924 if (searchpair_cmn(argvars, &match_pos) > 0)
6925 {
6926 lnum = match_pos.lnum;
6927 col = match_pos.col;
6928 }
6929
6930 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6931 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6932}
6933
6934/*
6935 * Search for a start/middle/end thing.
6936 * Used by searchpair(), see its documentation for the details.
6937 * Returns 0 or -1 for no match,
6938 */
6939 long
6940do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006941 char_u *spat, // start pattern
6942 char_u *mpat, // middle pattern
6943 char_u *epat, // end pattern
6944 int dir, // BACKWARD or FORWARD
6945 typval_T *skip, // skip expression
6946 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006947 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006948 linenr_T lnum_stop, // stop at this line if not zero
6949 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950{
6951 char_u *save_cpo;
6952 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6953 long retval = 0;
6954 pos_T pos;
6955 pos_T firstpos;
6956 pos_T foundpos;
6957 pos_T save_cursor;
6958 pos_T save_pos;
6959 int n;
6960 int r;
6961 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006962 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006963 int err;
6964 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006965#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006967#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006968
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006969 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 save_cpo = p_cpo;
6971 p_cpo = empty_option;
6972
6973#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006974 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 profile_setlimit(time_limit, &tm);
6976#endif
6977
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006978 // Make two search patterns: start/end (pat2, for in nested pairs) and
6979 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006980 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6981 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982 if (pat2 == NULL || pat3 == NULL)
6983 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006984 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006985 if (*mpat == NUL)
6986 STRCPY(pat3, pat2);
6987 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006988 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006989 spat, epat, mpat);
6990 if (flags & SP_START)
6991 options |= SEARCH_START;
6992
Bram Moolenaar48570482017-10-30 21:48:41 +01006993 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02006994 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01006995
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006996 save_cursor = curwin->w_cursor;
6997 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006998 CLEAR_POS(&firstpos);
6999 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007000 pat = pat3;
7001 for (;;)
7002 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007003 searchit_arg_T sia;
7004
Bram Moolenaara80faa82020-04-12 19:37:17 +02007005 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007006 sia.sa_stop_lnum = lnum_stop;
7007#ifdef FEAT_RELTIME
7008 sia.sa_tm = &tm;
7009#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007010 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007011 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007012 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007013 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007014 break;
7015
7016 if (firstpos.lnum == 0)
7017 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007018 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007019 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007020 // Found the same position again. Can happen with a pattern that
7021 // has "\zs" at the end and searching backwards. Advance one
7022 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007023 if (dir == BACKWARD)
7024 decl(&pos);
7025 else
7026 incl(&pos);
7027 }
7028 foundpos = pos;
7029
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007030 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007031 options &= ~SEARCH_START;
7032
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007033 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007034 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007035 {
7036 save_pos = curwin->w_cursor;
7037 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007038 err = FALSE;
7039 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007040 curwin->w_cursor = save_pos;
7041 if (err)
7042 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007043 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007044 curwin->w_cursor = save_cursor;
7045 retval = -1;
7046 break;
7047 }
7048 if (r)
7049 continue;
7050 }
7051
7052 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7053 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007054 // Found end when searching backwards or start when searching
7055 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007056 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007057 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007058 }
7059 else
7060 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007061 // Found end when searching forward or start when searching
7062 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007064 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007065 }
7066
7067 if (nest == 0)
7068 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007069 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007070 if (flags & SP_RETCOUNT)
7071 ++retval;
7072 else
7073 retval = pos.lnum;
7074 if (flags & SP_SETPCMARK)
7075 setpcmark();
7076 curwin->w_cursor = pos;
7077 if (!(flags & SP_REPEAT))
7078 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007079 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007080 }
7081 }
7082
7083 if (match_pos != NULL)
7084 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007085 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007086 match_pos->lnum = curwin->w_cursor.lnum;
7087 match_pos->col = curwin->w_cursor.col + 1;
7088 }
7089
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007090 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007091 if ((flags & SP_NOMOVE) || retval == 0)
7092 curwin->w_cursor = save_cursor;
7093
7094theend:
7095 vim_free(pat2);
7096 vim_free(pat3);
7097 if (p_cpo == empty_option)
7098 p_cpo = save_cpo;
7099 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007100 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007101 free_string_option(save_cpo);
7102
7103 return retval;
7104}
7105
7106/*
7107 * "searchpos()" function
7108 */
7109 static void
7110f_searchpos(typval_T *argvars, typval_T *rettv)
7111{
7112 pos_T match_pos;
7113 int lnum = 0;
7114 int col = 0;
7115 int n;
7116 int flags = 0;
7117
7118 if (rettv_list_alloc(rettv) == FAIL)
7119 return;
7120
7121 n = search_cmn(argvars, &match_pos, &flags);
7122 if (n > 0)
7123 {
7124 lnum = match_pos.lnum;
7125 col = match_pos.col;
7126 }
7127
7128 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7129 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7130 if (flags & SP_SUBPAT)
7131 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7132}
7133
7134 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7136{
7137 dict_T *d;
7138 dictitem_T *di;
7139 char_u *csearch;
7140
7141 if (argvars[0].v_type != VAR_DICT)
7142 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007143 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007144 return;
7145 }
7146
7147 if ((d = argvars[0].vval.v_dict) != NULL)
7148 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007149 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150 if (csearch != NULL)
7151 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007152 if (enc_utf8)
7153 {
7154 int pcc[MAX_MCO];
7155 int c = utfc_ptr2char(csearch, pcc);
7156
7157 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7158 }
7159 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007161 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007162 }
7163
7164 di = dict_find(d, (char_u *)"forward", -1);
7165 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007166 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007167 ? FORWARD : BACKWARD);
7168
7169 di = dict_find(d, (char_u *)"until", -1);
7170 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007171 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007172 }
7173}
7174
7175/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007176 * "setenv()" function
7177 */
7178 static void
7179f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7180{
7181 char_u namebuf[NUMBUFLEN];
7182 char_u valbuf[NUMBUFLEN];
7183 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7184
7185 if (argvars[1].v_type == VAR_SPECIAL
7186 && argvars[1].vval.v_number == VVAL_NULL)
7187 vim_unsetenv(name);
7188 else
7189 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7190}
7191
7192/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007193 * "setfperm({fname}, {mode})" function
7194 */
7195 static void
7196f_setfperm(typval_T *argvars, typval_T *rettv)
7197{
7198 char_u *fname;
7199 char_u modebuf[NUMBUFLEN];
7200 char_u *mode_str;
7201 int i;
7202 int mask;
7203 int mode = 0;
7204
7205 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007206 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007207 if (fname == NULL)
7208 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007209 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007210 if (mode_str == NULL)
7211 return;
7212 if (STRLEN(mode_str) != 9)
7213 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007214 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007215 return;
7216 }
7217
7218 mask = 1;
7219 for (i = 8; i >= 0; --i)
7220 {
7221 if (mode_str[i] != '-')
7222 mode |= mask;
7223 mask = mask << 1;
7224 }
7225 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7226}
7227
7228/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229 * "setpos()" function
7230 */
7231 static void
7232f_setpos(typval_T *argvars, typval_T *rettv)
7233{
7234 pos_T pos;
7235 int fnum;
7236 char_u *name;
7237 colnr_T curswant = -1;
7238
7239 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007240 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007241 if (name != NULL)
7242 {
7243 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7244 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007245 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007246 pos.col = 0;
7247 if (name[0] == '.' && name[1] == NUL)
7248 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007249 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007250 curwin->w_cursor = pos;
7251 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007252 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007253 curwin->w_curswant = curswant - 1;
7254 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007256 check_cursor();
7257 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258 }
7259 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7260 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007261 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007262 if (setmark_pos(name[1], &pos, fnum) == OK)
7263 rettv->vval.v_number = 0;
7264 }
7265 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007266 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 }
7268 }
7269}
7270
7271/*
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007272 * Translate a register type string to the yank type and block length
7273 */
7274 static int
7275get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
7276{
7277 char_u *stropt = *pp;
7278 switch (*stropt)
7279 {
7280 case 'v': case 'c': // character-wise selection
7281 *yank_type = MCHAR;
7282 break;
7283 case 'V': case 'l': // line-wise selection
7284 *yank_type = MLINE;
7285 break;
7286 case 'b': case Ctrl_V: // block-wise selection
7287 *yank_type = MBLOCK;
7288 if (VIM_ISDIGIT(stropt[1]))
7289 {
7290 ++stropt;
7291 *block_len = getdigits(&stropt) - 1;
7292 --stropt;
7293 }
7294 break;
7295 default:
7296 return FAIL;
7297 }
7298 *pp = stropt;
7299 return OK;
7300}
7301
7302/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007303 * "setreg()" function
7304 */
7305 static void
7306f_setreg(typval_T *argvars, typval_T *rettv)
7307{
7308 int regname;
7309 char_u *strregname;
7310 char_u *stropt;
7311 char_u *strval;
7312 int append;
7313 char_u yank_type;
7314 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007315 typval_T *regcontents;
7316 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007317
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007318 pointreg = 0;
7319 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007320 block_len = -1;
7321 yank_type = MAUTO;
7322 append = FALSE;
7323
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007324 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007325 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007326
7327 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007328 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007329 regname = *strregname;
7330 if (regname == 0 || regname == '@')
7331 regname = '"';
7332
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007333 if (argvars[1].v_type == VAR_DICT)
7334 {
7335 dict_T *d = argvars[1].vval.v_dict;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007336 dictitem_T *di;
7337
7338 if (d == NULL || d->dv_hashtab.ht_used == 0)
7339 {
7340 // Empty dict, clear the register (like setreg(0, []))
7341 char_u *lstval[2] = {NULL, NULL};
7342 write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
7343 return;
7344 }
7345
7346 di = dict_find(d, (char_u *)"regcontents", -1);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007347 if (di != NULL)
7348 regcontents = &di->di_tv;
7349
7350 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
7351 if (stropt != NULL)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007352 {
7353 int ret = get_yank_type(&stropt, &yank_type, &block_len);
7354
7355 if (ret == FAIL || *++stropt != NUL)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007356 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007357 semsg(_(e_invargval), "value");
7358 return;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007359 }
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007360 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007361
7362 if (regname == '"')
7363 {
7364 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
7365 if (stropt != NULL)
7366 {
7367 pointreg = *stropt;
7368 regname = pointreg;
7369 }
7370 }
7371 else if (dict_get_number(d, (char_u *)"isunnamed"))
7372 pointreg = regname;
7373 }
7374 else
7375 regcontents = &argvars[1];
7376
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 if (argvars[2].v_type != VAR_UNKNOWN)
7378 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007379 if (yank_type != MAUTO)
7380 {
7381 semsg(_(e_toomanyarg), "setreg");
7382 return;
7383 }
7384
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007385 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007387 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388 for (; *stropt != NUL; ++stropt)
7389 switch (*stropt)
7390 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007391 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 append = TRUE;
7393 break;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007394 default:
7395 get_yank_type(&stropt, &yank_type, &block_len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396 }
7397 }
7398
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007399 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007400 {
7401 char_u **lstval;
7402 char_u **allocval;
7403 char_u buf[NUMBUFLEN];
7404 char_u **curval;
7405 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007406 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 listitem_T *li;
7408 int len;
7409
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007410 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007411 len = ll == NULL ? 0 : ll->lv_len;
7412
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007413 // First half: use for pointers to result lines; second half: use for
7414 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007415 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007416 if (lstval == NULL)
7417 return;
7418 curval = lstval;
7419 allocval = lstval + len + 2;
7420 curallocval = allocval;
7421
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007422 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007424 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007425 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007427 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 if (strval == NULL)
7429 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007430 if (strval == buf)
7431 {
7432 // Need to make a copy, next tv_get_string_buf_chk() will
7433 // overwrite the string.
7434 strval = vim_strsave(buf);
7435 if (strval == NULL)
7436 goto free_lstval;
7437 *curallocval++ = strval;
7438 }
7439 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 }
7442 *curval++ = NULL;
7443
7444 write_reg_contents_lst(regname, lstval, -1,
7445 append, yank_type, block_len);
7446free_lstval:
7447 while (curallocval > allocval)
7448 vim_free(*--curallocval);
7449 vim_free(lstval);
7450 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007451 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007452 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007453 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007454 if (strval == NULL)
7455 return;
7456 write_reg_contents_ex(regname, strval, -1,
7457 append, yank_type, block_len);
7458 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007459 if (pointreg != 0)
7460 get_yank_register(pointreg, TRUE);
7461
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007462 rettv->vval.v_number = 0;
7463}
7464
7465/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007466 * "settagstack()" function
7467 */
7468 static void
7469f_settagstack(typval_T *argvars, typval_T *rettv)
7470{
7471 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7472 win_T *wp;
7473 dict_T *d;
7474 int action = 'r';
7475
7476 rettv->vval.v_number = -1;
7477
7478 // first argument: window number or id
7479 wp = find_win_by_nr_or_id(&argvars[0]);
7480 if (wp == NULL)
7481 return;
7482
7483 // second argument: dict with items to set in the tag stack
7484 if (argvars[1].v_type != VAR_DICT)
7485 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007486 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007487 return;
7488 }
7489 d = argvars[1].vval.v_dict;
7490 if (d == NULL)
7491 return;
7492
7493 // third argument: action - 'a' for append and 'r' for replace.
7494 // default is to replace the stack.
7495 if (argvars[2].v_type == VAR_UNKNOWN)
7496 action = 'r';
7497 else if (argvars[2].v_type == VAR_STRING)
7498 {
7499 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007500 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007501 if (actstr == NULL)
7502 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007503 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7504 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007505 action = *actstr;
7506 else
7507 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007508 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007509 return;
7510 }
7511 }
7512 else
7513 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007514 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007515 return;
7516 }
7517
7518 if (set_tagstack(wp, d, action) == OK)
7519 rettv->vval.v_number = 0;
7520}
7521
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522#ifdef FEAT_CRYPT
7523/*
7524 * "sha256({string})" function
7525 */
7526 static void
7527f_sha256(typval_T *argvars, typval_T *rettv)
7528{
7529 char_u *p;
7530
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007531 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 rettv->vval.v_string = vim_strsave(
7533 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7534 rettv->v_type = VAR_STRING;
7535}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007536#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537
7538/*
7539 * "shellescape({string})" function
7540 */
7541 static void
7542f_shellescape(typval_T *argvars, typval_T *rettv)
7543{
Bram Moolenaar20615522017-06-05 18:46:26 +02007544 int do_special = non_zero_arg(&argvars[1]);
7545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007547 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007548 rettv->v_type = VAR_STRING;
7549}
7550
7551/*
7552 * shiftwidth() function
7553 */
7554 static void
7555f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7556{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007557 rettv->vval.v_number = 0;
7558
7559 if (argvars[0].v_type != VAR_UNKNOWN)
7560 {
7561 long col;
7562
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007563 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007564 if (col < 0)
7565 return; // type error; errmsg already given
7566#ifdef FEAT_VARTABS
7567 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7568 return;
7569#endif
7570 }
7571
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007572 rettv->vval.v_number = get_sw_value(curbuf);
7573}
7574
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575#ifdef FEAT_FLOAT
7576/*
7577 * "sin()" function
7578 */
7579 static void
7580f_sin(typval_T *argvars, typval_T *rettv)
7581{
7582 float_T f = 0.0;
7583
7584 rettv->v_type = VAR_FLOAT;
7585 if (get_float_arg(argvars, &f) == OK)
7586 rettv->vval.v_float = sin(f);
7587 else
7588 rettv->vval.v_float = 0.0;
7589}
7590
7591/*
7592 * "sinh()" function
7593 */
7594 static void
7595f_sinh(typval_T *argvars, typval_T *rettv)
7596{
7597 float_T f = 0.0;
7598
7599 rettv->v_type = VAR_FLOAT;
7600 if (get_float_arg(argvars, &f) == OK)
7601 rettv->vval.v_float = sinh(f);
7602 else
7603 rettv->vval.v_float = 0.0;
7604}
7605#endif
7606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007607/*
7608 * "soundfold({word})" function
7609 */
7610 static void
7611f_soundfold(typval_T *argvars, typval_T *rettv)
7612{
7613 char_u *s;
7614
7615 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007616 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617#ifdef FEAT_SPELL
7618 rettv->vval.v_string = eval_soundfold(s);
7619#else
7620 rettv->vval.v_string = vim_strsave(s);
7621#endif
7622}
7623
7624/*
7625 * "spellbadword()" function
7626 */
7627 static void
7628f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7629{
7630 char_u *word = (char_u *)"";
7631 hlf_T attr = HLF_COUNT;
7632 int len = 0;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007633#ifdef FEAT_SPELL
7634 int wo_spell_save = curwin->w_p_spell;
7635
7636 if (!curwin->w_p_spell)
7637 {
7638 did_set_spelllang(curwin);
7639 curwin->w_p_spell = TRUE;
7640 }
7641
7642 if (*curwin->w_s->b_p_spl == NUL)
7643 {
7644 emsg(_(e_no_spell));
7645 curwin->w_p_spell = wo_spell_save;
7646 return;
7647 }
7648#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649
7650 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007651 {
7652#ifdef FEAT_SPELL
7653 curwin->w_p_spell = wo_spell_save;
7654#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007656 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657
7658#ifdef FEAT_SPELL
7659 if (argvars[0].v_type == VAR_UNKNOWN)
7660 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007661 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007662 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7663 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007664 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007665 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007666 curwin->w_set_curswant = TRUE;
7667 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007668 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007669 else if (*curbuf->b_s.b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007671 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 int capcol = -1;
7673
7674 if (str != NULL)
7675 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007676 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007677 while (*str != NUL)
7678 {
7679 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7680 if (attr != HLF_COUNT)
7681 {
7682 word = str;
7683 break;
7684 }
7685 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007686 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007687 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007688 }
7689 }
7690 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007691 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007692#endif
7693
7694 list_append_string(rettv->vval.v_list, word, len);
7695 list_append_string(rettv->vval.v_list, (char_u *)(
7696 attr == HLF_SPB ? "bad" :
7697 attr == HLF_SPR ? "rare" :
7698 attr == HLF_SPL ? "local" :
7699 attr == HLF_SPC ? "caps" :
7700 ""), -1);
7701}
7702
7703/*
7704 * "spellsuggest()" function
7705 */
7706 static void
7707f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7708{
7709#ifdef FEAT_SPELL
7710 char_u *str;
7711 int typeerr = FALSE;
7712 int maxcount;
7713 garray_T ga;
7714 int i;
7715 listitem_T *li;
7716 int need_capital = FALSE;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007717 int wo_spell_save = curwin->w_p_spell;
7718
7719 if (!curwin->w_p_spell)
7720 {
7721 did_set_spelllang(curwin);
7722 curwin->w_p_spell = TRUE;
7723 }
7724
7725 if (*curwin->w_s->b_p_spl == NUL)
7726 {
7727 emsg(_(e_no_spell));
7728 curwin->w_p_spell = wo_spell_save;
7729 return;
7730 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007731#endif
7732
7733 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007734 {
7735#ifdef FEAT_SPELL
7736 curwin->w_p_spell = wo_spell_save;
7737#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007739 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007740
7741#ifdef FEAT_SPELL
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007742 if (*curwin->w_s->b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007743 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007744 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007745 if (argvars[1].v_type != VAR_UNKNOWN)
7746 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007747 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748 if (maxcount <= 0)
7749 return;
7750 if (argvars[2].v_type != VAR_UNKNOWN)
7751 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007752 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007753 if (typeerr)
7754 return;
7755 }
7756 }
7757 else
7758 maxcount = 25;
7759
7760 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7761
7762 for (i = 0; i < ga.ga_len; ++i)
7763 {
7764 str = ((char_u **)ga.ga_data)[i];
7765
7766 li = listitem_alloc();
7767 if (li == NULL)
7768 vim_free(str);
7769 else
7770 {
7771 li->li_tv.v_type = VAR_STRING;
7772 li->li_tv.v_lock = 0;
7773 li->li_tv.vval.v_string = str;
7774 list_append(rettv->vval.v_list, li);
7775 }
7776 }
7777 ga_clear(&ga);
7778 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007779 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780#endif
7781}
7782
7783 static void
7784f_split(typval_T *argvars, typval_T *rettv)
7785{
7786 char_u *str;
7787 char_u *end;
7788 char_u *pat = NULL;
7789 regmatch_T regmatch;
7790 char_u patbuf[NUMBUFLEN];
7791 char_u *save_cpo;
7792 int match;
7793 colnr_T col = 0;
7794 int keepempty = FALSE;
7795 int typeerr = FALSE;
7796
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007797 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798 save_cpo = p_cpo;
7799 p_cpo = (char_u *)"";
7800
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007801 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007802 if (argvars[1].v_type != VAR_UNKNOWN)
7803 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007804 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805 if (pat == NULL)
7806 typeerr = TRUE;
7807 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007808 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007809 }
7810 if (pat == NULL || *pat == NUL)
7811 pat = (char_u *)"[\\x01- ]\\+";
7812
7813 if (rettv_list_alloc(rettv) == FAIL)
7814 return;
7815 if (typeerr)
7816 return;
7817
7818 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7819 if (regmatch.regprog != NULL)
7820 {
7821 regmatch.rm_ic = FALSE;
7822 while (*str != NUL || keepempty)
7823 {
7824 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007825 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 else
7827 match = vim_regexec_nl(&regmatch, str, col);
7828 if (match)
7829 end = regmatch.startp[0];
7830 else
7831 end = str + STRLEN(str);
7832 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7833 && *str != NUL && match && end < regmatch.endp[0]))
7834 {
7835 if (list_append_string(rettv->vval.v_list, str,
7836 (int)(end - str)) == FAIL)
7837 break;
7838 }
7839 if (!match)
7840 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007841 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007842 if (regmatch.endp[0] > str)
7843 col = 0;
7844 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007845 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007847 str = regmatch.endp[0];
7848 }
7849
7850 vim_regfree(regmatch.regprog);
7851 }
7852
7853 p_cpo = save_cpo;
7854}
7855
7856#ifdef FEAT_FLOAT
7857/*
7858 * "sqrt()" function
7859 */
7860 static void
7861f_sqrt(typval_T *argvars, typval_T *rettv)
7862{
7863 float_T f = 0.0;
7864
7865 rettv->v_type = VAR_FLOAT;
7866 if (get_float_arg(argvars, &f) == OK)
7867 rettv->vval.v_float = sqrt(f);
7868 else
7869 rettv->vval.v_float = 0.0;
7870}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007871#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007872
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007873#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007874/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875 * "str2float()" function
7876 */
7877 static void
7878f_str2float(typval_T *argvars, typval_T *rettv)
7879{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007880 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007881 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882
Bram Moolenaar08243d22017-01-10 16:12:29 +01007883 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007884 p = skipwhite(p + 1);
7885 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007886 if (isneg)
7887 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007888 rettv->v_type = VAR_FLOAT;
7889}
7890#endif
7891
7892/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007893 * "str2list()" function
7894 */
7895 static void
7896f_str2list(typval_T *argvars, typval_T *rettv)
7897{
7898 char_u *p;
7899 int utf8 = FALSE;
7900
7901 if (rettv_list_alloc(rettv) == FAIL)
7902 return;
7903
7904 if (argvars[1].v_type != VAR_UNKNOWN)
7905 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7906
7907 p = tv_get_string(&argvars[0]);
7908
7909 if (has_mbyte || utf8)
7910 {
7911 int (*ptr2len)(char_u *);
7912 int (*ptr2char)(char_u *);
7913
7914 if (utf8 || enc_utf8)
7915 {
7916 ptr2len = utf_ptr2len;
7917 ptr2char = utf_ptr2char;
7918 }
7919 else
7920 {
7921 ptr2len = mb_ptr2len;
7922 ptr2char = mb_ptr2char;
7923 }
7924
7925 for ( ; *p != NUL; p += (*ptr2len)(p))
7926 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7927 }
7928 else
7929 for ( ; *p != NUL; ++p)
7930 list_append_number(rettv->vval.v_list, *p);
7931}
7932
7933/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007934 * "str2nr()" function
7935 */
7936 static void
7937f_str2nr(typval_T *argvars, typval_T *rettv)
7938{
7939 int base = 10;
7940 char_u *p;
7941 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007942 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007943 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007944
7945 if (argvars[1].v_type != VAR_UNKNOWN)
7946 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007947 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007948 if (base != 2 && base != 8 && base != 10 && base != 16)
7949 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007950 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951 return;
7952 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007953 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7954 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007955 }
7956
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007957 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007958 isneg = (*p == '-');
7959 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960 p = skipwhite(p + 1);
7961 switch (base)
7962 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007963 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02007964 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007965 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007966 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007967 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7968 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007969 if (isneg)
7970 rettv->vval.v_number = -n;
7971 else
7972 rettv->vval.v_number = n;
7973
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007974}
7975
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976/*
7977 * "strgetchar()" function
7978 */
7979 static void
7980f_strgetchar(typval_T *argvars, typval_T *rettv)
7981{
7982 char_u *str;
7983 int len;
7984 int error = FALSE;
7985 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007986 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987
7988 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007989 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007990 if (str == NULL)
7991 return;
7992 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007993 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007994 if (error)
7995 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007996
Bram Moolenaar13505972019-01-24 15:04:48 +01007997 while (charidx >= 0 && byteidx < len)
7998 {
7999 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008000 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008001 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8002 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008004 --charidx;
8005 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007}
8008
8009/*
8010 * "stridx()" function
8011 */
8012 static void
8013f_stridx(typval_T *argvars, typval_T *rettv)
8014{
8015 char_u buf[NUMBUFLEN];
8016 char_u *needle;
8017 char_u *haystack;
8018 char_u *save_haystack;
8019 char_u *pos;
8020 int start_idx;
8021
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008022 needle = tv_get_string_chk(&argvars[1]);
8023 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008024 rettv->vval.v_number = -1;
8025 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008026 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008027
8028 if (argvars[2].v_type != VAR_UNKNOWN)
8029 {
8030 int error = FALSE;
8031
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008032 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033 if (error || start_idx >= (int)STRLEN(haystack))
8034 return;
8035 if (start_idx >= 0)
8036 haystack += start_idx;
8037 }
8038
8039 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8040 if (pos != NULL)
8041 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8042}
8043
8044/*
8045 * "string()" function
8046 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008047 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008048f_string(typval_T *argvars, typval_T *rettv)
8049{
8050 char_u *tofree;
8051 char_u numbuf[NUMBUFLEN];
8052
8053 rettv->v_type = VAR_STRING;
8054 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8055 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008056 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008057 if (rettv->vval.v_string != NULL && tofree == NULL)
8058 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8059}
8060
8061/*
8062 * "strlen()" function
8063 */
8064 static void
8065f_strlen(typval_T *argvars, typval_T *rettv)
8066{
8067 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008068 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069}
8070
8071/*
8072 * "strchars()" function
8073 */
8074 static void
8075f_strchars(typval_T *argvars, typval_T *rettv)
8076{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008077 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 varnumber_T len = 0;
8080 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081
8082 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008083 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008085 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 else
8087 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008088 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8089 while (*s != NUL)
8090 {
8091 func_mb_ptr2char_adv(&s);
8092 ++len;
8093 }
8094 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095 }
8096}
8097
8098/*
8099 * "strdisplaywidth()" function
8100 */
8101 static void
8102f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8103{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008104 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008105 int col = 0;
8106
8107 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008108 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008109
8110 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8111}
8112
8113/*
8114 * "strwidth()" function
8115 */
8116 static void
8117f_strwidth(typval_T *argvars, typval_T *rettv)
8118{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008119 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008120
Bram Moolenaar13505972019-01-24 15:04:48 +01008121 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122}
8123
8124/*
8125 * "strcharpart()" function
8126 */
8127 static void
8128f_strcharpart(typval_T *argvars, typval_T *rettv)
8129{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 char_u *p;
8131 int nchar;
8132 int nbyte = 0;
8133 int charlen;
8134 int len = 0;
8135 int slen;
8136 int error = FALSE;
8137
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008138 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008139 slen = (int)STRLEN(p);
8140
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008141 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142 if (!error)
8143 {
8144 if (nchar > 0)
8145 while (nchar > 0 && nbyte < slen)
8146 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008147 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148 --nchar;
8149 }
8150 else
8151 nbyte = nchar;
8152 if (argvars[2].v_type != VAR_UNKNOWN)
8153 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008154 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008155 while (charlen > 0 && nbyte + len < slen)
8156 {
8157 int off = nbyte + len;
8158
8159 if (off < 0)
8160 len += 1;
8161 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008162 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 --charlen;
8164 }
8165 }
8166 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008167 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008168 }
8169
8170 /*
8171 * Only return the overlap between the specified part and the actual
8172 * string.
8173 */
8174 if (nbyte < 0)
8175 {
8176 len += nbyte;
8177 nbyte = 0;
8178 }
8179 else if (nbyte > slen)
8180 nbyte = slen;
8181 if (len < 0)
8182 len = 0;
8183 else if (nbyte + len > slen)
8184 len = slen - nbyte;
8185
8186 rettv->v_type = VAR_STRING;
8187 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188}
8189
8190/*
8191 * "strpart()" function
8192 */
8193 static void
8194f_strpart(typval_T *argvars, typval_T *rettv)
8195{
8196 char_u *p;
8197 int n;
8198 int len;
8199 int slen;
8200 int error = FALSE;
8201
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008202 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008203 slen = (int)STRLEN(p);
8204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008205 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008206 if (error)
8207 len = 0;
8208 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008209 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008210 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008211 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008212
8213 /*
8214 * Only return the overlap between the specified part and the actual
8215 * string.
8216 */
8217 if (n < 0)
8218 {
8219 len += n;
8220 n = 0;
8221 }
8222 else if (n > slen)
8223 n = slen;
8224 if (len < 0)
8225 len = 0;
8226 else if (n + len > slen)
8227 len = slen - n;
8228
8229 rettv->v_type = VAR_STRING;
8230 rettv->vval.v_string = vim_strnsave(p + n, len);
8231}
8232
8233/*
8234 * "strridx()" function
8235 */
8236 static void
8237f_strridx(typval_T *argvars, typval_T *rettv)
8238{
8239 char_u buf[NUMBUFLEN];
8240 char_u *needle;
8241 char_u *haystack;
8242 char_u *rest;
8243 char_u *lastmatch = NULL;
8244 int haystack_len, end_idx;
8245
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008246 needle = tv_get_string_chk(&argvars[1]);
8247 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008248
8249 rettv->vval.v_number = -1;
8250 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008251 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008252
8253 haystack_len = (int)STRLEN(haystack);
8254 if (argvars[2].v_type != VAR_UNKNOWN)
8255 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008256 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008257 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008258 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008259 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008260 }
8261 else
8262 end_idx = haystack_len;
8263
8264 if (*needle == NUL)
8265 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008266 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008267 lastmatch = haystack + end_idx;
8268 }
8269 else
8270 {
8271 for (rest = haystack; *rest != '\0'; ++rest)
8272 {
8273 rest = (char_u *)strstr((char *)rest, (char *)needle);
8274 if (rest == NULL || rest > haystack + end_idx)
8275 break;
8276 lastmatch = rest;
8277 }
8278 }
8279
8280 if (lastmatch == NULL)
8281 rettv->vval.v_number = -1;
8282 else
8283 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8284}
8285
8286/*
8287 * "strtrans()" function
8288 */
8289 static void
8290f_strtrans(typval_T *argvars, typval_T *rettv)
8291{
8292 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008293 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008294}
8295
8296/*
8297 * "submatch()" function
8298 */
8299 static void
8300f_submatch(typval_T *argvars, typval_T *rettv)
8301{
8302 int error = FALSE;
8303 int no;
8304 int retList = 0;
8305
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008306 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008307 if (error)
8308 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008309 if (no < 0 || no >= NSUBEXP)
8310 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008311 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008312 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008313 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008315 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316 if (error)
8317 return;
8318
8319 if (retList == 0)
8320 {
8321 rettv->v_type = VAR_STRING;
8322 rettv->vval.v_string = reg_submatch(no);
8323 }
8324 else
8325 {
8326 rettv->v_type = VAR_LIST;
8327 rettv->vval.v_list = reg_submatch_list(no);
8328 }
8329}
8330
8331/*
8332 * "substitute()" function
8333 */
8334 static void
8335f_substitute(typval_T *argvars, typval_T *rettv)
8336{
8337 char_u patbuf[NUMBUFLEN];
8338 char_u subbuf[NUMBUFLEN];
8339 char_u flagsbuf[NUMBUFLEN];
8340
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008341 char_u *str = tv_get_string_chk(&argvars[0]);
8342 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008343 char_u *sub = NULL;
8344 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008345 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008346
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008347 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8348 expr = &argvars[2];
8349 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008350 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008351
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008352 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008353 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8354 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008355 rettv->vval.v_string = NULL;
8356 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008357 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008358}
8359
8360/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008361 * "swapinfo(swap_filename)" function
8362 */
8363 static void
8364f_swapinfo(typval_T *argvars, typval_T *rettv)
8365{
8366 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008367 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008368}
8369
8370/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008371 * "swapname(expr)" function
8372 */
8373 static void
8374f_swapname(typval_T *argvars, typval_T *rettv)
8375{
8376 buf_T *buf;
8377
8378 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008379 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008380 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8381 || buf->b_ml.ml_mfp->mf_fname == NULL)
8382 rettv->vval.v_string = NULL;
8383 else
8384 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8385}
8386
8387/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 * "synID(lnum, col, trans)" function
8389 */
8390 static void
8391f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8392{
8393 int id = 0;
8394#ifdef FEAT_SYN_HL
8395 linenr_T lnum;
8396 colnr_T col;
8397 int trans;
8398 int transerr = FALSE;
8399
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008400 lnum = tv_get_lnum(argvars); // -1 on type error
8401 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008402 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008403
8404 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8405 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8406 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8407#endif
8408
8409 rettv->vval.v_number = id;
8410}
8411
8412/*
8413 * "synIDattr(id, what [, mode])" function
8414 */
8415 static void
8416f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8417{
8418 char_u *p = NULL;
8419#ifdef FEAT_SYN_HL
8420 int id;
8421 char_u *what;
8422 char_u *mode;
8423 char_u modebuf[NUMBUFLEN];
8424 int modec;
8425
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008426 id = (int)tv_get_number(&argvars[0]);
8427 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008428 if (argvars[2].v_type != VAR_UNKNOWN)
8429 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008430 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008431 modec = TOLOWER_ASC(mode[0]);
8432 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008433 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008434 }
8435 else
8436 {
8437#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8438 if (USE_24BIT)
8439 modec = 'g';
8440 else
8441#endif
8442 if (t_colors > 1)
8443 modec = 'c';
8444 else
8445 modec = 't';
8446 }
8447
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448 switch (TOLOWER_ASC(what[0]))
8449 {
8450 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008451 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008452 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008453 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008454 p = highlight_has_attr(id, HL_BOLD, modec);
8455 break;
8456
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008457 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458 p = highlight_color(id, what, modec);
8459 break;
8460
8461 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008462 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008464 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008465 p = highlight_has_attr(id, HL_ITALIC, modec);
8466 break;
8467
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008468 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008469 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470 break;
8471
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008472 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008473 p = highlight_has_attr(id, HL_INVERSE, modec);
8474 break;
8475
8476 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008477 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008478 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008479 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008480 else if (TOLOWER_ASC(what[1]) == 't' &&
8481 TOLOWER_ASC(what[2]) == 'r')
8482 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008483 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008484 p = highlight_has_attr(id, HL_STANDOUT, modec);
8485 break;
8486
8487 case 'u':
8488 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008489 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8491 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008492 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008493 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8494 break;
8495 }
8496
8497 if (p != NULL)
8498 p = vim_strsave(p);
8499#endif
8500 rettv->v_type = VAR_STRING;
8501 rettv->vval.v_string = p;
8502}
8503
8504/*
8505 * "synIDtrans(id)" function
8506 */
8507 static void
8508f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8509{
8510 int id;
8511
8512#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008513 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008514
8515 if (id > 0)
8516 id = syn_get_final_id(id);
8517 else
8518#endif
8519 id = 0;
8520
8521 rettv->vval.v_number = id;
8522}
8523
8524/*
8525 * "synconcealed(lnum, col)" function
8526 */
8527 static void
8528f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8529{
8530#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8531 linenr_T lnum;
8532 colnr_T col;
8533 int syntax_flags = 0;
8534 int cchar;
8535 int matchid = 0;
8536 char_u str[NUMBUFLEN];
8537#endif
8538
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008539 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008540
8541#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008542 lnum = tv_get_lnum(argvars); // -1 on type error
8543 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008544
Bram Moolenaara80faa82020-04-12 19:37:17 +02008545 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008546
8547 if (rettv_list_alloc(rettv) != FAIL)
8548 {
8549 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8550 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8551 && curwin->w_p_cole > 0)
8552 {
8553 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8554 syntax_flags = get_syntax_info(&matchid);
8555
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008556 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008557 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8558 {
8559 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008560 if (cchar == NUL && curwin->w_p_cole == 1)
8561 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008562 if (cchar != NUL)
8563 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008564 if (has_mbyte)
8565 (*mb_char2bytes)(cchar, str);
8566 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008567 str[0] = cchar;
8568 }
8569 }
8570 }
8571
8572 list_append_number(rettv->vval.v_list,
8573 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008574 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008575 list_append_string(rettv->vval.v_list, str, -1);
8576 list_append_number(rettv->vval.v_list, matchid);
8577 }
8578#endif
8579}
8580
8581/*
8582 * "synstack(lnum, col)" function
8583 */
8584 static void
8585f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8586{
8587#ifdef FEAT_SYN_HL
8588 linenr_T lnum;
8589 colnr_T col;
8590 int i;
8591 int id;
8592#endif
8593
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008594 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595
8596#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008597 lnum = tv_get_lnum(argvars); // -1 on type error
8598 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008599
8600 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8601 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8602 && rettv_list_alloc(rettv) != FAIL)
8603 {
8604 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8605 for (i = 0; ; ++i)
8606 {
8607 id = syn_get_stack_item(i);
8608 if (id < 0)
8609 break;
8610 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8611 break;
8612 }
8613 }
8614#endif
8615}
8616
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008617/*
8618 * "tabpagebuflist()" function
8619 */
8620 static void
8621f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8622{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008623 tabpage_T *tp;
8624 win_T *wp = NULL;
8625
8626 if (argvars[0].v_type == VAR_UNKNOWN)
8627 wp = firstwin;
8628 else
8629 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008630 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008631 if (tp != NULL)
8632 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8633 }
8634 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8635 {
8636 for (; wp != NULL; wp = wp->w_next)
8637 if (list_append_number(rettv->vval.v_list,
8638 wp->w_buffer->b_fnum) == FAIL)
8639 break;
8640 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008641}
8642
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008643/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644 * "tagfiles()" function
8645 */
8646 static void
8647f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8648{
8649 char_u *fname;
8650 tagname_T tn;
8651 int first;
8652
8653 if (rettv_list_alloc(rettv) == FAIL)
8654 return;
8655 fname = alloc(MAXPATHL);
8656 if (fname == NULL)
8657 return;
8658
8659 for (first = TRUE; ; first = FALSE)
8660 if (get_tagfname(&tn, first, fname) == FAIL
8661 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8662 break;
8663 tagname_free(&tn);
8664 vim_free(fname);
8665}
8666
8667/*
8668 * "taglist()" function
8669 */
8670 static void
8671f_taglist(typval_T *argvars, typval_T *rettv)
8672{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008673 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008674 char_u *tag_pattern;
8675
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008676 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008677
8678 rettv->vval.v_number = FALSE;
8679 if (*tag_pattern == NUL)
8680 return;
8681
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008682 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008683 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008684 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008685 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008686}
8687
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008688#ifdef FEAT_FLOAT
8689/*
8690 * "tan()" function
8691 */
8692 static void
8693f_tan(typval_T *argvars, typval_T *rettv)
8694{
8695 float_T f = 0.0;
8696
8697 rettv->v_type = VAR_FLOAT;
8698 if (get_float_arg(argvars, &f) == OK)
8699 rettv->vval.v_float = tan(f);
8700 else
8701 rettv->vval.v_float = 0.0;
8702}
8703
8704/*
8705 * "tanh()" function
8706 */
8707 static void
8708f_tanh(typval_T *argvars, typval_T *rettv)
8709{
8710 float_T f = 0.0;
8711
8712 rettv->v_type = VAR_FLOAT;
8713 if (get_float_arg(argvars, &f) == OK)
8714 rettv->vval.v_float = tanh(f);
8715 else
8716 rettv->vval.v_float = 0.0;
8717}
8718#endif
8719
8720/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008721 * "tolower(string)" function
8722 */
8723 static void
8724f_tolower(typval_T *argvars, typval_T *rettv)
8725{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008727 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008728}
8729
8730/*
8731 * "toupper(string)" function
8732 */
8733 static void
8734f_toupper(typval_T *argvars, typval_T *rettv)
8735{
8736 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008737 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008738}
8739
8740/*
8741 * "tr(string, fromstr, tostr)" function
8742 */
8743 static void
8744f_tr(typval_T *argvars, typval_T *rettv)
8745{
8746 char_u *in_str;
8747 char_u *fromstr;
8748 char_u *tostr;
8749 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008750 int inlen;
8751 int fromlen;
8752 int tolen;
8753 int idx;
8754 char_u *cpstr;
8755 int cplen;
8756 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008757 char_u buf[NUMBUFLEN];
8758 char_u buf2[NUMBUFLEN];
8759 garray_T ga;
8760
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008761 in_str = tv_get_string(&argvars[0]);
8762 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8763 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008764
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008765 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008766 rettv->v_type = VAR_STRING;
8767 rettv->vval.v_string = NULL;
8768 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008769 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008770 ga_init2(&ga, (int)sizeof(char), 80);
8771
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008772 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008773 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008774 if (STRLEN(fromstr) != STRLEN(tostr))
8775 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008776error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008777 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008778 ga_clear(&ga);
8779 return;
8780 }
8781
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008782 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008783 while (*in_str != NUL)
8784 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008785 if (has_mbyte)
8786 {
8787 inlen = (*mb_ptr2len)(in_str);
8788 cpstr = in_str;
8789 cplen = inlen;
8790 idx = 0;
8791 for (p = fromstr; *p != NUL; p += fromlen)
8792 {
8793 fromlen = (*mb_ptr2len)(p);
8794 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8795 {
8796 for (p = tostr; *p != NUL; p += tolen)
8797 {
8798 tolen = (*mb_ptr2len)(p);
8799 if (idx-- == 0)
8800 {
8801 cplen = tolen;
8802 cpstr = p;
8803 break;
8804 }
8805 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008806 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008807 goto error;
8808 break;
8809 }
8810 ++idx;
8811 }
8812
8813 if (first && cpstr == in_str)
8814 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008815 // Check that fromstr and tostr have the same number of
8816 // (multi-byte) characters. Done only once when a character
8817 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008818 first = FALSE;
8819 for (p = tostr; *p != NUL; p += tolen)
8820 {
8821 tolen = (*mb_ptr2len)(p);
8822 --idx;
8823 }
8824 if (idx != 0)
8825 goto error;
8826 }
8827
8828 (void)ga_grow(&ga, cplen);
8829 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8830 ga.ga_len += cplen;
8831
8832 in_str += inlen;
8833 }
8834 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008835 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008836 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008837 p = vim_strchr(fromstr, *in_str);
8838 if (p != NULL)
8839 ga_append(&ga, tostr[p - fromstr]);
8840 else
8841 ga_append(&ga, *in_str);
8842 ++in_str;
8843 }
8844 }
8845
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008846 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008847 (void)ga_grow(&ga, 1);
8848 ga_append(&ga, NUL);
8849
8850 rettv->vval.v_string = ga.ga_data;
8851}
8852
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008853/*
8854 * "trim({expr})" function
8855 */
8856 static void
8857f_trim(typval_T *argvars, typval_T *rettv)
8858{
8859 char_u buf1[NUMBUFLEN];
8860 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008861 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008862 char_u *mask = NULL;
8863 char_u *tail;
8864 char_u *prev;
8865 char_u *p;
8866 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008867 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008868
8869 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008870 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008871 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008872 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008873
8874 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008875 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008876 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008877
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008878 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008879 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008880 int error = 0;
8881
8882 // leading or trailing characters to trim
8883 dir = (int)tv_get_number_chk(&argvars[2], &error);
8884 if (error)
8885 return;
8886 if (dir < 0 || dir > 2)
8887 {
8888 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8889 return;
8890 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008891 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008892 }
8893
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008894 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008895 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008896 // Trim leading characters
8897 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008898 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008899 c1 = PTR2CHAR(head);
8900 if (mask == NULL)
8901 {
8902 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008903 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008904 }
8905 else
8906 {
8907 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8908 if (c1 == PTR2CHAR(p))
8909 break;
8910 if (*p == NUL)
8911 break;
8912 }
8913 MB_PTR_ADV(head);
8914 }
8915 }
8916
8917 tail = head + STRLEN(head);
8918 if (dir == 0 || dir == 2)
8919 {
8920 // Trim trailing characters
8921 for (; tail > head; tail = prev)
8922 {
8923 prev = tail;
8924 MB_PTR_BACK(head, prev);
8925 c1 = PTR2CHAR(prev);
8926 if (mask == NULL)
8927 {
8928 if (c1 > ' ' && c1 != 0xa0)
8929 break;
8930 }
8931 else
8932 {
8933 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8934 if (c1 == PTR2CHAR(p))
8935 break;
8936 if (*p == NUL)
8937 break;
8938 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008939 }
8940 }
Bram Moolenaardf44a272020-06-07 20:49:05 +02008941 rettv->vval.v_string = vim_strnsave(head, tail - head);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008942}
8943
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008944#ifdef FEAT_FLOAT
8945/*
8946 * "trunc({float})" function
8947 */
8948 static void
8949f_trunc(typval_T *argvars, typval_T *rettv)
8950{
8951 float_T f = 0.0;
8952
8953 rettv->v_type = VAR_FLOAT;
8954 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008955 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008956 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8957 else
8958 rettv->vval.v_float = 0.0;
8959}
8960#endif
8961
8962/*
8963 * "type(expr)" function
8964 */
8965 static void
8966f_type(typval_T *argvars, typval_T *rettv)
8967{
8968 int n = -1;
8969
8970 switch (argvars[0].v_type)
8971 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008972 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8973 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008974 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008975 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8976 case VAR_LIST: n = VAR_TYPE_LIST; break;
8977 case VAR_DICT: n = VAR_TYPE_DICT; break;
8978 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8979 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8980 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008981 case VAR_JOB: n = VAR_TYPE_JOB; break;
8982 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008983 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008984 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02008985 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008986 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008987 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008988 n = -1;
8989 break;
8990 }
8991 rettv->vval.v_number = n;
8992}
8993
8994/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008995 * "virtcol(string)" function
8996 */
8997 static void
8998f_virtcol(typval_T *argvars, typval_T *rettv)
8999{
9000 colnr_T vcol = 0;
9001 pos_T *fp;
9002 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009003 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009004
9005 fp = var2fpos(&argvars[0], FALSE, &fnum);
9006 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9007 && fnum == curbuf->b_fnum)
9008 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009009 // Limit the column to a valid value, getvvcol() doesn't check.
9010 if (fp->col < 0)
9011 fp->col = 0;
9012 else
9013 {
9014 len = (int)STRLEN(ml_get(fp->lnum));
9015 if (fp->col > len)
9016 fp->col = len;
9017 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009018 getvvcol(curwin, fp, NULL, NULL, &vcol);
9019 ++vcol;
9020 }
9021
9022 rettv->vval.v_number = vcol;
9023}
9024
9025/*
9026 * "visualmode()" function
9027 */
9028 static void
9029f_visualmode(typval_T *argvars, typval_T *rettv)
9030{
9031 char_u str[2];
9032
9033 rettv->v_type = VAR_STRING;
9034 str[0] = curbuf->b_visual_mode_eval;
9035 str[1] = NUL;
9036 rettv->vval.v_string = vim_strsave(str);
9037
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009038 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009039 if (non_zero_arg(&argvars[0]))
9040 curbuf->b_visual_mode_eval = NUL;
9041}
9042
9043/*
9044 * "wildmenumode()" function
9045 */
9046 static void
9047f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9048{
9049#ifdef FEAT_WILDMENU
9050 if (wild_menu_showing)
9051 rettv->vval.v_number = 1;
9052#endif
9053}
9054
9055/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01009056 * "windowsversion()" function
9057 */
9058 static void
9059f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9060{
9061 rettv->v_type = VAR_STRING;
9062 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
9063}
9064
9065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009066 * "wordcount()" function
9067 */
9068 static void
9069f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
9070{
9071 if (rettv_dict_alloc(rettv) == FAIL)
9072 return;
9073 cursor_pos_info(rettv->vval.v_dict);
9074}
9075
9076/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009077 * "xor(expr, expr)" function
9078 */
9079 static void
9080f_xor(typval_T *argvars, typval_T *rettv)
9081{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009082 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9083 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009084}
9085
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009086#endif // FEAT_EVAL