blob: 5383d098f4a5528777ab33bae51be0065c596ff2 [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 Moolenaar6f02b002021-01-10 20:22:54 +010050static void f_charcol(typval_T *argvars, typval_T *rettv);
Bram Moolenaar17793ef2020-12-28 12:56:58 +010051static void f_charidx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020053static void f_confirm(typval_T *argvars, typval_T *rettv);
54static void f_copy(typval_T *argvars, typval_T *rettv);
55#ifdef FEAT_FLOAT
56static void f_cos(typval_T *argvars, typval_T *rettv);
57static void f_cosh(typval_T *argvars, typval_T *rettv);
58#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020059static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010060#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020061static void f_debugbreak(typval_T *argvars, typval_T *rettv);
62#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020063static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010065static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020067static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020068static void f_escape(typval_T *argvars, typval_T *rettv);
69static void f_eval(typval_T *argvars, typval_T *rettv);
70static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020071static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_exists(typval_T *argvars, typval_T *rettv);
73#ifdef FEAT_FLOAT
74static void f_exp(typval_T *argvars, typval_T *rettv);
75#endif
76static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020077static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020078static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020079#ifdef FEAT_FLOAT
80static void f_float2nr(typval_T *argvars, typval_T *rettv);
81static void f_floor(typval_T *argvars, typval_T *rettv);
82static void f_fmod(typval_T *argvars, typval_T *rettv);
83#endif
84static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020086static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020087static void f_function(typval_T *argvars, typval_T *rettv);
88static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
89static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010090static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6f02b002021-01-10 20:22:54 +010091static void f_getcharpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020093static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020094static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010095static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getpid(typval_T *argvars, typval_T *rettv);
97static void f_getcurpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6f02b002021-01-10 20:22:54 +010098static void f_getcursorcharpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_getreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarbb861e22020-06-07 18:16:36 +0200101static void f_getreginfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200102static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100103static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +0200104static void f_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
106static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_hlID(typval_T *argvars, typval_T *rettv);
108static void f_hlexists(typval_T *argvars, typval_T *rettv);
109static void f_hostname(typval_T *argvars, typval_T *rettv);
110static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200111static void f_index(typval_T *argvars, typval_T *rettv);
112static void f_input(typval_T *argvars, typval_T *rettv);
113static void f_inputdialog(typval_T *argvars, typval_T *rettv);
114static void f_inputlist(typval_T *argvars, typval_T *rettv);
115static void f_inputrestore(typval_T *argvars, typval_T *rettv);
116static void f_inputsave(typval_T *argvars, typval_T *rettv);
117static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100118static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200120static void f_islocked(typval_T *argvars, typval_T *rettv);
121#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200122static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200123static void f_isnan(typval_T *argvars, typval_T *rettv);
124#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
126static void f_len(typval_T *argvars, typval_T *rettv);
127static void f_libcall(typval_T *argvars, typval_T *rettv);
128static void f_libcallnr(typval_T *argvars, typval_T *rettv);
129static void f_line(typval_T *argvars, typval_T *rettv);
130static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200131#ifdef FEAT_FLOAT
132static void f_log(typval_T *argvars, typval_T *rettv);
133static void f_log10(typval_T *argvars, typval_T *rettv);
134#endif
135#ifdef FEAT_LUA
136static void f_luaeval(typval_T *argvars, typval_T *rettv);
137#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200138static void f_maparg(typval_T *argvars, typval_T *rettv);
139static void f_mapcheck(typval_T *argvars, typval_T *rettv);
140static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_matchend(typval_T *argvars, typval_T *rettv);
142static void f_matchlist(typval_T *argvars, typval_T *rettv);
143static void f_matchstr(typval_T *argvars, typval_T *rettv);
144static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
145static void f_max(typval_T *argvars, typval_T *rettv);
146static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_MZSCHEME
148static void f_mzeval(typval_T *argvars, typval_T *rettv);
149#endif
150static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
151static void f_nr2char(typval_T *argvars, typval_T *rettv);
152static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200153#ifdef FEAT_PERL
154static void f_perleval(typval_T *argvars, typval_T *rettv);
155#endif
156#ifdef FEAT_FLOAT
157static void f_pow(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
160static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200161static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200162static void f_pumvisible(typval_T *argvars, typval_T *rettv);
163#ifdef FEAT_PYTHON3
164static void f_py3eval(typval_T *argvars, typval_T *rettv);
165#endif
166#ifdef FEAT_PYTHON
167static void f_pyeval(typval_T *argvars, typval_T *rettv);
168#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100169#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
170static void f_pyxeval(typval_T *argvars, typval_T *rettv);
171#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100172static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100173static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200175static void f_reg_executing(typval_T *argvars, typval_T *rettv);
176static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_rename(typval_T *argvars, typval_T *rettv);
178static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179#ifdef FEAT_FLOAT
180static void f_round(typval_T *argvars, typval_T *rettv);
181#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100182#ifdef FEAT_RUBY
183static void f_rubyeval(typval_T *argvars, typval_T *rettv);
184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_screenattr(typval_T *argvars, typval_T *rettv);
186static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100187static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_screencol(typval_T *argvars, typval_T *rettv);
189static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100190static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_search(typval_T *argvars, typval_T *rettv);
192static void f_searchdecl(typval_T *argvars, typval_T *rettv);
193static void f_searchpair(typval_T *argvars, typval_T *rettv);
194static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
195static void f_searchpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6f02b002021-01-10 20:22:54 +0100196static void f_setcharpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6f02b002021-01-10 20:22:54 +0100198static void f_setcursorcharpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200199static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100203static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204#ifdef FEAT_CRYPT
205static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_shellescape(typval_T *argvars, typval_T *rettv);
208static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209#ifdef FEAT_FLOAT
210static void f_sin(typval_T *argvars, typval_T *rettv);
211static void f_sinh(typval_T *argvars, typval_T *rettv);
212#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_soundfold(typval_T *argvars, typval_T *rettv);
214static void f_spellbadword(typval_T *argvars, typval_T *rettv);
215static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
216static void f_split(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100219#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100220static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100221#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_str2float(typval_T *argvars, typval_T *rettv);
223#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200224static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_str2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar70ce8a12021-03-14 19:02:09 +0100226static void f_strcharlen(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200227static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200228static void f_strgetchar(typval_T *argvars, typval_T *rettv);
229static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200230static void f_strlen(typval_T *argvars, typval_T *rettv);
231static void f_strcharpart(typval_T *argvars, typval_T *rettv);
232static void f_strpart(typval_T *argvars, typval_T *rettv);
233static void f_strridx(typval_T *argvars, typval_T *rettv);
234static void f_strtrans(typval_T *argvars, typval_T *rettv);
235static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
236static void f_strwidth(typval_T *argvars, typval_T *rettv);
237static void f_submatch(typval_T *argvars, typval_T *rettv);
238static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200239static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200240static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200241static void f_synID(typval_T *argvars, typval_T *rettv);
242static void f_synIDattr(typval_T *argvars, typval_T *rettv);
243static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
244static void f_synstack(typval_T *argvars, typval_T *rettv);
245static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200247static void f_taglist(typval_T *argvars, typval_T *rettv);
248static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200249#ifdef FEAT_FLOAT
250static void f_tan(typval_T *argvars, typval_T *rettv);
251static void f_tanh(typval_T *argvars, typval_T *rettv);
252#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200253static void f_tolower(typval_T *argvars, typval_T *rettv);
254static void f_toupper(typval_T *argvars, typval_T *rettv);
255static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100256static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200257#ifdef FEAT_FLOAT
258static void f_trunc(typval_T *argvars, typval_T *rettv);
259#endif
260static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_virtcol(typval_T *argvars, typval_T *rettv);
262static void f_visualmode(typval_T *argvars, typval_T *rettv);
263static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100264static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200265static void f_wordcount(typval_T *argvars, typval_T *rettv);
266static void f_xor(typval_T *argvars, typval_T *rettv);
267
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100268
Bram Moolenaar94738d82020-10-21 14:25:07 +0200269/*
270 * Functions that check the argument type of a builtin function.
271 * Each function returns FAIL and gives an error message if the type is wrong.
272 */
273
274// Context passed to an arg_ function.
275typedef struct {
Bram Moolenaarca174532020-10-21 16:42:22 +0200276 int arg_count; // actual argument count
277 type_T **arg_types; // list of argument types
278 int arg_idx; // current argument index (first arg is zero)
Bram Moolenaar351ead02021-01-16 16:07:01 +0100279 cctx_T *arg_cctx;
Bram Moolenaar94738d82020-10-21 14:25:07 +0200280} argcontext_T;
281
282// A function to check one argument type. The first argument is the type to
283// check. If needed, other argument types can be obtained with the context.
284// E.g. if "arg_idx" is 1, then (type - 1) is the first argument type.
285typedef int (*argcheck_T)(type_T *, argcontext_T *);
286
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100287/*
Bram Moolenaar351ead02021-01-16 16:07:01 +0100288 * Call need_type() to check an argument type.
289 */
290 static int
291check_arg_type(
292 type_T *expected,
293 type_T *actual,
294 argcontext_T *context)
295{
296 // TODO: would be useful to know if "actual" is a constant and pass it to
297 // need_type() to get a compile time error if possible.
298 return need_type(actual, expected,
299 context->arg_idx - context->arg_count, context->arg_idx + 1,
300 context->arg_cctx, FALSE, FALSE);
301}
302
303/*
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100304 * Check "type" is a float or a number.
305 */
Bram Moolenaar94738d82020-10-21 14:25:07 +0200306 static int
307arg_float_or_nr(type_T *type, argcontext_T *context)
308{
Bram Moolenaarca174532020-10-21 16:42:22 +0200309 if (type->tt_type == VAR_ANY
310 || type->tt_type == VAR_FLOAT || type->tt_type == VAR_NUMBER)
Bram Moolenaar94738d82020-10-21 14:25:07 +0200311 return OK;
312 arg_type_mismatch(&t_number, type, context->arg_idx + 1);
313 return FAIL;
314}
315
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100316/*
317 * Check "type" is a number.
318 */
Bram Moolenaarca174532020-10-21 16:42:22 +0200319 static int
320arg_number(type_T *type, argcontext_T *context)
321{
Bram Moolenaar351ead02021-01-16 16:07:01 +0100322 return check_arg_type(&t_number, type, context);
Bram Moolenaarca174532020-10-21 16:42:22 +0200323}
324
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100325/*
326 * Check "type" is a string.
327 */
328 static int
329arg_string(type_T *type, argcontext_T *context)
330{
Bram Moolenaar351ead02021-01-16 16:07:01 +0100331 return check_arg_type(&t_string, type, context);
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100332}
333
334/*
Bram Moolenaarf2b26bc2021-01-30 23:05:11 +0100335 * Check "type" is a bool or number 0 or 1.
336 */
337 static int
338arg_bool(type_T *type, argcontext_T *context)
339{
340 if (type->tt_type == VAR_ANY
341 || type->tt_type == VAR_NUMBER || type->tt_type == VAR_BOOL)
342 return OK;
343 return check_arg_type(&t_bool, type, context);
344}
345
346/*
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100347 * Check "type" is a list or a blob.
348 */
Bram Moolenaarca174532020-10-21 16:42:22 +0200349 static int
350arg_list_or_blob(type_T *type, argcontext_T *context)
351{
352 if (type->tt_type == VAR_ANY
353 || type->tt_type == VAR_LIST || type->tt_type == VAR_BLOB)
354 return OK;
355 arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
356 return FAIL;
357}
358
359/*
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100360 * Check "type" is a list or a dict.
361 */
362 static int
363arg_list_or_dict(type_T *type, argcontext_T *context)
364{
365 if (type->tt_type == VAR_ANY
366 || type->tt_type == VAR_LIST || type->tt_type == VAR_DICT)
367 return OK;
368 arg_type_mismatch(&t_list_any, type, context->arg_idx + 1);
369 return FAIL;
370}
371
372/*
Bram Moolenaarb0e6b512021-01-12 20:23:40 +0100373 * Check "type" is the same type as the previous argument.
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100374 * Must not be used for the first argcheck_T entry.
375 */
376 static int
377arg_same_as_prev(type_T *type, argcontext_T *context)
378{
379 type_T *prev_type = context->arg_types[context->arg_idx - 1];
380
Bram Moolenaar351ead02021-01-16 16:07:01 +0100381 return check_arg_type(prev_type, type, context);
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100382}
383
384/*
Bram Moolenaarb0e6b512021-01-12 20:23:40 +0100385 * Check "type" is the same basic type as the previous argument, checks list or
386 * dict vs other type, but not member type.
387 * Must not be used for the first argcheck_T entry.
388 */
389 static int
390arg_same_struct_as_prev(type_T *type, argcontext_T *context)
391{
392 type_T *prev_type = context->arg_types[context->arg_idx - 1];
393
394 if (prev_type->tt_type != context->arg_types[context->arg_idx]->tt_type)
Bram Moolenaar351ead02021-01-16 16:07:01 +0100395 return check_arg_type(prev_type, type, context);
Bram Moolenaarb0e6b512021-01-12 20:23:40 +0100396 return OK;
397}
398
399/*
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100400 * Check "type" is an item of the list or blob of the previous arg.
Bram Moolenaarca174532020-10-21 16:42:22 +0200401 * Must not be used for the first argcheck_T entry.
402 */
403 static int
404arg_item_of_prev(type_T *type, argcontext_T *context)
405{
406 type_T *prev_type = context->arg_types[context->arg_idx - 1];
407 type_T *expected;
408
409 if (prev_type->tt_type == VAR_LIST)
410 expected = prev_type->tt_member;
411 else if (prev_type->tt_type == VAR_BLOB)
412 expected = &t_number;
413 else
414 // probably VAR_ANY, can't check
415 return OK;
416
Bram Moolenaar351ead02021-01-16 16:07:01 +0100417 return check_arg_type(expected, type, context);
Bram Moolenaarca174532020-10-21 16:42:22 +0200418}
419
Bram Moolenaar94738d82020-10-21 14:25:07 +0200420/*
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100421 * Check "type" which is the third argument of extend().
422 */
423 static int
424arg_extend3(type_T *type, argcontext_T *context)
425{
426 type_T *first_type = context->arg_types[context->arg_idx - 2];
427
428 if (first_type->tt_type == VAR_LIST)
429 return arg_number(type, context);
430 if (first_type->tt_type == VAR_DICT)
431 return arg_string(type, context);
432 return OK;
433}
434
435
436/*
Bram Moolenaar94738d82020-10-21 14:25:07 +0200437 * Lists of functions that check the argument types of a builtin function.
438 */
Bram Moolenaar80ad3e22021-01-31 20:48:58 +0100439argcheck_T arg1_string[] = {arg_string};
Bram Moolenaarf2b26bc2021-01-30 23:05:11 +0100440argcheck_T arg3_string_nr_bool[] = {arg_string, arg_number, arg_bool};
Bram Moolenaar94738d82020-10-21 14:25:07 +0200441argcheck_T arg1_float_or_nr[] = {arg_float_or_nr};
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100442argcheck_T arg2_listblob_item[] = {arg_list_or_blob, arg_item_of_prev};
443argcheck_T arg23_extend[] = {arg_list_or_dict, arg_same_as_prev, arg_extend3};
Bram Moolenaarb0e6b512021-01-12 20:23:40 +0100444argcheck_T arg23_extendnew[] = {arg_list_or_dict, arg_same_struct_as_prev, arg_extend3};
Bram Moolenaarca174532020-10-21 16:42:22 +0200445argcheck_T arg3_insert[] = {arg_list_or_blob, arg_item_of_prev, arg_number};
Bram Moolenaar94738d82020-10-21 14:25:07 +0200446
447/*
448 * Functions that return the return type of a builtin function.
Bram Moolenaara1224cb2020-10-22 12:31:49 +0200449 * Note that "argtypes" is NULL if "argcount" is zero.
Bram Moolenaar94738d82020-10-21 14:25:07 +0200450 */
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100451 static type_T *
452ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
453{
454 return &t_void;
455}
456 static type_T *
457ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
458{
459 return &t_any;
460}
461 static type_T *
Bram Moolenaar403dc312020-10-17 19:29:51 +0200462ret_bool(int argcount UNUSED, type_T **argtypes UNUSED)
463{
464 return &t_bool;
465}
466 static type_T *
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100467ret_number_bool(int argcount UNUSED, type_T **argtypes UNUSED)
468{
469 return &t_number_bool;
470}
471 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100472ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
473{
474 return &t_number;
475}
476 static type_T *
477ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
478{
479 return &t_float;
480}
481 static type_T *
482ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
483{
484 return &t_string;
485}
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200486 static type_T *
487ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100488{
489 return &t_list_any;
490}
491 static type_T *
492ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
493{
494 return &t_list_number;
495}
496 static type_T *
497ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
498{
499 return &t_list_string;
500}
501 static type_T *
502ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
503{
504 return &t_list_dict_any;
505}
506 static type_T *
507ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
508{
509 return &t_dict_any;
510}
511 static type_T *
Bram Moolenaar64ed4d42021-01-12 21:22:31 +0100512ret_job_info(int argcount, type_T **argtypes UNUSED)
513{
514 if (argcount == 0)
515 return &t_list_job;
516 return &t_dict_any;
517}
518 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100519ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
520{
521 return &t_dict_number;
522}
523 static type_T *
524ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
525{
526 return &t_dict_string;
527}
528 static type_T *
529ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
530{
531 return &t_blob;
532}
533 static type_T *
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200534ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100535{
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200536 return &t_func_any;
537}
538 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100539ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
540{
541 return &t_channel;
542}
543 static type_T *
544ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
545{
546 return &t_job;
547}
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200548 static type_T *
549ret_first_arg(int argcount, type_T **argtypes)
550{
551 if (argcount > 0)
552 return argtypes[0];
553 return &t_void;
554}
Bram Moolenaarea696852020-11-09 18:31:39 +0100555// for map(): returns first argument but item type may differ
556 static type_T *
557ret_first_cont(int argcount UNUSED, type_T **argtypes)
558{
559 if (argtypes[0]->tt_type == VAR_LIST)
560 return &t_list_any;
561 if (argtypes[0]->tt_type == VAR_DICT)
562 return &t_dict_any;
563 if (argtypes[0]->tt_type == VAR_BLOB)
564 return argtypes[0];
565 return &t_any;
566}
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200567
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200568/*
569 * Used for getqflist(): returns list if there is no argument, dict if there is
570 * one.
571 */
572 static type_T *
573ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
574{
575 if (argcount > 0)
576 return &t_dict_any;
577 return &t_list_dict_any;
578}
579
580/*
581 * Used for getloclist(): returns list if there is one argument, dict if there
582 * are two.
583 */
584 static type_T *
585ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
586{
587 if (argcount > 1)
588 return &t_dict_any;
589 return &t_list_dict_any;
590}
591
Bram Moolenaar846178a2020-07-05 17:04:13 +0200592 static type_T *
593ret_argv(int argcount, type_T **argtypes UNUSED)
594{
595 // argv() returns list of strings
596 if (argcount == 0)
597 return &t_list_string;
598
599 // argv(0) returns a string, but argv(-1] returns a list
600 return &t_any;
601}
602
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200603 static type_T *
604ret_remove(int argcount UNUSED, type_T **argtypes)
605{
Bram Moolenaar5e654232020-09-16 15:22:00 +0200606 if (argtypes != NULL)
607 {
608 if (argtypes[0]->tt_type == VAR_LIST
609 || argtypes[0]->tt_type == VAR_DICT)
610 return argtypes[0]->tt_member;
611 if (argtypes[0]->tt_type == VAR_BLOB)
612 return &t_number;
613 }
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200614 return &t_any;
615}
616
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200617 static type_T *
618ret_getreg(int argcount, type_T **argtypes UNUSED)
619{
620 // Assume that if the third argument is passed it's non-zero
621 if (argcount == 3)
622 return &t_list_string;
623 return &t_string;
624}
625
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200626 static type_T *
627ret_maparg(int argcount, type_T **argtypes UNUSED)
628{
629 // Assume that if the fourth argument is passed it's non-zero
630 if (argcount == 4)
631 return &t_dict_any;
632 return &t_string;
633}
634
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100635static type_T *ret_f_function(int argcount, type_T **argtypes);
636
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637/*
638 * Array with names and number of arguments of all internal functions
639 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
640 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200641typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200642{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200643 char *f_name; // function name
644 char f_min_argc; // minimal number of arguments
645 char f_max_argc; // maximal number of arguments
646 char f_argtype; // for method: FEARG_ values
Bram Moolenaar94738d82020-10-21 14:25:07 +0200647 argcheck_T *f_argcheck; // list of functions to check argument types
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100648 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
649 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200650 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200651 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200652} funcentry_T;
653
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200654// values for f_argtype; zero means it cannot be used as a method
655#define FEARG_1 1 // base is the first argument
656#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200657#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200658#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200659#define FEARG_LAST 9 // base is the last argument
660
Bram Moolenaar15c47602020-03-26 22:16:48 +0100661#ifdef FEAT_FLOAT
662# define FLOAT_FUNC(name) name
663#else
664# define FLOAT_FUNC(name) NULL
665#endif
666#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
667# define MATH_FUNC(name) name
668#else
669# define MATH_FUNC(name) NULL
670#endif
671#ifdef FEAT_TIMERS
672# define TIMER_FUNC(name) name
673#else
674# define TIMER_FUNC(name) NULL
675#endif
676#ifdef FEAT_JOB_CHANNEL
677# define JOB_FUNC(name) name
678#else
679# define JOB_FUNC(name) NULL
680#endif
681#ifdef FEAT_PROP_POPUP
682# define PROP_FUNC(name) name
683#else
684# define PROP_FUNC(name) NULL
685#endif
686#ifdef FEAT_SIGNS
687# define SIGN_FUNC(name) name
688#else
689# define SIGN_FUNC(name) NULL
690#endif
691#ifdef FEAT_SOUND
692# define SOUND_FUNC(name) name
693#else
694# define SOUND_FUNC(name) NULL
695#endif
696#ifdef FEAT_TERMINAL
697# define TERM_FUNC(name) name
698#else
699# define TERM_FUNC(name) NULL
700#endif
701
Bram Moolenaarac92e252019-08-03 21:58:38 +0200702static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200703{
Bram Moolenaar94738d82020-10-21 14:25:07 +0200704 {"abs", 1, 1, FEARG_1, arg1_float_or_nr,
705 ret_any, FLOAT_FUNC(f_abs)},
706 {"acos", 1, 1, FEARG_1, NULL,
707 ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100708 {"add", 2, 2, FEARG_1, NULL /* arg2_listblob_item */,
Bram Moolenaar94738d82020-10-21 14:25:07 +0200709 ret_first_arg, f_add},
710 {"and", 2, 2, FEARG_1, NULL,
711 ret_number, f_and},
712 {"append", 2, 2, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100713 ret_number_bool, f_append},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200714 {"appendbufline", 3, 3, FEARG_3, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100715 ret_number_bool, f_appendbufline},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200716 {"argc", 0, 1, 0, NULL,
717 ret_number, f_argc},
718 {"argidx", 0, 0, 0, NULL,
719 ret_number, f_argidx},
720 {"arglistid", 0, 2, 0, NULL,
721 ret_number, f_arglistid},
722 {"argv", 0, 2, 0, NULL,
723 ret_argv, f_argv},
724 {"asin", 1, 1, FEARG_1, NULL,
725 ret_float, FLOAT_FUNC(f_asin)},
726 {"assert_beeps", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100727 ret_number_bool, f_assert_beeps},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200728 {"assert_equal", 2, 3, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100729 ret_number_bool, f_assert_equal},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200730 {"assert_equalfile", 2, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100731 ret_number_bool, f_assert_equalfile},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200732 {"assert_exception", 1, 2, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100733 ret_number_bool, f_assert_exception},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200734 {"assert_fails", 1, 5, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100735 ret_number_bool, f_assert_fails},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200736 {"assert_false", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100737 ret_number_bool, f_assert_false},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200738 {"assert_inrange", 3, 4, FEARG_3, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100739 ret_number_bool, f_assert_inrange},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200740 {"assert_match", 2, 3, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100741 ret_number_bool, f_assert_match},
Bram Moolenaar5b8cabf2021-04-02 18:55:57 +0200742 {"assert_nobeep", 1, 2, FEARG_1, NULL,
743 ret_number_bool, f_assert_nobeep},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200744 {"assert_notequal", 2, 3, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100745 ret_number_bool, f_assert_notequal},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200746 {"assert_notmatch", 2, 3, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100747 ret_number_bool, f_assert_notmatch},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200748 {"assert_report", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100749 ret_number_bool, f_assert_report},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200750 {"assert_true", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100751 ret_number_bool, f_assert_true},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200752 {"atan", 1, 1, FEARG_1, NULL,
753 ret_float, FLOAT_FUNC(f_atan)},
754 {"atan2", 2, 2, FEARG_1, NULL,
755 ret_float, FLOAT_FUNC(f_atan2)},
756 {"balloon_gettext", 0, 0, 0, NULL,
757 ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100758#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100759 f_balloon_gettext
760#else
761 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100762#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100763 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200764 {"balloon_show", 1, 1, FEARG_1, NULL,
765 ret_void,
Bram Moolenaar15c47602020-03-26 22:16:48 +0100766#ifdef FEAT_BEVAL
767 f_balloon_show
768#else
769 NULL
770#endif
771 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200772 {"balloon_split", 1, 1, FEARG_1, NULL,
773 ret_list_string,
Bram Moolenaar15c47602020-03-26 22:16:48 +0100774#if defined(FEAT_BEVAL_TERM)
775 f_balloon_split
776#else
777 NULL
778#endif
779 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200780 {"browse", 4, 4, 0, NULL,
781 ret_string, f_browse},
782 {"browsedir", 2, 2, 0, NULL,
783 ret_string, f_browsedir},
784 {"bufadd", 1, 1, FEARG_1, NULL,
785 ret_number, f_bufadd},
786 {"bufexists", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100787 ret_number_bool, f_bufexists},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +0200788 {"buffer_exists", 1, 1, FEARG_1, NULL, // obsolete
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100789 ret_number_bool, f_bufexists},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +0200790 {"buffer_name", 0, 1, FEARG_1, NULL, // obsolete
791 ret_string, f_bufname},
792 {"buffer_number", 0, 1, FEARG_1, NULL, // obsolete
793 ret_number, f_bufnr},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200794 {"buflisted", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100795 ret_number_bool, f_buflisted},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200796 {"bufload", 1, 1, FEARG_1, NULL,
797 ret_void, f_bufload},
798 {"bufloaded", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100799 ret_number_bool, f_bufloaded},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200800 {"bufname", 0, 1, FEARG_1, NULL,
801 ret_string, f_bufname},
802 {"bufnr", 0, 2, FEARG_1, NULL,
803 ret_number, f_bufnr},
804 {"bufwinid", 1, 1, FEARG_1, NULL,
805 ret_number, f_bufwinid},
806 {"bufwinnr", 1, 1, FEARG_1, NULL,
807 ret_number, f_bufwinnr},
808 {"byte2line", 1, 1, FEARG_1, NULL,
809 ret_number, f_byte2line},
810 {"byteidx", 2, 2, FEARG_1, NULL,
811 ret_number, f_byteidx},
812 {"byteidxcomp", 2, 2, FEARG_1, NULL,
813 ret_number, f_byteidxcomp},
814 {"call", 2, 3, FEARG_1, NULL,
815 ret_any, f_call},
816 {"ceil", 1, 1, FEARG_1, NULL,
817 ret_float, FLOAT_FUNC(f_ceil)},
818 {"ch_canread", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100819 ret_number_bool, JOB_FUNC(f_ch_canread)},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200820 {"ch_close", 1, 1, FEARG_1, NULL,
821 ret_void, JOB_FUNC(f_ch_close)},
822 {"ch_close_in", 1, 1, FEARG_1, NULL,
823 ret_void, JOB_FUNC(f_ch_close_in)},
824 {"ch_evalexpr", 2, 3, FEARG_1, NULL,
825 ret_any, JOB_FUNC(f_ch_evalexpr)},
826 {"ch_evalraw", 2, 3, FEARG_1, NULL,
827 ret_any, JOB_FUNC(f_ch_evalraw)},
828 {"ch_getbufnr", 2, 2, FEARG_1, NULL,
829 ret_number, JOB_FUNC(f_ch_getbufnr)},
830 {"ch_getjob", 1, 1, FEARG_1, NULL,
831 ret_job, JOB_FUNC(f_ch_getjob)},
832 {"ch_info", 1, 1, FEARG_1, NULL,
833 ret_dict_any, JOB_FUNC(f_ch_info)},
834 {"ch_log", 1, 2, FEARG_1, NULL,
835 ret_void, JOB_FUNC(f_ch_log)},
836 {"ch_logfile", 1, 2, FEARG_1, NULL,
837 ret_void, JOB_FUNC(f_ch_logfile)},
838 {"ch_open", 1, 2, FEARG_1, NULL,
839 ret_channel, JOB_FUNC(f_ch_open)},
840 {"ch_read", 1, 2, FEARG_1, NULL,
841 ret_string, JOB_FUNC(f_ch_read)},
842 {"ch_readblob", 1, 2, FEARG_1, NULL,
843 ret_blob, JOB_FUNC(f_ch_readblob)},
844 {"ch_readraw", 1, 2, FEARG_1, NULL,
845 ret_string, JOB_FUNC(f_ch_readraw)},
846 {"ch_sendexpr", 2, 3, FEARG_1, NULL,
847 ret_void, JOB_FUNC(f_ch_sendexpr)},
848 {"ch_sendraw", 2, 3, FEARG_1, NULL,
849 ret_void, JOB_FUNC(f_ch_sendraw)},
850 {"ch_setoptions", 2, 2, FEARG_1, NULL,
851 ret_void, JOB_FUNC(f_ch_setoptions)},
852 {"ch_status", 1, 2, FEARG_1, NULL,
853 ret_string, JOB_FUNC(f_ch_status)},
854 {"changenr", 0, 0, 0, NULL,
855 ret_number, f_changenr},
856 {"char2nr", 1, 2, FEARG_1, NULL,
857 ret_number, f_char2nr},
858 {"charclass", 1, 1, FEARG_1, NULL,
859 ret_number, f_charclass},
Bram Moolenaar6f02b002021-01-10 20:22:54 +0100860 {"charcol", 1, 1, FEARG_1, NULL,
861 ret_number, f_charcol},
Bram Moolenaar17793ef2020-12-28 12:56:58 +0100862 {"charidx", 2, 3, FEARG_1, NULL,
863 ret_number, f_charidx},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200864 {"chdir", 1, 1, FEARG_1, NULL,
865 ret_string, f_chdir},
866 {"cindent", 1, 1, FEARG_1, NULL,
867 ret_number, f_cindent},
868 {"clearmatches", 0, 1, FEARG_1, NULL,
869 ret_void, f_clearmatches},
870 {"col", 1, 1, FEARG_1, NULL,
871 ret_number, f_col},
872 {"complete", 2, 2, FEARG_2, NULL,
873 ret_void, f_complete},
874 {"complete_add", 1, 1, FEARG_1, NULL,
875 ret_number, f_complete_add},
876 {"complete_check", 0, 0, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100877 ret_number_bool, f_complete_check},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200878 {"complete_info", 0, 1, FEARG_1, NULL,
879 ret_dict_any, f_complete_info},
880 {"confirm", 1, 4, FEARG_1, NULL,
881 ret_number, f_confirm},
882 {"copy", 1, 1, FEARG_1, NULL,
883 ret_first_arg, f_copy},
884 {"cos", 1, 1, FEARG_1, NULL,
885 ret_float, FLOAT_FUNC(f_cos)},
886 {"cosh", 1, 1, FEARG_1, NULL,
887 ret_float, FLOAT_FUNC(f_cosh)},
888 {"count", 2, 4, FEARG_1, NULL,
889 ret_number, f_count},
890 {"cscope_connection",0,3, 0, NULL,
891 ret_number, f_cscope_connection},
892 {"cursor", 1, 3, FEARG_1, NULL,
893 ret_number, f_cursor},
894 {"debugbreak", 1, 1, FEARG_1, NULL,
895 ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100896#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100897 f_debugbreak
898#else
899 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200900#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100901 },
Bram Moolenaar94738d82020-10-21 14:25:07 +0200902 {"deepcopy", 1, 2, FEARG_1, NULL,
903 ret_first_arg, f_deepcopy},
904 {"delete", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100905 ret_number_bool, f_delete},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200906 {"deletebufline", 2, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100907 ret_number_bool, f_deletebufline},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200908 {"did_filetype", 0, 0, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100909 ret_number_bool, f_did_filetype},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200910 {"diff_filler", 1, 1, FEARG_1, NULL,
911 ret_number, f_diff_filler},
912 {"diff_hlID", 2, 2, FEARG_1, NULL,
913 ret_number, f_diff_hlID},
914 {"echoraw", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100915 ret_void, f_echoraw},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200916 {"empty", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100917 ret_number_bool, f_empty},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200918 {"environ", 0, 0, 0, NULL,
919 ret_dict_string, f_environ},
920 {"escape", 2, 2, FEARG_1, NULL,
921 ret_string, f_escape},
922 {"eval", 1, 1, FEARG_1, NULL,
923 ret_any, f_eval},
924 {"eventhandler", 0, 0, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100925 ret_number_bool, f_eventhandler},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200926 {"executable", 1, 1, FEARG_1, NULL,
927 ret_number, f_executable},
928 {"execute", 1, 2, FEARG_1, NULL,
929 ret_string, f_execute},
930 {"exepath", 1, 1, FEARG_1, NULL,
931 ret_string, f_exepath},
932 {"exists", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100933 ret_number_bool, f_exists},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200934 {"exp", 1, 1, FEARG_1, NULL,
935 ret_float, FLOAT_FUNC(f_exp)},
936 {"expand", 1, 3, FEARG_1, NULL,
937 ret_any, f_expand},
938 {"expandcmd", 1, 1, FEARG_1, NULL,
939 ret_string, f_expandcmd},
Bram Moolenaarfbcbffe2020-10-31 19:33:38 +0100940 {"extend", 2, 3, FEARG_1, arg23_extend,
Bram Moolenaar94738d82020-10-21 14:25:07 +0200941 ret_first_arg, f_extend},
Bram Moolenaarb0e6b512021-01-12 20:23:40 +0100942 {"extendnew", 2, 3, FEARG_1, arg23_extendnew,
943 ret_first_cont, f_extendnew},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200944 {"feedkeys", 1, 2, FEARG_1, NULL,
945 ret_void, f_feedkeys},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +0200946 {"file_readable", 1, 1, FEARG_1, NULL, // obsolete
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100947 ret_number_bool, f_filereadable},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200948 {"filereadable", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +0100949 ret_number_bool, f_filereadable},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200950 {"filewritable", 1, 1, FEARG_1, NULL,
951 ret_number, f_filewritable},
952 {"filter", 2, 2, FEARG_1, NULL,
953 ret_first_arg, f_filter},
954 {"finddir", 1, 3, FEARG_1, NULL,
955 ret_string, f_finddir},
956 {"findfile", 1, 3, FEARG_1, NULL,
957 ret_string, f_findfile},
958 {"flatten", 1, 2, FEARG_1, NULL,
959 ret_list_any, f_flatten},
Bram Moolenaar3b690062021-02-01 20:14:51 +0100960 {"flattennew", 1, 2, FEARG_1, NULL,
961 ret_list_any, f_flattennew},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200962 {"float2nr", 1, 1, FEARG_1, NULL,
963 ret_number, FLOAT_FUNC(f_float2nr)},
964 {"floor", 1, 1, FEARG_1, NULL,
965 ret_float, FLOAT_FUNC(f_floor)},
966 {"fmod", 2, 2, FEARG_1, NULL,
967 ret_float, FLOAT_FUNC(f_fmod)},
968 {"fnameescape", 1, 1, FEARG_1, NULL,
969 ret_string, f_fnameescape},
970 {"fnamemodify", 2, 2, FEARG_1, NULL,
971 ret_string, f_fnamemodify},
972 {"foldclosed", 1, 1, FEARG_1, NULL,
973 ret_number, f_foldclosed},
974 {"foldclosedend", 1, 1, FEARG_1, NULL,
975 ret_number, f_foldclosedend},
976 {"foldlevel", 1, 1, FEARG_1, NULL,
977 ret_number, f_foldlevel},
978 {"foldtext", 0, 0, 0, NULL,
979 ret_string, f_foldtext},
980 {"foldtextresult", 1, 1, FEARG_1, NULL,
981 ret_string, f_foldtextresult},
982 {"foreground", 0, 0, 0, NULL,
983 ret_void, f_foreground},
Bram Moolenaar038e09e2021-02-06 12:38:51 +0100984 {"fullcommand", 1, 1, FEARG_1, arg1_string,
985 ret_string, f_fullcommand},
Bram Moolenaar94738d82020-10-21 14:25:07 +0200986 {"funcref", 1, 3, FEARG_1, NULL,
987 ret_func_any, f_funcref},
988 {"function", 1, 3, FEARG_1, NULL,
989 ret_f_function, f_function},
990 {"garbagecollect", 0, 1, 0, NULL,
991 ret_void, f_garbagecollect},
992 {"get", 2, 3, FEARG_1, NULL,
993 ret_any, f_get},
994 {"getbufinfo", 0, 1, FEARG_1, NULL,
995 ret_list_dict_any, f_getbufinfo},
996 {"getbufline", 2, 3, FEARG_1, NULL,
997 ret_list_string, f_getbufline},
998 {"getbufvar", 2, 3, FEARG_1, NULL,
999 ret_any, f_getbufvar},
1000 {"getchangelist", 0, 1, FEARG_1, NULL,
1001 ret_list_any, f_getchangelist},
1002 {"getchar", 0, 1, 0, NULL,
1003 ret_number, f_getchar},
1004 {"getcharmod", 0, 0, 0, NULL,
1005 ret_number, f_getcharmod},
Bram Moolenaar6f02b002021-01-10 20:22:54 +01001006 {"getcharpos", 1, 1, FEARG_1, NULL,
1007 ret_list_number, f_getcharpos},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001008 {"getcharsearch", 0, 0, 0, NULL,
1009 ret_dict_any, f_getcharsearch},
1010 {"getcmdline", 0, 0, 0, NULL,
1011 ret_string, f_getcmdline},
1012 {"getcmdpos", 0, 0, 0, NULL,
1013 ret_number, f_getcmdpos},
1014 {"getcmdtype", 0, 0, 0, NULL,
1015 ret_string, f_getcmdtype},
1016 {"getcmdwintype", 0, 0, 0, NULL,
1017 ret_string, f_getcmdwintype},
1018 {"getcompletion", 2, 3, FEARG_1, NULL,
1019 ret_list_string, f_getcompletion},
1020 {"getcurpos", 0, 1, FEARG_1, NULL,
1021 ret_list_number, f_getcurpos},
Bram Moolenaar6f02b002021-01-10 20:22:54 +01001022 {"getcursorcharpos", 0, 1, FEARG_1, NULL,
1023 ret_list_number, f_getcursorcharpos},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001024 {"getcwd", 0, 2, FEARG_1, NULL,
1025 ret_string, f_getcwd},
1026 {"getenv", 1, 1, FEARG_1, NULL,
Bram Moolenaar7ad67d12021-03-10 16:08:26 +01001027 ret_any, f_getenv},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001028 {"getfontname", 0, 1, 0, NULL,
1029 ret_string, f_getfontname},
1030 {"getfperm", 1, 1, FEARG_1, NULL,
1031 ret_string, f_getfperm},
1032 {"getfsize", 1, 1, FEARG_1, NULL,
1033 ret_number, f_getfsize},
1034 {"getftime", 1, 1, FEARG_1, NULL,
1035 ret_number, f_getftime},
1036 {"getftype", 1, 1, FEARG_1, NULL,
1037 ret_string, f_getftype},
1038 {"getimstatus", 0, 0, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001039 ret_number_bool, f_getimstatus},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001040 {"getjumplist", 0, 2, FEARG_1, NULL,
1041 ret_list_any, f_getjumplist},
1042 {"getline", 1, 2, FEARG_1, NULL,
1043 ret_f_getline, f_getline},
1044 {"getloclist", 1, 2, 0, NULL,
1045 ret_list_or_dict_1, f_getloclist},
1046 {"getmarklist", 0, 1, FEARG_1, NULL,
1047 ret_list_dict_any, f_getmarklist},
1048 {"getmatches", 0, 1, 0, NULL,
1049 ret_list_dict_any, f_getmatches},
1050 {"getmousepos", 0, 0, 0, NULL,
1051 ret_dict_number, f_getmousepos},
1052 {"getpid", 0, 0, 0, NULL,
1053 ret_number, f_getpid},
1054 {"getpos", 1, 1, FEARG_1, NULL,
1055 ret_list_number, f_getpos},
1056 {"getqflist", 0, 1, 0, NULL,
1057 ret_list_or_dict_0, f_getqflist},
1058 {"getreg", 0, 3, FEARG_1, NULL,
1059 ret_getreg, f_getreg},
1060 {"getreginfo", 0, 1, FEARG_1, NULL,
1061 ret_dict_any, f_getreginfo},
1062 {"getregtype", 0, 1, FEARG_1, NULL,
1063 ret_string, f_getregtype},
1064 {"gettabinfo", 0, 1, FEARG_1, NULL,
1065 ret_list_dict_any, f_gettabinfo},
1066 {"gettabvar", 2, 3, FEARG_1, NULL,
1067 ret_any, f_gettabvar},
1068 {"gettabwinvar", 3, 4, FEARG_1, NULL,
1069 ret_any, f_gettabwinvar},
1070 {"gettagstack", 0, 1, FEARG_1, NULL,
1071 ret_dict_any, f_gettagstack},
1072 {"gettext", 1, 1, FEARG_1, NULL,
1073 ret_string, f_gettext},
1074 {"getwininfo", 0, 1, FEARG_1, NULL,
1075 ret_list_dict_any, f_getwininfo},
1076 {"getwinpos", 0, 1, FEARG_1, NULL,
1077 ret_list_number, f_getwinpos},
1078 {"getwinposx", 0, 0, 0, NULL,
1079 ret_number, f_getwinposx},
1080 {"getwinposy", 0, 0, 0, NULL,
1081 ret_number, f_getwinposy},
1082 {"getwinvar", 2, 3, FEARG_1, NULL,
1083 ret_any, f_getwinvar},
1084 {"glob", 1, 4, FEARG_1, NULL,
1085 ret_any, f_glob},
1086 {"glob2regpat", 1, 1, FEARG_1, NULL,
1087 ret_string, f_glob2regpat},
1088 {"globpath", 2, 5, FEARG_2, NULL,
1089 ret_any, f_globpath},
1090 {"has", 1, 2, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001091 ret_number_bool, f_has},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001092 {"has_key", 2, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001093 ret_number_bool, f_has_key},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001094 {"haslocaldir", 0, 2, FEARG_1, NULL,
1095 ret_number, f_haslocaldir},
1096 {"hasmapto", 1, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001097 ret_number_bool, f_hasmapto},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +02001098 {"highlightID", 1, 1, FEARG_1, NULL, // obsolete
1099 ret_number, f_hlID},
1100 {"highlight_exists",1, 1, FEARG_1, NULL, // obsolete
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001101 ret_number_bool, f_hlexists},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001102 {"histadd", 2, 2, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001103 ret_number_bool, f_histadd},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001104 {"histdel", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001105 ret_number_bool, f_histdel},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001106 {"histget", 1, 2, FEARG_1, NULL,
1107 ret_string, f_histget},
1108 {"histnr", 1, 1, FEARG_1, NULL,
1109 ret_number, f_histnr},
1110 {"hlID", 1, 1, FEARG_1, NULL,
1111 ret_number, f_hlID},
1112 {"hlexists", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001113 ret_number_bool, f_hlexists},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001114 {"hostname", 0, 0, 0, NULL,
1115 ret_string, f_hostname},
1116 {"iconv", 3, 3, FEARG_1, NULL,
1117 ret_string, f_iconv},
1118 {"indent", 1, 1, FEARG_1, NULL,
1119 ret_number, f_indent},
1120 {"index", 2, 4, FEARG_1, NULL,
1121 ret_number, f_index},
1122 {"input", 1, 3, FEARG_1, NULL,
1123 ret_string, f_input},
1124 {"inputdialog", 1, 3, FEARG_1, NULL,
1125 ret_string, f_inputdialog},
1126 {"inputlist", 1, 1, FEARG_1, NULL,
1127 ret_number, f_inputlist},
1128 {"inputrestore", 0, 0, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001129 ret_number_bool, f_inputrestore},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001130 {"inputsave", 0, 0, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001131 ret_number_bool, f_inputsave},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001132 {"inputsecret", 1, 2, FEARG_1, NULL,
1133 ret_string, f_inputsecret},
Bram Moolenaarca174532020-10-21 16:42:22 +02001134 {"insert", 2, 3, FEARG_1, arg3_insert,
Bram Moolenaar94738d82020-10-21 14:25:07 +02001135 ret_first_arg, f_insert},
1136 {"interrupt", 0, 0, 0, NULL,
1137 ret_void, f_interrupt},
1138 {"invert", 1, 1, FEARG_1, NULL,
1139 ret_number, f_invert},
1140 {"isdirectory", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001141 ret_number_bool, f_isdirectory},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001142 {"isinf", 1, 1, FEARG_1, NULL,
1143 ret_number, MATH_FUNC(f_isinf)},
1144 {"islocked", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001145 ret_number_bool, f_islocked},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001146 {"isnan", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001147 ret_number_bool, MATH_FUNC(f_isnan)},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001148 {"items", 1, 1, FEARG_1, NULL,
1149 ret_list_any, f_items},
1150 {"job_getchannel", 1, 1, FEARG_1, NULL,
1151 ret_channel, JOB_FUNC(f_job_getchannel)},
1152 {"job_info", 0, 1, FEARG_1, NULL,
Bram Moolenaar64ed4d42021-01-12 21:22:31 +01001153 ret_job_info, JOB_FUNC(f_job_info)},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001154 {"job_setoptions", 2, 2, FEARG_1, NULL,
1155 ret_void, JOB_FUNC(f_job_setoptions)},
1156 {"job_start", 1, 2, FEARG_1, NULL,
1157 ret_job, JOB_FUNC(f_job_start)},
1158 {"job_status", 1, 1, FEARG_1, NULL,
1159 ret_string, JOB_FUNC(f_job_status)},
1160 {"job_stop", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001161 ret_number_bool, JOB_FUNC(f_job_stop)},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001162 {"join", 1, 2, FEARG_1, NULL,
1163 ret_string, f_join},
1164 {"js_decode", 1, 1, FEARG_1, NULL,
1165 ret_any, f_js_decode},
1166 {"js_encode", 1, 1, FEARG_1, NULL,
1167 ret_string, f_js_encode},
1168 {"json_decode", 1, 1, FEARG_1, NULL,
1169 ret_any, f_json_decode},
1170 {"json_encode", 1, 1, FEARG_1, NULL,
1171 ret_string, f_json_encode},
1172 {"keys", 1, 1, FEARG_1, NULL,
1173 ret_list_string, f_keys},
Bram Moolenaarb8f519e2020-10-21 14:49:08 +02001174 {"last_buffer_nr", 0, 0, 0, NULL, // obsolete
1175 ret_number, f_last_buffer_nr},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001176 {"len", 1, 1, FEARG_1, NULL,
1177 ret_number, f_len},
1178 {"libcall", 3, 3, FEARG_3, NULL,
1179 ret_string, f_libcall},
1180 {"libcallnr", 3, 3, FEARG_3, NULL,
1181 ret_number, f_libcallnr},
1182 {"line", 1, 2, FEARG_1, NULL,
1183 ret_number, f_line},
1184 {"line2byte", 1, 1, FEARG_1, NULL,
1185 ret_number, f_line2byte},
1186 {"lispindent", 1, 1, FEARG_1, NULL,
1187 ret_number, f_lispindent},
1188 {"list2str", 1, 2, FEARG_1, NULL,
1189 ret_string, f_list2str},
1190 {"listener_add", 1, 2, FEARG_2, NULL,
1191 ret_number, f_listener_add},
1192 {"listener_flush", 0, 1, FEARG_1, NULL,
1193 ret_void, f_listener_flush},
1194 {"listener_remove", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001195 ret_number_bool, f_listener_remove},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001196 {"localtime", 0, 0, 0, NULL,
1197 ret_number, f_localtime},
1198 {"log", 1, 1, FEARG_1, NULL,
1199 ret_float, FLOAT_FUNC(f_log)},
1200 {"log10", 1, 1, FEARG_1, NULL,
1201 ret_float, FLOAT_FUNC(f_log10)},
1202 {"luaeval", 1, 2, FEARG_1, NULL,
1203 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001204#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +01001205 f_luaeval
1206#else
1207 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001208#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001209 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001210 {"map", 2, 2, FEARG_1, NULL,
Bram Moolenaarea696852020-11-09 18:31:39 +01001211 ret_first_cont, f_map},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001212 {"maparg", 1, 4, FEARG_1, NULL,
1213 ret_maparg, f_maparg},
1214 {"mapcheck", 1, 3, FEARG_1, NULL,
1215 ret_string, f_mapcheck},
Bram Moolenaarea696852020-11-09 18:31:39 +01001216 {"mapnew", 2, 2, FEARG_1, NULL,
1217 ret_first_cont, f_mapnew},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001218 {"mapset", 3, 3, FEARG_1, NULL,
1219 ret_void, f_mapset},
1220 {"match", 2, 4, FEARG_1, NULL,
1221 ret_any, f_match},
1222 {"matchadd", 2, 5, FEARG_1, NULL,
1223 ret_number, f_matchadd},
1224 {"matchaddpos", 2, 5, FEARG_1, NULL,
1225 ret_number, f_matchaddpos},
1226 {"matcharg", 1, 1, FEARG_1, NULL,
1227 ret_list_string, f_matcharg},
1228 {"matchdelete", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001229 ret_number_bool, f_matchdelete},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001230 {"matchend", 2, 4, FEARG_1, NULL,
1231 ret_number, f_matchend},
1232 {"matchfuzzy", 2, 3, FEARG_1, NULL,
1233 ret_list_string, f_matchfuzzy},
1234 {"matchfuzzypos", 2, 3, FEARG_1, NULL,
1235 ret_list_any, f_matchfuzzypos},
1236 {"matchlist", 2, 4, FEARG_1, NULL,
1237 ret_list_string, f_matchlist},
1238 {"matchstr", 2, 4, FEARG_1, NULL,
1239 ret_string, f_matchstr},
1240 {"matchstrpos", 2, 4, FEARG_1, NULL,
1241 ret_list_any, f_matchstrpos},
1242 {"max", 1, 1, FEARG_1, NULL,
Bram Moolenaar9ae37052021-01-22 22:31:10 +01001243 ret_number, f_max},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001244 {"menu_info", 1, 2, FEARG_1, NULL,
1245 ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +01001246#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +01001247 f_menu_info
1248#else
1249 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +01001250#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001251 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001252 {"min", 1, 1, FEARG_1, NULL,
Bram Moolenaar9ae37052021-01-22 22:31:10 +01001253 ret_number, f_min},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001254 {"mkdir", 1, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001255 ret_number_bool, f_mkdir},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001256 {"mode", 0, 1, FEARG_1, NULL,
1257 ret_string, f_mode},
1258 {"mzeval", 1, 1, FEARG_1, NULL,
1259 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001260#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +01001261 f_mzeval
1262#else
1263 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001264#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001265 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001266 {"nextnonblank", 1, 1, FEARG_1, NULL,
1267 ret_number, f_nextnonblank},
1268 {"nr2char", 1, 2, FEARG_1, NULL,
1269 ret_string, f_nr2char},
1270 {"or", 2, 2, FEARG_1, NULL,
1271 ret_number, f_or},
1272 {"pathshorten", 1, 2, FEARG_1, NULL,
1273 ret_string, f_pathshorten},
1274 {"perleval", 1, 1, FEARG_1, NULL,
1275 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001276#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +01001277 f_perleval
1278#else
1279 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001280#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001281 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001282 {"popup_atcursor", 2, 2, FEARG_1, NULL,
1283 ret_number, PROP_FUNC(f_popup_atcursor)},
1284 {"popup_beval", 2, 2, FEARG_1, NULL,
1285 ret_number, PROP_FUNC(f_popup_beval)},
1286 {"popup_clear", 0, 1, 0, NULL,
1287 ret_void, PROP_FUNC(f_popup_clear)},
1288 {"popup_close", 1, 2, FEARG_1, NULL,
1289 ret_void, PROP_FUNC(f_popup_close)},
1290 {"popup_create", 2, 2, FEARG_1, NULL,
1291 ret_number, PROP_FUNC(f_popup_create)},
1292 {"popup_dialog", 2, 2, FEARG_1, NULL,
1293 ret_number, PROP_FUNC(f_popup_dialog)},
1294 {"popup_filter_menu", 2, 2, 0, NULL,
1295 ret_bool, PROP_FUNC(f_popup_filter_menu)},
1296 {"popup_filter_yesno", 2, 2, 0, NULL,
1297 ret_bool, PROP_FUNC(f_popup_filter_yesno)},
1298 {"popup_findinfo", 0, 0, 0, NULL,
1299 ret_number, PROP_FUNC(f_popup_findinfo)},
1300 {"popup_findpreview", 0, 0, 0, NULL,
1301 ret_number, PROP_FUNC(f_popup_findpreview)},
1302 {"popup_getoptions", 1, 1, FEARG_1, NULL,
1303 ret_dict_any, PROP_FUNC(f_popup_getoptions)},
1304 {"popup_getpos", 1, 1, FEARG_1, NULL,
1305 ret_dict_any, PROP_FUNC(f_popup_getpos)},
1306 {"popup_hide", 1, 1, FEARG_1, NULL,
1307 ret_void, PROP_FUNC(f_popup_hide)},
1308 {"popup_list", 0, 0, 0, NULL,
1309 ret_list_number, PROP_FUNC(f_popup_list)},
1310 {"popup_locate", 2, 2, 0, NULL,
1311 ret_number, PROP_FUNC(f_popup_locate)},
1312 {"popup_menu", 2, 2, FEARG_1, NULL,
1313 ret_number, PROP_FUNC(f_popup_menu)},
1314 {"popup_move", 2, 2, FEARG_1, NULL,
1315 ret_void, PROP_FUNC(f_popup_move)},
1316 {"popup_notification", 2, 2, FEARG_1, NULL,
1317 ret_number, PROP_FUNC(f_popup_notification)},
1318 {"popup_setoptions", 2, 2, FEARG_1, NULL,
1319 ret_void, PROP_FUNC(f_popup_setoptions)},
1320 {"popup_settext", 2, 2, FEARG_1, NULL,
1321 ret_void, PROP_FUNC(f_popup_settext)},
1322 {"popup_show", 1, 1, FEARG_1, NULL,
1323 ret_void, PROP_FUNC(f_popup_show)},
1324 {"pow", 2, 2, FEARG_1, NULL,
1325 ret_float, FLOAT_FUNC(f_pow)},
1326 {"prevnonblank", 1, 1, FEARG_1, NULL,
1327 ret_number, f_prevnonblank},
1328 {"printf", 1, 19, FEARG_2, NULL,
1329 ret_string, f_printf},
1330 {"prompt_getprompt", 1, 1, FEARG_1, NULL,
1331 ret_string, JOB_FUNC(f_prompt_getprompt)},
1332 {"prompt_setcallback", 2, 2, FEARG_1, NULL,
1333 ret_void, JOB_FUNC(f_prompt_setcallback)},
1334 {"prompt_setinterrupt", 2, 2, FEARG_1, NULL,
1335 ret_void, JOB_FUNC(f_prompt_setinterrupt)},
1336 {"prompt_setprompt", 2, 2, FEARG_1, NULL,
1337 ret_void, JOB_FUNC(f_prompt_setprompt)},
1338 {"prop_add", 3, 3, FEARG_1, NULL,
1339 ret_void, PROP_FUNC(f_prop_add)},
1340 {"prop_clear", 1, 3, FEARG_1, NULL,
1341 ret_void, PROP_FUNC(f_prop_clear)},
1342 {"prop_find", 1, 2, FEARG_1, NULL,
1343 ret_dict_any, PROP_FUNC(f_prop_find)},
1344 {"prop_list", 1, 2, FEARG_1, NULL,
1345 ret_list_dict_any, PROP_FUNC(f_prop_list)},
1346 {"prop_remove", 1, 3, FEARG_1, NULL,
1347 ret_number, PROP_FUNC(f_prop_remove)},
1348 {"prop_type_add", 2, 2, FEARG_1, NULL,
1349 ret_void, PROP_FUNC(f_prop_type_add)},
1350 {"prop_type_change", 2, 2, FEARG_1, NULL,
1351 ret_void, PROP_FUNC(f_prop_type_change)},
1352 {"prop_type_delete", 1, 2, FEARG_1, NULL,
1353 ret_void, PROP_FUNC(f_prop_type_delete)},
1354 {"prop_type_get", 1, 2, FEARG_1, NULL,
1355 ret_dict_any, PROP_FUNC(f_prop_type_get)},
1356 {"prop_type_list", 0, 1, FEARG_1, NULL,
1357 ret_list_string, PROP_FUNC(f_prop_type_list)},
1358 {"pum_getpos", 0, 0, 0, NULL,
1359 ret_dict_number, f_pum_getpos},
1360 {"pumvisible", 0, 0, 0, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001361 ret_number_bool, f_pumvisible},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001362 {"py3eval", 1, 1, FEARG_1, NULL,
1363 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +01001365 f_py3eval
1366#else
1367 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001368#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001369 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001370 {"pyeval", 1, 1, FEARG_1, NULL,
1371 ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001372#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +01001373 f_pyeval
1374#else
1375 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001377 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001378 {"pyxeval", 1, 1, FEARG_1, NULL,
1379 ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001380#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +01001381 f_pyxeval
1382#else
1383 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01001384#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001385 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001386 {"rand", 0, 1, FEARG_1, NULL,
1387 ret_number, f_rand},
1388 {"range", 1, 3, FEARG_1, NULL,
1389 ret_list_number, f_range},
Bram Moolenaarc423ad72021-01-13 20:38:03 +01001390 {"readblob", 1, 1, FEARG_1, NULL,
1391 ret_blob, f_readblob},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001392 {"readdir", 1, 3, FEARG_1, NULL,
1393 ret_list_string, f_readdir},
1394 {"readdirex", 1, 3, FEARG_1, NULL,
1395 ret_list_dict_any, f_readdirex},
1396 {"readfile", 1, 3, FEARG_1, NULL,
Bram Moolenaarc423ad72021-01-13 20:38:03 +01001397 ret_list_string, f_readfile},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001398 {"reduce", 2, 3, FEARG_1, NULL,
1399 ret_any, f_reduce},
1400 {"reg_executing", 0, 0, 0, NULL,
1401 ret_string, f_reg_executing},
1402 {"reg_recording", 0, 0, 0, NULL,
1403 ret_string, f_reg_recording},
1404 {"reltime", 0, 2, FEARG_1, NULL,
1405 ret_list_any, f_reltime},
1406 {"reltimefloat", 1, 1, FEARG_1, NULL,
1407 ret_float, FLOAT_FUNC(f_reltimefloat)},
1408 {"reltimestr", 1, 1, FEARG_1, NULL,
1409 ret_string, f_reltimestr},
1410 {"remote_expr", 2, 4, FEARG_1, NULL,
1411 ret_string, f_remote_expr},
1412 {"remote_foreground", 1, 1, FEARG_1, NULL,
1413 ret_string, f_remote_foreground},
1414 {"remote_peek", 1, 2, FEARG_1, NULL,
1415 ret_number, f_remote_peek},
1416 {"remote_read", 1, 2, FEARG_1, NULL,
1417 ret_string, f_remote_read},
1418 {"remote_send", 2, 3, FEARG_1, NULL,
1419 ret_string, f_remote_send},
1420 {"remote_startserver", 1, 1, FEARG_1, NULL,
1421 ret_void, f_remote_startserver},
1422 {"remove", 2, 3, FEARG_1, NULL,
1423 ret_remove, f_remove},
1424 {"rename", 2, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001425 ret_number_bool, f_rename},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001426 {"repeat", 2, 2, FEARG_1, NULL,
1427 ret_first_arg, f_repeat},
1428 {"resolve", 1, 1, FEARG_1, NULL,
1429 ret_string, f_resolve},
1430 {"reverse", 1, 1, FEARG_1, NULL,
1431 ret_first_arg, f_reverse},
1432 {"round", 1, 1, FEARG_1, NULL,
1433 ret_float, FLOAT_FUNC(f_round)},
1434 {"rubyeval", 1, 1, FEARG_1, NULL,
1435 ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +01001436#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +01001437 f_rubyeval
1438#else
1439 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +01001440#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001441 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001442 {"screenattr", 2, 2, FEARG_1, NULL,
1443 ret_number, f_screenattr},
1444 {"screenchar", 2, 2, FEARG_1, NULL,
1445 ret_number, f_screenchar},
1446 {"screenchars", 2, 2, FEARG_1, NULL,
1447 ret_list_number, f_screenchars},
1448 {"screencol", 0, 0, 0, NULL,
1449 ret_number, f_screencol},
1450 {"screenpos", 3, 3, FEARG_1, NULL,
1451 ret_dict_number, f_screenpos},
1452 {"screenrow", 0, 0, 0, NULL,
1453 ret_number, f_screenrow},
1454 {"screenstring", 2, 2, FEARG_1, NULL,
1455 ret_string, f_screenstring},
1456 {"search", 1, 5, FEARG_1, NULL,
1457 ret_number, f_search},
1458 {"searchcount", 0, 1, FEARG_1, NULL,
1459 ret_dict_any, f_searchcount},
1460 {"searchdecl", 1, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001461 ret_number_bool, f_searchdecl},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001462 {"searchpair", 3, 7, 0, NULL,
1463 ret_number, f_searchpair},
1464 {"searchpairpos", 3, 7, 0, NULL,
1465 ret_list_number, f_searchpairpos},
1466 {"searchpos", 1, 5, FEARG_1, NULL,
1467 ret_list_number, f_searchpos},
1468 {"server2client", 2, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001469 ret_number_bool, f_server2client},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001470 {"serverlist", 0, 0, 0, NULL,
1471 ret_string, f_serverlist},
1472 {"setbufline", 3, 3, FEARG_3, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001473 ret_number_bool, f_setbufline},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001474 {"setbufvar", 3, 3, FEARG_3, NULL,
1475 ret_void, f_setbufvar},
1476 {"setcellwidths", 1, 1, FEARG_1, NULL,
1477 ret_void, f_setcellwidths},
Bram Moolenaar6f02b002021-01-10 20:22:54 +01001478 {"setcharpos", 2, 2, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001479 ret_number_bool, f_setcharpos},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001480 {"setcharsearch", 1, 1, FEARG_1, NULL,
1481 ret_void, f_setcharsearch},
1482 {"setcmdpos", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001483 ret_number_bool, f_setcmdpos},
1484 {"setcursorcharpos", 1, 3, FEARG_1, NULL,
1485 ret_number_bool, f_setcursorcharpos},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001486 {"setenv", 2, 2, FEARG_2, NULL,
1487 ret_void, f_setenv},
1488 {"setfperm", 2, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001489 ret_number_bool, f_setfperm},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001490 {"setline", 2, 2, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001491 ret_number_bool, f_setline},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001492 {"setloclist", 2, 4, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001493 ret_number_bool, f_setloclist},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001494 {"setmatches", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001495 ret_number_bool, f_setmatches},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001496 {"setpos", 2, 2, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001497 ret_number_bool, f_setpos},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001498 {"setqflist", 1, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001499 ret_number_bool, f_setqflist},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001500 {"setreg", 2, 3, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001501 ret_number_bool, f_setreg},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001502 {"settabvar", 3, 3, FEARG_3, NULL,
1503 ret_void, f_settabvar},
1504 {"settabwinvar", 4, 4, FEARG_4, NULL,
1505 ret_void, f_settabwinvar},
1506 {"settagstack", 2, 3, FEARG_2, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001507 ret_number_bool, f_settagstack},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001508 {"setwinvar", 3, 3, FEARG_3, NULL,
1509 ret_void, f_setwinvar},
1510 {"sha256", 1, 1, FEARG_1, NULL,
1511 ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +01001513 f_sha256
1514#else
1515 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001516#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001517 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001518 {"shellescape", 1, 2, FEARG_1, NULL,
1519 ret_string, f_shellescape},
1520 {"shiftwidth", 0, 1, FEARG_1, NULL,
1521 ret_number, f_shiftwidth},
1522 {"sign_define", 1, 2, FEARG_1, NULL,
1523 ret_any, SIGN_FUNC(f_sign_define)},
1524 {"sign_getdefined", 0, 1, FEARG_1, NULL,
1525 ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
1526 {"sign_getplaced", 0, 2, FEARG_1, NULL,
1527 ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
1528 {"sign_jump", 3, 3, FEARG_1, NULL,
1529 ret_number, SIGN_FUNC(f_sign_jump)},
1530 {"sign_place", 4, 5, FEARG_1, NULL,
1531 ret_number, SIGN_FUNC(f_sign_place)},
1532 {"sign_placelist", 1, 1, FEARG_1, NULL,
1533 ret_list_number, SIGN_FUNC(f_sign_placelist)},
1534 {"sign_undefine", 0, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001535 ret_number_bool, SIGN_FUNC(f_sign_undefine)},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001536 {"sign_unplace", 1, 2, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001537 ret_number_bool, SIGN_FUNC(f_sign_unplace)},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001538 {"sign_unplacelist", 1, 2, FEARG_1, NULL,
1539 ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
1540 {"simplify", 1, 1, FEARG_1, NULL,
1541 ret_string, f_simplify},
1542 {"sin", 1, 1, FEARG_1, NULL,
1543 ret_float, FLOAT_FUNC(f_sin)},
1544 {"sinh", 1, 1, FEARG_1, NULL,
1545 ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaar6601b622021-01-13 21:47:15 +01001546 {"slice", 2, 3, FEARG_1, NULL,
1547 ret_first_arg, f_slice},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001548 {"sort", 1, 3, FEARG_1, NULL,
1549 ret_first_arg, f_sort},
1550 {"sound_clear", 0, 0, 0, NULL,
1551 ret_void, SOUND_FUNC(f_sound_clear)},
1552 {"sound_playevent", 1, 2, FEARG_1, NULL,
1553 ret_number, SOUND_FUNC(f_sound_playevent)},
1554 {"sound_playfile", 1, 2, FEARG_1, NULL,
1555 ret_number, SOUND_FUNC(f_sound_playfile)},
1556 {"sound_stop", 1, 1, FEARG_1, NULL,
1557 ret_void, SOUND_FUNC(f_sound_stop)},
1558 {"soundfold", 1, 1, FEARG_1, NULL,
1559 ret_string, f_soundfold},
1560 {"spellbadword", 0, 1, FEARG_1, NULL,
1561 ret_list_string, f_spellbadword},
1562 {"spellsuggest", 1, 3, FEARG_1, NULL,
1563 ret_list_string, f_spellsuggest},
1564 {"split", 1, 3, FEARG_1, NULL,
1565 ret_list_string, f_split},
1566 {"sqrt", 1, 1, FEARG_1, NULL,
1567 ret_float, FLOAT_FUNC(f_sqrt)},
1568 {"srand", 0, 1, FEARG_1, NULL,
1569 ret_list_number, f_srand},
1570 {"state", 0, 1, FEARG_1, NULL,
1571 ret_string, f_state},
Bram Moolenaar80ad3e22021-01-31 20:48:58 +01001572 {"str2float", 1, 1, FEARG_1, arg1_string,
Bram Moolenaar94738d82020-10-21 14:25:07 +02001573 ret_float, FLOAT_FUNC(f_str2float)},
1574 {"str2list", 1, 2, FEARG_1, NULL,
1575 ret_list_number, f_str2list},
Bram Moolenaarf2b26bc2021-01-30 23:05:11 +01001576 {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool,
Bram Moolenaar94738d82020-10-21 14:25:07 +02001577 ret_number, f_str2nr},
Bram Moolenaar70ce8a12021-03-14 19:02:09 +01001578 {"strcharlen", 1, 1, FEARG_1, NULL,
1579 ret_number, f_strcharlen},
Bram Moolenaar02b4d9b2021-03-14 19:46:45 +01001580 {"strcharpart", 2, 4, FEARG_1, NULL,
Bram Moolenaar94738d82020-10-21 14:25:07 +02001581 ret_string, f_strcharpart},
1582 {"strchars", 1, 2, FEARG_1, NULL,
1583 ret_number, f_strchars},
1584 {"strdisplaywidth", 1, 2, FEARG_1, NULL,
1585 ret_number, f_strdisplaywidth},
1586 {"strftime", 1, 2, FEARG_1, NULL,
1587 ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001588#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +01001589 f_strftime
1590#else
1591 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001592#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001593 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001594 {"strgetchar", 2, 2, FEARG_1, NULL,
1595 ret_number, f_strgetchar},
1596 {"stridx", 2, 3, FEARG_1, NULL,
1597 ret_number, f_stridx},
1598 {"string", 1, 1, FEARG_1, NULL,
1599 ret_string, f_string},
1600 {"strlen", 1, 1, FEARG_1, NULL,
1601 ret_number, f_strlen},
1602 {"strpart", 2, 4, FEARG_1, NULL,
1603 ret_string, f_strpart},
1604 {"strptime", 2, 2, FEARG_1, NULL,
1605 ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +01001606#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +01001607 f_strptime
1608#else
1609 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +01001610#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001611 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001612 {"strridx", 2, 3, FEARG_1, NULL,
1613 ret_number, f_strridx},
1614 {"strtrans", 1, 1, FEARG_1, NULL,
1615 ret_string, f_strtrans},
1616 {"strwidth", 1, 1, FEARG_1, NULL,
1617 ret_number, f_strwidth},
1618 {"submatch", 1, 2, FEARG_1, NULL,
1619 ret_string, f_submatch},
1620 {"substitute", 4, 4, FEARG_1, NULL,
1621 ret_string, f_substitute},
1622 {"swapinfo", 1, 1, FEARG_1, NULL,
1623 ret_dict_any, f_swapinfo},
1624 {"swapname", 1, 1, FEARG_1, NULL,
1625 ret_string, f_swapname},
1626 {"synID", 3, 3, 0, NULL,
1627 ret_number, f_synID},
1628 {"synIDattr", 2, 3, FEARG_1, NULL,
1629 ret_string, f_synIDattr},
1630 {"synIDtrans", 1, 1, FEARG_1, NULL,
1631 ret_number, f_synIDtrans},
1632 {"synconcealed", 2, 2, 0, NULL,
1633 ret_list_any, f_synconcealed},
1634 {"synstack", 2, 2, 0, NULL,
1635 ret_list_number, f_synstack},
1636 {"system", 1, 2, FEARG_1, NULL,
1637 ret_string, f_system},
1638 {"systemlist", 1, 2, FEARG_1, NULL,
1639 ret_list_string, f_systemlist},
1640 {"tabpagebuflist", 0, 1, FEARG_1, NULL,
1641 ret_list_number, f_tabpagebuflist},
1642 {"tabpagenr", 0, 1, 0, NULL,
1643 ret_number, f_tabpagenr},
1644 {"tabpagewinnr", 1, 2, FEARG_1, NULL,
1645 ret_number, f_tabpagewinnr},
1646 {"tagfiles", 0, 0, 0, NULL,
1647 ret_list_string, f_tagfiles},
1648 {"taglist", 1, 2, FEARG_1, NULL,
1649 ret_list_dict_any, f_taglist},
1650 {"tan", 1, 1, FEARG_1, NULL,
1651 ret_float, FLOAT_FUNC(f_tan)},
1652 {"tanh", 1, 1, FEARG_1, NULL,
1653 ret_float, FLOAT_FUNC(f_tanh)},
1654 {"tempname", 0, 0, 0, NULL,
1655 ret_string, f_tempname},
1656 {"term_dumpdiff", 2, 3, FEARG_1, NULL,
1657 ret_number, TERM_FUNC(f_term_dumpdiff)},
1658 {"term_dumpload", 1, 2, FEARG_1, NULL,
1659 ret_number, TERM_FUNC(f_term_dumpload)},
1660 {"term_dumpwrite", 2, 3, FEARG_2, NULL,
1661 ret_void, TERM_FUNC(f_term_dumpwrite)},
1662 {"term_getaltscreen", 1, 1, FEARG_1, NULL,
1663 ret_number, TERM_FUNC(f_term_getaltscreen)},
1664 {"term_getansicolors", 1, 1, FEARG_1, NULL,
1665 ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001666#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001667 f_term_getansicolors
1668#else
1669 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001670#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001671 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001672 {"term_getattr", 2, 2, FEARG_1, NULL,
1673 ret_number, TERM_FUNC(f_term_getattr)},
1674 {"term_getcursor", 1, 1, FEARG_1, NULL,
1675 ret_list_any, TERM_FUNC(f_term_getcursor)},
1676 {"term_getjob", 1, 1, FEARG_1, NULL,
1677 ret_job, TERM_FUNC(f_term_getjob)},
1678 {"term_getline", 2, 2, FEARG_1, NULL,
1679 ret_string, TERM_FUNC(f_term_getline)},
1680 {"term_getscrolled", 1, 1, FEARG_1, NULL,
1681 ret_number, TERM_FUNC(f_term_getscrolled)},
1682 {"term_getsize", 1, 1, FEARG_1, NULL,
1683 ret_list_number, TERM_FUNC(f_term_getsize)},
1684 {"term_getstatus", 1, 1, FEARG_1, NULL,
1685 ret_string, TERM_FUNC(f_term_getstatus)},
1686 {"term_gettitle", 1, 1, FEARG_1, NULL,
1687 ret_string, TERM_FUNC(f_term_gettitle)},
1688 {"term_gettty", 1, 2, FEARG_1, NULL,
1689 ret_string, TERM_FUNC(f_term_gettty)},
1690 {"term_list", 0, 0, 0, NULL,
1691 ret_list_number, TERM_FUNC(f_term_list)},
1692 {"term_scrape", 2, 2, FEARG_1, NULL,
1693 ret_list_dict_any, TERM_FUNC(f_term_scrape)},
1694 {"term_sendkeys", 2, 2, FEARG_1, NULL,
1695 ret_void, TERM_FUNC(f_term_sendkeys)},
1696 {"term_setansicolors", 2, 2, FEARG_1, NULL,
1697 ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001698#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001699 f_term_setansicolors
1700#else
1701 NULL
1702#endif
1703 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001704 {"term_setapi", 2, 2, FEARG_1, NULL,
1705 ret_void, TERM_FUNC(f_term_setapi)},
1706 {"term_setkill", 2, 2, FEARG_1, NULL,
1707 ret_void, TERM_FUNC(f_term_setkill)},
1708 {"term_setrestore", 2, 2, FEARG_1, NULL,
1709 ret_void, TERM_FUNC(f_term_setrestore)},
1710 {"term_setsize", 3, 3, FEARG_1, NULL,
1711 ret_void, TERM_FUNC(f_term_setsize)},
1712 {"term_start", 1, 2, FEARG_1, NULL,
1713 ret_number, TERM_FUNC(f_term_start)},
1714 {"term_wait", 1, 2, FEARG_1, NULL,
1715 ret_void, TERM_FUNC(f_term_wait)},
1716 {"terminalprops", 0, 0, 0, NULL,
1717 ret_dict_string, f_terminalprops},
1718 {"test_alloc_fail", 3, 3, FEARG_1, NULL,
1719 ret_void, f_test_alloc_fail},
1720 {"test_autochdir", 0, 0, 0, NULL,
1721 ret_void, f_test_autochdir},
1722 {"test_feedinput", 1, 1, FEARG_1, NULL,
1723 ret_void, f_test_feedinput},
1724 {"test_garbagecollect_now", 0, 0, 0, NULL,
1725 ret_void, f_test_garbagecollect_now},
1726 {"test_garbagecollect_soon", 0, 0, 0, NULL,
1727 ret_void, f_test_garbagecollect_soon},
1728 {"test_getvalue", 1, 1, FEARG_1, NULL,
1729 ret_number, f_test_getvalue},
1730 {"test_ignore_error", 1, 1, FEARG_1, NULL,
1731 ret_void, f_test_ignore_error},
1732 {"test_null_blob", 0, 0, 0, NULL,
1733 ret_blob, f_test_null_blob},
1734 {"test_null_channel", 0, 0, 0, NULL,
1735 ret_channel, JOB_FUNC(f_test_null_channel)},
1736 {"test_null_dict", 0, 0, 0, NULL,
1737 ret_dict_any, f_test_null_dict},
1738 {"test_null_function", 0, 0, 0, NULL,
1739 ret_func_any, f_test_null_function},
1740 {"test_null_job", 0, 0, 0, NULL,
1741 ret_job, JOB_FUNC(f_test_null_job)},
1742 {"test_null_list", 0, 0, 0, NULL,
1743 ret_list_any, f_test_null_list},
1744 {"test_null_partial", 0, 0, 0, NULL,
1745 ret_func_any, f_test_null_partial},
1746 {"test_null_string", 0, 0, 0, NULL,
1747 ret_string, f_test_null_string},
1748 {"test_option_not_set", 1, 1, FEARG_1, NULL,
1749 ret_void, f_test_option_not_set},
1750 {"test_override", 2, 2, FEARG_2, NULL,
1751 ret_void, f_test_override},
1752 {"test_refcount", 1, 1, FEARG_1, NULL,
1753 ret_number, f_test_refcount},
1754 {"test_scrollbar", 3, 3, FEARG_2, NULL,
1755 ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +02001756#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +01001757 f_test_scrollbar
1758#else
1759 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +02001760#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001761 },
Bram Moolenaar94738d82020-10-21 14:25:07 +02001762 {"test_setmouse", 2, 2, 0, NULL,
1763 ret_void, f_test_setmouse},
1764 {"test_settime", 1, 1, FEARG_1, NULL,
1765 ret_void, f_test_settime},
1766 {"test_srand_seed", 0, 1, FEARG_1, NULL,
1767 ret_void, f_test_srand_seed},
1768 {"test_unknown", 0, 0, 0, NULL,
1769 ret_any, f_test_unknown},
1770 {"test_void", 0, 0, 0, NULL,
1771 ret_void, f_test_void},
1772 {"timer_info", 0, 1, FEARG_1, NULL,
1773 ret_list_dict_any, TIMER_FUNC(f_timer_info)},
1774 {"timer_pause", 2, 2, FEARG_1, NULL,
1775 ret_void, TIMER_FUNC(f_timer_pause)},
1776 {"timer_start", 2, 3, FEARG_1, NULL,
1777 ret_number, TIMER_FUNC(f_timer_start)},
1778 {"timer_stop", 1, 1, FEARG_1, NULL,
1779 ret_void, TIMER_FUNC(f_timer_stop)},
1780 {"timer_stopall", 0, 0, 0, NULL,
1781 ret_void, TIMER_FUNC(f_timer_stopall)},
1782 {"tolower", 1, 1, FEARG_1, NULL,
1783 ret_string, f_tolower},
1784 {"toupper", 1, 1, FEARG_1, NULL,
1785 ret_string, f_toupper},
1786 {"tr", 3, 3, FEARG_1, NULL,
1787 ret_string, f_tr},
1788 {"trim", 1, 3, FEARG_1, NULL,
1789 ret_string, f_trim},
1790 {"trunc", 1, 1, FEARG_1, NULL,
1791 ret_float, FLOAT_FUNC(f_trunc)},
1792 {"type", 1, 1, FEARG_1, NULL,
1793 ret_number, f_type},
Bram Moolenaara47e05f2021-01-12 21:49:00 +01001794 {"typename", 1, 1, FEARG_1, NULL,
1795 ret_string, f_typename},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001796 {"undofile", 1, 1, FEARG_1, NULL,
1797 ret_string, f_undofile},
1798 {"undotree", 0, 0, 0, NULL,
1799 ret_dict_any, f_undotree},
1800 {"uniq", 1, 3, FEARG_1, NULL,
1801 ret_list_any, f_uniq},
1802 {"values", 1, 1, FEARG_1, NULL,
1803 ret_list_any, f_values},
1804 {"virtcol", 1, 1, FEARG_1, NULL,
1805 ret_number, f_virtcol},
1806 {"visualmode", 0, 1, 0, NULL,
1807 ret_string, f_visualmode},
1808 {"wildmenumode", 0, 0, 0, NULL,
1809 ret_number, f_wildmenumode},
1810 {"win_execute", 2, 3, FEARG_2, NULL,
1811 ret_string, f_win_execute},
1812 {"win_findbuf", 1, 1, FEARG_1, NULL,
1813 ret_list_number, f_win_findbuf},
1814 {"win_getid", 0, 2, FEARG_1, NULL,
1815 ret_number, f_win_getid},
1816 {"win_gettype", 0, 1, FEARG_1, NULL,
1817 ret_string, f_win_gettype},
1818 {"win_gotoid", 1, 1, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001819 ret_number_bool, f_win_gotoid},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001820 {"win_id2tabwin", 1, 1, FEARG_1, NULL,
1821 ret_list_number, f_win_id2tabwin},
1822 {"win_id2win", 1, 1, FEARG_1, NULL,
1823 ret_number, f_win_id2win},
1824 {"win_screenpos", 1, 1, FEARG_1, NULL,
1825 ret_list_number, f_win_screenpos},
1826 {"win_splitmove", 2, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001827 ret_number_bool, f_win_splitmove},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001828 {"winbufnr", 1, 1, FEARG_1, NULL,
1829 ret_number, f_winbufnr},
1830 {"wincol", 0, 0, 0, NULL,
1831 ret_number, f_wincol},
1832 {"windowsversion", 0, 0, 0, NULL,
1833 ret_string, f_windowsversion},
1834 {"winheight", 1, 1, FEARG_1, NULL,
1835 ret_number, f_winheight},
1836 {"winlayout", 0, 1, FEARG_1, NULL,
1837 ret_list_any, f_winlayout},
1838 {"winline", 0, 0, 0, NULL,
1839 ret_number, f_winline},
1840 {"winnr", 0, 1, FEARG_1, NULL,
1841 ret_number, f_winnr},
1842 {"winrestcmd", 0, 0, 0, NULL,
1843 ret_string, f_winrestcmd},
1844 {"winrestview", 1, 1, FEARG_1, NULL,
1845 ret_void, f_winrestview},
1846 {"winsaveview", 0, 0, 0, NULL,
Bram Moolenaar43b69b32021-01-07 20:23:33 +01001847 ret_dict_number, f_winsaveview},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001848 {"winwidth", 1, 1, FEARG_1, NULL,
1849 ret_number, f_winwidth},
1850 {"wordcount", 0, 0, 0, NULL,
1851 ret_dict_number, f_wordcount},
1852 {"writefile", 2, 3, FEARG_1, NULL,
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01001853 ret_number_bool, f_writefile},
Bram Moolenaar94738d82020-10-21 14:25:07 +02001854 {"xor", 2, 2, FEARG_1, NULL,
1855 ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001856};
1857
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001858/*
1859 * Function given to ExpandGeneric() to obtain the list of internal
1860 * or user defined function names.
1861 */
1862 char_u *
1863get_function_name(expand_T *xp, int idx)
1864{
1865 static int intidx = -1;
1866 char_u *name;
1867
1868 if (idx == 0)
1869 intidx = -1;
1870 if (intidx < 0)
1871 {
1872 name = get_user_func_name(xp, idx);
1873 if (name != NULL)
Bram Moolenaar1bb4de52021-01-13 19:48:46 +01001874 {
1875 if (*name != '<' && STRNCMP("g:", xp->xp_pattern, 2) == 0)
1876 return cat_prefix_varname('g', name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001877 return name;
Bram Moolenaar1bb4de52021-01-13 19:48:46 +01001878 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001879 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001880 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001881 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001882 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001883 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001884 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001885 STRCAT(IObuff, ")");
1886 return IObuff;
1887 }
1888
1889 return NULL;
1890}
1891
1892/*
1893 * Function given to ExpandGeneric() to obtain the list of internal or
1894 * user defined variable or function names.
1895 */
1896 char_u *
1897get_expr_name(expand_T *xp, int idx)
1898{
1899 static int intidx = -1;
1900 char_u *name;
1901
1902 if (idx == 0)
1903 intidx = -1;
1904 if (intidx < 0)
1905 {
1906 name = get_function_name(xp, idx);
1907 if (name != NULL)
1908 return name;
1909 }
1910 return get_user_var_name(xp, ++intidx);
1911}
1912
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001913/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001914 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001915 * Return index, or -1 if not found or "implemented" is TRUE and the function
1916 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001917 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001918 static int
1919find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001920{
1921 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001922 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923 int cmp;
1924 int x;
1925
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001926 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001927
1928 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001929 while (first <= last)
1930 {
1931 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001932 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001933 if (cmp < 0)
1934 last = x - 1;
1935 else if (cmp > 0)
1936 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001937 else if (implemented && global_functions[x].f_func == NULL)
1938 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001939 else
1940 return x;
1941 }
1942 return -1;
1943}
1944
Bram Moolenaar15c47602020-03-26 22:16:48 +01001945/*
1946 * Find internal function "name" in table "global_functions".
1947 * Return index, or -1 if not found or the function is not implemented.
1948 */
1949 int
1950find_internal_func(char_u *name)
1951{
1952 return find_internal_func_opt(name, TRUE);
1953}
1954
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001955 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001956has_internal_func(char_u *name)
1957{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001958 return find_internal_func_opt(name, TRUE) >= 0;
1959}
1960
1961 static int
1962has_internal_func_name(char_u *name)
1963{
1964 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001965}
1966
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001967 char *
1968internal_func_name(int idx)
1969{
1970 return global_functions[idx].f_name;
1971}
1972
Bram Moolenaar94738d82020-10-21 14:25:07 +02001973/*
1974 * Check the argument types for builting function "idx".
1975 * Uses the list of types on the type stack: "types".
1976 * Return FAIL and gives an error message when a type is wrong.
1977 */
1978 int
Bram Moolenaar351ead02021-01-16 16:07:01 +01001979internal_func_check_arg_types(
1980 type_T **types,
1981 int idx,
1982 int argcount,
1983 cctx_T *cctx)
Bram Moolenaar94738d82020-10-21 14:25:07 +02001984{
1985 argcheck_T *argchecks = global_functions[idx].f_argcheck;
1986 int i;
1987
1988 if (argchecks != NULL)
1989 {
1990 argcontext_T context;
1991
1992 context.arg_count = argcount;
Bram Moolenaarca174532020-10-21 16:42:22 +02001993 context.arg_types = types;
Bram Moolenaar351ead02021-01-16 16:07:01 +01001994 context.arg_cctx = cctx;
Bram Moolenaar94738d82020-10-21 14:25:07 +02001995 for (i = 0; i < argcount; ++i)
1996 if (argchecks[i] != NULL)
1997 {
1998 context.arg_idx = i;
Bram Moolenaarca174532020-10-21 16:42:22 +02001999 if (argchecks[i](types[i], &context) == FAIL)
Bram Moolenaar94738d82020-10-21 14:25:07 +02002000 return FAIL;
2001 }
2002 }
2003 return OK;
2004}
2005
Bram Moolenaara1224cb2020-10-22 12:31:49 +02002006/*
2007 * Call the "f_retfunc" function to obtain the return type of function "idx".
2008 * "argtypes" is the list of argument types or NULL when there are no
2009 * arguments.
2010 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002011 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002012internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002013{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002014 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002015}
2016
2017/*
Bram Moolenaar75ab91f2021-01-10 22:42:50 +01002018 * Return TRUE if "idx" is for the map() function.
2019 */
2020 int
2021internal_func_is_map(int idx)
2022{
2023 return global_functions[idx].f_func == f_map;
2024}
2025
2026/*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002027 * Check the argument count to use for internal function "idx".
Bram Moolenaar389df252020-07-09 21:20:47 +02002028 * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
2029 * first argument, 2 if method base is second argument, etc. 9 if method base
2030 * is last argument.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002031 */
2032 int
2033check_internal_func(int idx, int argcount)
2034{
2035 int res;
2036 char *name;
2037
2038 if (argcount < global_functions[idx].f_min_argc)
2039 res = FCERR_TOOFEW;
2040 else if (argcount > global_functions[idx].f_max_argc)
2041 res = FCERR_TOOMANY;
2042 else
Bram Moolenaar389df252020-07-09 21:20:47 +02002043 return global_functions[idx].f_argtype;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002044
2045 name = internal_func_name(idx);
2046 if (res == FCERR_TOOMANY)
2047 semsg(_(e_toomanyarg), name);
2048 else
2049 semsg(_(e_toofewarg), name);
Bram Moolenaar389df252020-07-09 21:20:47 +02002050 return -1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002051}
2052
Bram Moolenaarac92e252019-08-03 21:58:38 +02002053 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002054call_internal_func(
2055 char_u *name,
2056 int argcount,
2057 typval_T *argvars,
2058 typval_T *rettv)
2059{
2060 int i;
2061
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002062 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01002064 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02002065 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01002066 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02002067 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01002068 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002069 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02002070 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01002071 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02002072}
2073
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002074 void
2075call_internal_func_by_idx(
2076 int idx,
2077 typval_T *argvars,
2078 typval_T *rettv)
2079{
2080 global_functions[idx].f_func(argvars, rettv);
2081}
2082
Bram Moolenaarac92e252019-08-03 21:58:38 +02002083/*
2084 * Invoke a method for base->method().
2085 */
2086 int
2087call_internal_method(
2088 char_u *name,
2089 int argcount,
2090 typval_T *argvars,
2091 typval_T *rettv,
2092 typval_T *basetv)
2093{
2094 int i;
2095 int fi;
2096 typval_T argv[MAX_FUNC_ARGS + 1];
2097
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002098 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02002099 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01002100 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02002101 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01002102 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002103 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01002104 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002105 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01002106 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02002107
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002108 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02002109 {
2110 // base value goes last
2111 for (i = 0; i < argcount; ++i)
2112 argv[i] = argvars[i];
2113 argv[argcount] = *basetv;
2114 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002115 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02002116 {
2117 // base value goes second
2118 argv[0] = argvars[0];
2119 argv[1] = *basetv;
2120 for (i = 1; i < argcount; ++i)
2121 argv[i + 1] = argvars[i];
2122 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02002123 else if (global_functions[fi].f_argtype == FEARG_3)
2124 {
2125 // base value goes third
2126 argv[0] = argvars[0];
2127 argv[1] = argvars[1];
2128 argv[2] = *basetv;
2129 for (i = 2; i < argcount; ++i)
2130 argv[i + 1] = argvars[i];
2131 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02002132 else if (global_functions[fi].f_argtype == FEARG_4)
2133 {
2134 // base value goes fourth
2135 argv[0] = argvars[0];
2136 argv[1] = argvars[1];
2137 argv[2] = argvars[2];
2138 argv[3] = *basetv;
2139 for (i = 3; i < argcount; ++i)
2140 argv[i + 1] = argvars[i];
2141 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02002142 else
2143 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002144 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02002145 argv[0] = *basetv;
2146 for (i = 0; i < argcount; ++i)
2147 argv[i + 1] = argvars[i];
2148 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02002149 argv[argcount + 1].v_type = VAR_UNKNOWN;
2150
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02002151 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01002152 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153}
2154
2155/*
2156 * Return TRUE for a non-zero Number and a non-empty String.
2157 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02002158 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002159non_zero_arg(typval_T *argvars)
2160{
2161 return ((argvars[0].v_type == VAR_NUMBER
2162 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01002163 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 && argvars[0].vval.v_number == VVAL_TRUE)
2165 || (argvars[0].v_type == VAR_STRING
2166 && argvars[0].vval.v_string != NULL
2167 && *argvars[0].vval.v_string != NUL));
2168}
2169
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002170#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171/*
2172 * Get the float value of "argvars[0]" into "f".
2173 * Returns FAIL when the argument is not a Number or Float.
2174 */
2175 static int
2176get_float_arg(typval_T *argvars, float_T *f)
2177{
2178 if (argvars[0].v_type == VAR_FLOAT)
2179 {
2180 *f = argvars[0].vval.v_float;
2181 return OK;
2182 }
2183 if (argvars[0].v_type == VAR_NUMBER)
2184 {
2185 *f = (float_T)argvars[0].vval.v_number;
2186 return OK;
2187 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002188 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002189 return FAIL;
2190}
2191
2192/*
2193 * "abs(expr)" function
2194 */
2195 static void
2196f_abs(typval_T *argvars, typval_T *rettv)
2197{
2198 if (argvars[0].v_type == VAR_FLOAT)
2199 {
2200 rettv->v_type = VAR_FLOAT;
2201 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
2202 }
2203 else
2204 {
2205 varnumber_T n;
2206 int error = FALSE;
2207
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002208 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002209 if (error)
2210 rettv->vval.v_number = -1;
2211 else if (n > 0)
2212 rettv->vval.v_number = n;
2213 else
2214 rettv->vval.v_number = -n;
2215 }
2216}
2217
2218/*
2219 * "acos()" function
2220 */
2221 static void
2222f_acos(typval_T *argvars, typval_T *rettv)
2223{
2224 float_T f = 0.0;
2225
2226 rettv->v_type = VAR_FLOAT;
2227 if (get_float_arg(argvars, &f) == OK)
2228 rettv->vval.v_float = acos(f);
2229 else
2230 rettv->vval.v_float = 0.0;
2231}
2232#endif
2233
2234/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002235 * "and(expr, expr)" function
2236 */
2237 static void
2238f_and(typval_T *argvars, typval_T *rettv)
2239{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002240 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
2241 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02002242}
2243
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002244#ifdef FEAT_FLOAT
2245/*
2246 * "asin()" function
2247 */
2248 static void
2249f_asin(typval_T *argvars, typval_T *rettv)
2250{
2251 float_T f = 0.0;
2252
2253 rettv->v_type = VAR_FLOAT;
2254 if (get_float_arg(argvars, &f) == OK)
2255 rettv->vval.v_float = asin(f);
2256 else
2257 rettv->vval.v_float = 0.0;
2258}
2259
2260/*
2261 * "atan()" function
2262 */
2263 static void
2264f_atan(typval_T *argvars, typval_T *rettv)
2265{
2266 float_T f = 0.0;
2267
2268 rettv->v_type = VAR_FLOAT;
2269 if (get_float_arg(argvars, &f) == OK)
2270 rettv->vval.v_float = atan(f);
2271 else
2272 rettv->vval.v_float = 0.0;
2273}
2274
2275/*
2276 * "atan2()" function
2277 */
2278 static void
2279f_atan2(typval_T *argvars, typval_T *rettv)
2280{
2281 float_T fx = 0.0, fy = 0.0;
2282
2283 rettv->v_type = VAR_FLOAT;
2284 if (get_float_arg(argvars, &fx) == OK
2285 && get_float_arg(&argvars[1], &fy) == OK)
2286 rettv->vval.v_float = atan2(fx, fy);
2287 else
2288 rettv->vval.v_float = 0.0;
2289}
2290#endif
2291
2292/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01002293 * "balloon_show()" function
2294 */
2295#ifdef FEAT_BEVAL
2296 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002297f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
2298{
2299 rettv->v_type = VAR_STRING;
2300 if (balloonEval != NULL)
2301 {
2302 if (balloonEval->msg == NULL)
2303 rettv->vval.v_string = NULL;
2304 else
2305 rettv->vval.v_string = vim_strsave(balloonEval->msg);
2306 }
2307}
2308
2309 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01002310f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
2311{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01002312 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01002313 {
2314 if (argvars[0].v_type == VAR_LIST
2315# ifdef FEAT_GUI
2316 && !gui.in_use
2317# endif
2318 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002319 {
2320 list_T *l = argvars[0].vval.v_list;
2321
2322 // empty list removes the balloon
2323 post_balloon(balloonEval, NULL,
2324 l == NULL || l->lv_len == 0 ? NULL : l);
2325 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01002326 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002327 {
Bram Moolenaar32105ae2021-03-27 18:59:25 +01002328 char_u *mesg;
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002329
Bram Moolenaar32105ae2021-03-27 18:59:25 +01002330 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
2331 return;
2332
2333 mesg = tv_get_string_chk(&argvars[0]);
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02002334 if (mesg != NULL)
2335 // empty string removes the balloon
2336 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
2337 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01002338 }
2339}
2340
Bram Moolenaar669a8282017-11-19 20:13:05 +01002341# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01002342 static void
2343f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
2344{
2345 if (rettv_list_alloc(rettv) == OK)
2346 {
Bram Moolenaar32105ae2021-03-27 18:59:25 +01002347 char_u *msg;
Bram Moolenaar246fe032017-11-19 19:56:27 +01002348
Bram Moolenaar32105ae2021-03-27 18:59:25 +01002349 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
2350 return;
2351 msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01002352 if (msg != NULL)
2353 {
2354 pumitem_T *array;
2355 int size = split_message(msg, &array);
2356 int i;
2357
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002358 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01002359 for (i = 1; i < size - 1; ++i)
2360 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01002361 while (size > 0)
2362 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01002363 vim_free(array);
2364 }
2365 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01002366}
Bram Moolenaar669a8282017-11-19 20:13:05 +01002367# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01002368#endif
2369
2370/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002371 * Get the buffer from "arg" and give an error and return NULL if it is not
2372 * valid.
2373 */
Bram Moolenaara3347722019-05-11 21:14:24 +02002374 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002375get_buf_arg(typval_T *arg)
2376{
2377 buf_T *buf;
2378
2379 ++emsg_off;
2380 buf = tv_get_buf(arg, FALSE);
2381 --emsg_off;
2382 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002383 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01002384 return buf;
2385}
2386
2387/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002388 * "byte2line(byte)" function
2389 */
2390 static void
2391f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2392{
2393#ifndef FEAT_BYTEOFF
2394 rettv->vval.v_number = -1;
2395#else
2396 long boff = 0;
2397
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002398 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002399 if (boff < 0)
2400 rettv->vval.v_number = -1;
2401 else
2402 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2403 (linenr_T)0, &boff);
2404#endif
2405}
2406
2407 static void
2408byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2409{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002410 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002411 char_u *str;
2412 varnumber_T idx;
2413
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002414 str = tv_get_string_chk(&argvars[0]);
2415 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002416 rettv->vval.v_number = -1;
2417 if (str == NULL || idx < 0)
2418 return;
2419
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002420 t = str;
2421 for ( ; idx > 0; idx--)
2422 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002423 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002424 return;
2425 if (enc_utf8 && comp)
2426 t += utf_ptr2len(t);
2427 else
2428 t += (*mb_ptr2len)(t);
2429 }
2430 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002431}
2432
2433/*
2434 * "byteidx()" function
2435 */
2436 static void
2437f_byteidx(typval_T *argvars, typval_T *rettv)
2438{
2439 byteidx(argvars, rettv, FALSE);
2440}
2441
2442/*
2443 * "byteidxcomp()" function
2444 */
2445 static void
2446f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2447{
2448 byteidx(argvars, rettv, TRUE);
2449}
2450
2451/*
2452 * "call(func, arglist [, dict])" function
2453 */
2454 static void
2455f_call(typval_T *argvars, typval_T *rettv)
2456{
2457 char_u *func;
2458 partial_T *partial = NULL;
2459 dict_T *selfdict = NULL;
2460
2461 if (argvars[1].v_type != VAR_LIST)
2462 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002463 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002464 return;
2465 }
2466 if (argvars[1].vval.v_list == NULL)
2467 return;
2468
2469 if (argvars[0].v_type == VAR_FUNC)
2470 func = argvars[0].vval.v_string;
2471 else if (argvars[0].v_type == VAR_PARTIAL)
2472 {
2473 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002474 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002475 }
2476 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002477 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002478 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002479 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002480
2481 if (argvars[2].v_type != VAR_UNKNOWN)
2482 {
2483 if (argvars[2].v_type != VAR_DICT)
2484 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002485 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002486 return;
2487 }
2488 selfdict = argvars[2].vval.v_dict;
2489 }
2490
2491 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2492}
2493
2494#ifdef FEAT_FLOAT
2495/*
2496 * "ceil({float})" function
2497 */
2498 static void
2499f_ceil(typval_T *argvars, typval_T *rettv)
2500{
2501 float_T f = 0.0;
2502
2503 rettv->v_type = VAR_FLOAT;
2504 if (get_float_arg(argvars, &f) == OK)
2505 rettv->vval.v_float = ceil(f);
2506 else
2507 rettv->vval.v_float = 0.0;
2508}
2509#endif
2510
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511/*
2512 * "changenr()" function
2513 */
2514 static void
2515f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2516{
2517 rettv->vval.v_number = curbuf->b_u_seq_cur;
2518}
2519
2520/*
2521 * "char2nr(string)" function
2522 */
2523 static void
2524f_char2nr(typval_T *argvars, typval_T *rettv)
2525{
Bram Moolenaarc5809432021-03-27 21:23:30 +01002526 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
2527 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528 if (has_mbyte)
2529 {
2530 int utf8 = 0;
2531
2532 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar24f77502020-09-04 19:50:57 +02002533 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002534
2535 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002536 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002538 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002539 }
2540 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002541 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002542}
2543
Bram Moolenaar17793ef2020-12-28 12:56:58 +01002544/*
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002545 * Get the current cursor column and store it in 'rettv'. If 'charcol' is TRUE,
2546 * returns the character index of the column. Otherwise, returns the byte index
2547 * of the column.
2548 */
2549 static void
2550get_col(typval_T *argvars, typval_T *rettv, int charcol)
2551{
2552 colnr_T col = 0;
2553 pos_T *fp;
2554 int fnum = curbuf->b_fnum;
2555
2556 fp = var2fpos(&argvars[0], FALSE, &fnum, charcol);
2557 if (fp != NULL && fnum == curbuf->b_fnum)
2558 {
2559 if (fp->col == MAXCOL)
2560 {
2561 // '> can be MAXCOL, get the length of the line then
2562 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2563 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2564 else
2565 col = MAXCOL;
2566 }
2567 else
2568 {
2569 col = fp->col + 1;
2570 // col(".") when the cursor is on the NUL at the end of the line
2571 // because of "coladd" can be seen as an extra column.
2572 if (virtual_active() && fp == &curwin->w_cursor)
2573 {
2574 char_u *p = ml_get_cursor();
2575
2576 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2577 curwin->w_virtcol - curwin->w_cursor.coladd))
2578 {
2579 int l;
2580
2581 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2582 col += l;
2583 }
2584 }
2585 }
2586 }
2587 rettv->vval.v_number = col;
2588}
2589
2590/*
2591 * "charcol()" function
2592 */
2593 static void
2594f_charcol(typval_T *argvars, typval_T *rettv)
2595{
2596 get_col(argvars, rettv, TRUE);
2597}
2598
2599/*
Bram Moolenaar17793ef2020-12-28 12:56:58 +01002600 * "charidx()" function
2601 */
2602 static void
2603f_charidx(typval_T *argvars, typval_T *rettv)
2604{
2605 char_u *str;
2606 varnumber_T idx;
Bram Moolenaar239f8d92021-01-17 13:21:20 +01002607 varnumber_T countcc = FALSE;
Bram Moolenaar17793ef2020-12-28 12:56:58 +01002608 char_u *p;
2609 int len;
2610 int (*ptr2len)(char_u *);
2611
2612 rettv->vval.v_number = -1;
2613
2614 if (argvars[0].v_type != VAR_STRING || argvars[1].v_type != VAR_NUMBER
2615 || (argvars[2].v_type != VAR_UNKNOWN
2616 && argvars[2].v_type != VAR_NUMBER))
2617 {
2618 emsg(_(e_invarg));
2619 return;
2620 }
2621
2622 str = tv_get_string_chk(&argvars[0]);
2623 idx = tv_get_number_chk(&argvars[1], NULL);
2624 if (str == NULL || idx < 0)
2625 return;
2626
2627 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar239f8d92021-01-17 13:21:20 +01002628 countcc = tv_get_bool(&argvars[2]);
Bram Moolenaar17793ef2020-12-28 12:56:58 +01002629 if (countcc < 0 || countcc > 1)
2630 {
2631 semsg(_(e_using_number_as_bool_nr), countcc);
2632 return;
2633 }
2634
2635 if (enc_utf8 && countcc)
2636 ptr2len = utf_ptr2len;
2637 else
2638 ptr2len = mb_ptr2len;
2639
2640 for (p = str, len = 0; p <= str + idx; len++)
2641 {
2642 if (*p == NUL)
2643 return;
2644 p += ptr2len(p);
2645 }
2646
2647 rettv->vval.v_number = len > 0 ? len - 1 : 0;
2648}
2649
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002650 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002651get_optional_window(typval_T *argvars, int idx)
2652{
2653 win_T *win = curwin;
2654
2655 if (argvars[idx].v_type != VAR_UNKNOWN)
2656 {
2657 win = find_win_by_nr_or_id(&argvars[idx]);
2658 if (win == NULL)
2659 {
2660 emsg(_(e_invalwindow));
2661 return NULL;
2662 }
2663 }
2664 return win;
2665}
2666
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002667/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002668 * "col(string)" function
2669 */
2670 static void
2671f_col(typval_T *argvars, typval_T *rettv)
2672{
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002673 get_col(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002674}
2675
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002676/*
2677 * "confirm(message, buttons[, default [, type]])" function
2678 */
2679 static void
2680f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2681{
2682#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2683 char_u *message;
2684 char_u *buttons = NULL;
2685 char_u buf[NUMBUFLEN];
2686 char_u buf2[NUMBUFLEN];
2687 int def = 1;
2688 int type = VIM_GENERIC;
2689 char_u *typestr;
2690 int error = FALSE;
2691
Bram Moolenaarc5809432021-03-27 21:23:30 +01002692 if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
2693 return;
2694
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002695 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002696 if (message == NULL)
2697 error = TRUE;
2698 if (argvars[1].v_type != VAR_UNKNOWN)
2699 {
Bram Moolenaarc5809432021-03-27 21:23:30 +01002700 if (in_vim9script() && check_for_string_arg(argvars, 1) == FAIL)
2701 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002702 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703 if (buttons == NULL)
2704 error = TRUE;
2705 if (argvars[2].v_type != VAR_UNKNOWN)
2706 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002707 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002708 if (argvars[3].v_type != VAR_UNKNOWN)
2709 {
Bram Moolenaarc5809432021-03-27 21:23:30 +01002710 if (in_vim9script() && check_for_string_arg(argvars, 3) == FAIL)
2711 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002712 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 if (typestr == NULL)
2714 error = TRUE;
2715 else
2716 {
2717 switch (TOUPPER_ASC(*typestr))
2718 {
2719 case 'E': type = VIM_ERROR; break;
2720 case 'Q': type = VIM_QUESTION; break;
2721 case 'I': type = VIM_INFO; break;
2722 case 'W': type = VIM_WARNING; break;
2723 case 'G': type = VIM_GENERIC; break;
2724 }
2725 }
2726 }
2727 }
2728 }
2729
2730 if (buttons == NULL || *buttons == NUL)
2731 buttons = (char_u *)_("&Ok");
2732
2733 if (!error)
2734 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2735 def, NULL, FALSE);
2736#endif
2737}
2738
2739/*
2740 * "copy()" function
2741 */
2742 static void
2743f_copy(typval_T *argvars, typval_T *rettv)
2744{
2745 item_copy(&argvars[0], rettv, FALSE, 0);
2746}
2747
2748#ifdef FEAT_FLOAT
2749/*
2750 * "cos()" function
2751 */
2752 static void
2753f_cos(typval_T *argvars, typval_T *rettv)
2754{
2755 float_T f = 0.0;
2756
2757 rettv->v_type = VAR_FLOAT;
2758 if (get_float_arg(argvars, &f) == OK)
2759 rettv->vval.v_float = cos(f);
2760 else
2761 rettv->vval.v_float = 0.0;
2762}
2763
2764/*
2765 * "cosh()" function
2766 */
2767 static void
2768f_cosh(typval_T *argvars, typval_T *rettv)
2769{
2770 float_T f = 0.0;
2771
2772 rettv->v_type = VAR_FLOAT;
2773 if (get_float_arg(argvars, &f) == OK)
2774 rettv->vval.v_float = cosh(f);
2775 else
2776 rettv->vval.v_float = 0.0;
2777}
2778#endif
2779
2780/*
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002781 * Set the cursor position.
2782 * If 'charcol' is TRUE, then use the column number as a character offet.
2783 * Otherwise use the column number as a byte offset.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002784 */
2785 static void
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002786set_cursorpos(typval_T *argvars, typval_T *rettv, int charcol)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787{
2788 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002789 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002790 int set_curswant = TRUE;
2791
2792 rettv->vval.v_number = -1;
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002793 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002794 {
2795 pos_T pos;
2796 colnr_T curswant = -1;
2797
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002798 if (list2fpos(argvars, &pos, NULL, &curswant, charcol) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002799 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002800 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002801 return;
2802 }
2803 line = pos.lnum;
2804 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002805 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002806 if (curswant >= 0)
2807 {
2808 curwin->w_curswant = curswant - 1;
2809 set_curswant = FALSE;
2810 }
2811 }
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002812 else if ((argvars[0].v_type == VAR_NUMBER ||
2813 argvars[0].v_type == VAR_STRING)
Bram Moolenaar9ebcf232021-01-16 16:52:49 +01002814 && (argvars[1].v_type == VAR_NUMBER ||
2815 argvars[1].v_type == VAR_STRING))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002816 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002817 line = tv_get_lnum(argvars);
Bram Moolenaar9a963372020-12-21 21:58:46 +01002818 if (line < 0)
2819 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002820 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002821 if (charcol)
Bram Moolenaar91458462021-01-13 20:08:38 +01002822 col = buf_charidx_to_byteidx(curbuf, line, col) + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002823 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002824 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002825 }
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002826 else
2827 {
2828 emsg(_(e_invarg));
2829 return;
2830 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002831 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002832 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002833 if (line > 0)
2834 curwin->w_cursor.lnum = line;
2835 if (col > 0)
2836 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002837 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002838
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002839 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002841 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002842 if (has_mbyte)
2843 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002844
2845 curwin->w_set_curswant = set_curswant;
2846 rettv->vval.v_number = 0;
2847}
2848
Bram Moolenaar6f02b002021-01-10 20:22:54 +01002849/*
2850 * "cursor(lnum, col)" function, or
2851 * "cursor(list)"
2852 *
2853 * Moves the cursor to the specified line and column.
2854 * Returns 0 when the position could be set, -1 otherwise.
2855 */
2856 static void
2857f_cursor(typval_T *argvars, typval_T *rettv)
2858{
2859 set_cursorpos(argvars, rettv, FALSE);
2860}
2861
Bram Moolenaar4f974752019-02-17 17:44:42 +01002862#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002863/*
2864 * "debugbreak()" function
2865 */
2866 static void
2867f_debugbreak(typval_T *argvars, typval_T *rettv)
2868{
2869 int pid;
2870
2871 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002872 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002873 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002874 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002875 else
2876 {
2877 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2878
2879 if (hProcess != NULL)
2880 {
2881 DebugBreakProcess(hProcess);
2882 CloseHandle(hProcess);
2883 rettv->vval.v_number = OK;
2884 }
2885 }
2886}
2887#endif
2888
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002889/*
2890 * "deepcopy()" function
2891 */
2892 static void
2893f_deepcopy(typval_T *argvars, typval_T *rettv)
2894{
Bram Moolenaar239f8d92021-01-17 13:21:20 +01002895 varnumber_T noref = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002896 int copyID;
2897
2898 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar239f8d92021-01-17 13:21:20 +01002899 noref = tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002900 if (noref < 0 || noref > 1)
Bram Moolenaarbade44e2020-09-26 22:39:24 +02002901 semsg(_(e_using_number_as_bool_nr), noref);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002902 else
2903 {
2904 copyID = get_copyID();
2905 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2906 }
2907}
2908
2909/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002910 * "did_filetype()" function
2911 */
2912 static void
2913f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2914{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002915 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002916}
2917
2918/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01002919 * "echoraw({expr})" function
2920 */
2921 static void
2922f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
2923{
2924 char_u *str = tv_get_string_chk(&argvars[0]);
2925
2926 if (str != NULL && *str != NUL)
2927 {
2928 out_str(str);
2929 out_flush();
2930 }
2931}
2932
2933/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002934 * "empty({expr})" function
2935 */
2936 static void
2937f_empty(typval_T *argvars, typval_T *rettv)
2938{
2939 int n = FALSE;
2940
2941 switch (argvars[0].v_type)
2942 {
2943 case VAR_STRING:
2944 case VAR_FUNC:
2945 n = argvars[0].vval.v_string == NULL
2946 || *argvars[0].vval.v_string == NUL;
2947 break;
2948 case VAR_PARTIAL:
2949 n = FALSE;
2950 break;
2951 case VAR_NUMBER:
2952 n = argvars[0].vval.v_number == 0;
2953 break;
2954 case VAR_FLOAT:
2955#ifdef FEAT_FLOAT
2956 n = argvars[0].vval.v_float == 0.0;
2957 break;
2958#endif
2959 case VAR_LIST:
2960 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002961 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002962 break;
2963 case VAR_DICT:
2964 n = argvars[0].vval.v_dict == NULL
2965 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2966 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01002967 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002968 case VAR_SPECIAL:
2969 n = argvars[0].vval.v_number != VVAL_TRUE;
2970 break;
2971
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002972 case VAR_BLOB:
2973 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002974 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2975 break;
2976
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002977 case VAR_JOB:
2978#ifdef FEAT_JOB_CHANNEL
2979 n = argvars[0].vval.v_job == NULL
2980 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2981 break;
2982#endif
2983 case VAR_CHANNEL:
2984#ifdef FEAT_JOB_CHANNEL
2985 n = argvars[0].vval.v_channel == NULL
2986 || !channel_is_open(argvars[0].vval.v_channel);
2987 break;
2988#endif
2989 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002990 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002991 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01002992 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002993 n = TRUE;
2994 break;
2995 }
2996
2997 rettv->vval.v_number = n;
2998}
2999
3000/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003001 * "environ()" function
3002 */
3003 static void
3004f_environ(typval_T *argvars UNUSED, typval_T *rettv)
3005{
3006#if !defined(AMIGA)
3007 int i = 0;
3008 char_u *entry, *value;
3009# ifdef MSWIN
3010 extern wchar_t **_wenviron;
3011# else
3012 extern char **environ;
3013# endif
3014
3015 if (rettv_dict_alloc(rettv) != OK)
3016 return;
3017
3018# ifdef MSWIN
3019 if (*_wenviron == NULL)
3020 return;
3021# else
3022 if (*environ == NULL)
3023 return;
3024# endif
3025
3026 for (i = 0; ; ++i)
3027 {
3028# ifdef MSWIN
3029 short_u *p;
3030
3031 if ((p = (short_u *)_wenviron[i]) == NULL)
3032 return;
3033 entry = utf16_to_enc(p, NULL);
3034# else
3035 if ((entry = (char_u *)environ[i]) == NULL)
3036 return;
3037 entry = vim_strsave(entry);
3038# endif
3039 if (entry == NULL) // out of memory
3040 return;
3041 if ((value = vim_strchr(entry, '=')) == NULL)
3042 {
3043 vim_free(entry);
3044 continue;
3045 }
3046 *value++ = NUL;
3047 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
3048 vim_free(entry);
3049 }
3050#endif
3051}
3052
3053/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003054 * "escape({string}, {chars})" function
3055 */
3056 static void
3057f_escape(typval_T *argvars, typval_T *rettv)
3058{
3059 char_u buf[NUMBUFLEN];
3060
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003061 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3062 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003063 rettv->v_type = VAR_STRING;
3064}
3065
3066/*
3067 * "eval()" function
3068 */
3069 static void
3070f_eval(typval_T *argvars, typval_T *rettv)
3071{
3072 char_u *s, *p;
3073
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003074 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 if (s != NULL)
3076 s = skipwhite(s);
3077
3078 p = s;
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02003079 if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003080 {
3081 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003082 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083 need_clr_eos = FALSE;
3084 rettv->v_type = VAR_NUMBER;
3085 rettv->vval.v_number = 0;
3086 }
3087 else if (*s != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02003088 semsg(_(e_trailing_arg), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003089}
3090
3091/*
3092 * "eventhandler()" function
3093 */
3094 static void
3095f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3096{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02003097 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003098}
3099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100static garray_T redir_execute_ga;
3101
3102/*
3103 * Append "value[value_len]" to the execute() output.
3104 */
3105 void
3106execute_redir_str(char_u *value, int value_len)
3107{
3108 int len;
3109
3110 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003111 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003112 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003113 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003114 if (ga_grow(&redir_execute_ga, len) == OK)
3115 {
3116 mch_memmove((char *)redir_execute_ga.ga_data
3117 + redir_execute_ga.ga_len, value, len);
3118 redir_execute_ga.ga_len += len;
3119 }
3120}
3121
3122/*
3123 * Get next line from a list.
3124 * Called by do_cmdline() to get the next line.
3125 * Returns allocated string, or NULL for end of function.
3126 */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003127 static char_u *
3128get_list_line(
3129 int c UNUSED,
3130 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02003131 int indent UNUSED,
Bram Moolenaar66250c92020-08-20 15:02:42 +02003132 getline_opt_T options UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003133{
3134 listitem_T **p = (listitem_T **)cookie;
3135 listitem_T *item = *p;
3136 char_u buf[NUMBUFLEN];
3137 char_u *s;
3138
3139 if (item == NULL)
3140 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003141 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003142 *p = item->li_next;
3143 return s == NULL ? NULL : vim_strsave(s);
3144}
3145
3146/*
3147 * "execute()" function
3148 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02003149 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003150execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003151{
3152 char_u *cmd = NULL;
3153 list_T *list = NULL;
3154 int save_msg_silent = msg_silent;
3155 int save_emsg_silent = emsg_silent;
3156 int save_emsg_noredir = emsg_noredir;
3157 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003158 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003159 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003160 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003161 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003162
3163 rettv->vval.v_string = NULL;
3164 rettv->v_type = VAR_STRING;
3165
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003166 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003167 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003168 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003169 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003170 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003171 return;
3172 ++list->lv_refcount;
3173 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01003174 else if (argvars[arg_off].v_type == VAR_JOB
3175 || argvars[arg_off].v_type == VAR_CHANNEL)
3176 {
3177 emsg(_(e_inval_string));
3178 return;
3179 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003180 else
3181 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003182 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003183 if (cmd == NULL)
3184 return;
3185 }
3186
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003187 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003188 {
3189 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003190 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003191
3192 if (s == NULL)
3193 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003194 if (*s == NUL)
3195 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003196 if (STRNCMP(s, "silent", 6) == 0)
3197 ++msg_silent;
3198 if (STRCMP(s, "silent!") == 0)
3199 {
3200 emsg_silent = TRUE;
3201 emsg_noredir = TRUE;
3202 }
3203 }
3204 else
3205 ++msg_silent;
3206
3207 if (redir_execute)
3208 save_ga = redir_execute_ga;
3209 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3210 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003211 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003212 if (!echo_output)
3213 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003214
3215 if (cmd != NULL)
3216 do_cmdline_cmd(cmd);
3217 else
3218 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003219 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003220
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02003221 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003222 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003223 do_cmdline(NULL, get_list_line, (void *)&item,
3224 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3225 --list->lv_refcount;
3226 }
3227
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003228 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01003229 if (ga_grow(&redir_execute_ga, 1) == OK)
3230 {
3231 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3232 rettv->vval.v_string = redir_execute_ga.ga_data;
3233 }
3234 else
3235 {
3236 ga_clear(&redir_execute_ga);
3237 rettv->vval.v_string = NULL;
3238 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003239 msg_silent = save_msg_silent;
3240 emsg_silent = save_emsg_silent;
3241 emsg_noredir = save_emsg_noredir;
3242
3243 redir_execute = save_redir_execute;
3244 if (redir_execute)
3245 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003246 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003247
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003248 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003249 if (echo_output)
3250 // When not working silently: put it in column zero. A following
3251 // "echon" will overwrite the message, unavoidably.
3252 msg_col = 0;
3253 else
3254 // When working silently: Put it back where it was, since nothing
3255 // should have been written.
3256 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257}
3258
3259/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003260 * "execute()" function
3261 */
3262 static void
3263f_execute(typval_T *argvars, typval_T *rettv)
3264{
3265 execute_common(argvars, rettv, 0);
3266}
3267
3268/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003269 * "exists()" function
3270 */
3271 static void
3272f_exists(typval_T *argvars, typval_T *rettv)
3273{
3274 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003275 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003276
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003277 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003278 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003279 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003280 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003281 if (mch_getenv(p + 1) != NULL)
3282 n = TRUE;
3283 else
3284 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003285 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003286 p = expand_env_save(p);
3287 if (p != NULL && *p != '$')
3288 n = TRUE;
3289 vim_free(p);
3290 }
3291 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003292 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003293 {
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02003294 n = (eval_option(&p, NULL, TRUE) == OK);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003295 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003296 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003298 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003300 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01003302 else if (*p == '?') // internal function only
3303 {
3304 n = has_internal_func_name(p + 1);
3305 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003306 else if (*p == ':')
3307 {
3308 n = cmd_exists(p + 1);
3309 }
3310 else if (*p == '#')
3311 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312 if (p[1] == '#')
3313 n = autocmd_supported(p + 2);
3314 else
3315 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003317 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003318 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003319 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003320 }
3321
3322 rettv->vval.v_number = n;
3323}
3324
3325#ifdef FEAT_FLOAT
3326/*
3327 * "exp()" function
3328 */
3329 static void
3330f_exp(typval_T *argvars, typval_T *rettv)
3331{
3332 float_T f = 0.0;
3333
3334 rettv->v_type = VAR_FLOAT;
3335 if (get_float_arg(argvars, &f) == OK)
3336 rettv->vval.v_float = exp(f);
3337 else
3338 rettv->vval.v_float = 0.0;
3339}
3340#endif
3341
3342/*
3343 * "expand()" function
3344 */
3345 static void
3346f_expand(typval_T *argvars, typval_T *rettv)
3347{
3348 char_u *s;
3349 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003350 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003351 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3352 expand_T xpc;
3353 int error = FALSE;
3354 char_u *result;
Bram Moolenaar8f187fc2020-09-26 18:47:11 +02003355#ifdef BACKSLASH_IN_FILENAME
3356 char_u *p_csl_save = p_csl;
3357
3358 // avoid using 'completeslash' here
3359 p_csl = empty_option;
3360#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003361
3362 rettv->v_type = VAR_STRING;
3363 if (argvars[1].v_type != VAR_UNKNOWN
3364 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02003365 && tv_get_bool_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003366 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003367 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003368
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003369 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003370 if (*s == '%' || *s == '#' || *s == '<')
3371 {
3372 ++emsg_off;
3373 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3374 --emsg_off;
3375 if (rettv->v_type == VAR_LIST)
3376 {
3377 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3378 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02003379 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380 }
3381 else
3382 rettv->vval.v_string = result;
3383 }
3384 else
3385 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003386 // When the optional second argument is non-zero, don't remove matches
3387 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003388 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaar551d25e2020-09-02 21:37:56 +02003389 && tv_get_bool_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003390 options |= WILD_KEEP_ALL;
3391 if (!error)
3392 {
3393 ExpandInit(&xpc);
3394 xpc.xp_context = EXPAND_FILES;
3395 if (p_wic)
3396 options += WILD_ICASE;
3397 if (rettv->v_type == VAR_STRING)
3398 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3399 options, WILD_ALL);
3400 else if (rettv_list_alloc(rettv) != FAIL)
3401 {
3402 int i;
3403
3404 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3405 for (i = 0; i < xpc.xp_numfiles; i++)
3406 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3407 ExpandCleanup(&xpc);
3408 }
3409 }
3410 else
3411 rettv->vval.v_string = NULL;
3412 }
Bram Moolenaar8f187fc2020-09-26 18:47:11 +02003413#ifdef BACKSLASH_IN_FILENAME
3414 p_csl = p_csl_save;
3415#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003416}
3417
3418/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003419 * "expandcmd()" function
3420 * Expand all the special characters in a command string.
3421 */
3422 static void
3423f_expandcmd(typval_T *argvars, typval_T *rettv)
3424{
3425 exarg_T eap;
3426 char_u *cmdstr;
3427 char *errormsg = NULL;
3428
3429 rettv->v_type = VAR_STRING;
3430 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3431
3432 memset(&eap, 0, sizeof(eap));
3433 eap.cmd = cmdstr;
3434 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003435 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003436 eap.usefilter = FALSE;
3437 eap.nextcmd = NULL;
3438 eap.cmdidx = CMD_USER;
3439
3440 expand_filename(&eap, &cmdstr, &errormsg);
3441 if (errormsg != NULL && *errormsg != NUL)
3442 emsg(errormsg);
3443
3444 rettv->vval.v_string = cmdstr;
3445}
3446
3447/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003448 * "feedkeys()" function
3449 */
3450 static void
3451f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3452{
3453 int remap = TRUE;
3454 int insert = FALSE;
3455 char_u *keys, *flags;
3456 char_u nbuf[NUMBUFLEN];
3457 int typed = FALSE;
3458 int execute = FALSE;
3459 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003460 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003461 char_u *keys_esc;
3462
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003463 // This is not allowed in the sandbox. If the commands would still be
3464 // executed in the sandbox it would be OK, but it probably happens later,
3465 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003466 if (check_secure())
3467 return;
3468
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003469 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470
3471 if (argvars[1].v_type != VAR_UNKNOWN)
3472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003473 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474 for ( ; *flags != NUL; ++flags)
3475 {
3476 switch (*flags)
3477 {
3478 case 'n': remap = FALSE; break;
3479 case 'm': remap = TRUE; break;
3480 case 't': typed = TRUE; break;
3481 case 'i': insert = TRUE; break;
3482 case 'x': execute = TRUE; break;
3483 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003484 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003485 }
3486 }
3487 }
3488
3489 if (*keys != NUL || execute)
3490 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003491 // Need to escape K_SPECIAL and CSI before putting the string in the
3492 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003493 keys_esc = vim_strsave_escape_csi(keys);
3494 if (keys_esc != NULL)
3495 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003496 if (lowlevel)
3497 {
3498#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01003499 int idx;
3500 int len = (int)STRLEN(keys);
3501
3502 for (idx = 0; idx < len; ++idx)
3503 {
3504 // if a CTRL-C was typed, set got_int, similar to what
3505 // happens in fill_input_buf()
3506 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
3507 got_int = TRUE;
3508 add_to_input_buf(keys + idx, 1);
3509 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003510#else
3511 emsg(_("E980: lowlevel input not supported"));
3512#endif
3513 }
3514 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003515 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003516 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003518 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003519#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003520 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003521#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02003522 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003523 typebuf_was_filled = TRUE;
3524 }
3525 vim_free(keys_esc);
3526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003527 if (execute)
3528 {
3529 int save_msg_scroll = msg_scroll;
3530
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003531 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003532 msg_scroll = FALSE;
3533
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003534 if (!dangerous)
Bram Moolenaar4934ad02020-09-28 22:29:58 +02003535 {
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003536 ++ex_normal_busy;
Bram Moolenaar4934ad02020-09-28 22:29:58 +02003537 ++in_feedkeys;
3538 }
Bram Moolenaar905dd902019-04-07 14:21:47 +02003539 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003540 if (!dangerous)
Bram Moolenaar189832b2020-09-23 12:29:11 +02003541 {
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003542 --ex_normal_busy;
Bram Moolenaar4934ad02020-09-28 22:29:58 +02003543 --in_feedkeys;
Bram Moolenaar189832b2020-09-23 12:29:11 +02003544 }
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003545
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546 msg_scroll |= save_msg_scroll;
3547 }
3548 }
3549 }
3550}
3551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003552#ifdef FEAT_FLOAT
3553/*
3554 * "float2nr({float})" function
3555 */
3556 static void
3557f_float2nr(typval_T *argvars, typval_T *rettv)
3558{
3559 float_T f = 0.0;
3560
3561 if (get_float_arg(argvars, &f) == OK)
3562 {
Bram Moolenaar37184272020-05-23 19:30:05 +02003563 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003564 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02003565 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003566 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003567 else
3568 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569 }
3570}
3571
3572/*
3573 * "floor({float})" function
3574 */
3575 static void
3576f_floor(typval_T *argvars, typval_T *rettv)
3577{
3578 float_T f = 0.0;
3579
3580 rettv->v_type = VAR_FLOAT;
3581 if (get_float_arg(argvars, &f) == OK)
3582 rettv->vval.v_float = floor(f);
3583 else
3584 rettv->vval.v_float = 0.0;
3585}
3586
3587/*
3588 * "fmod()" function
3589 */
3590 static void
3591f_fmod(typval_T *argvars, typval_T *rettv)
3592{
3593 float_T fx = 0.0, fy = 0.0;
3594
3595 rettv->v_type = VAR_FLOAT;
3596 if (get_float_arg(argvars, &fx) == OK
3597 && get_float_arg(&argvars[1], &fy) == OK)
3598 rettv->vval.v_float = fmod(fx, fy);
3599 else
3600 rettv->vval.v_float = 0.0;
3601}
3602#endif
3603
3604/*
3605 * "fnameescape({string})" function
3606 */
3607 static void
3608f_fnameescape(typval_T *argvars, typval_T *rettv)
3609{
3610 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003611 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003612 rettv->v_type = VAR_STRING;
3613}
3614
3615/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003616 * "foreground()" function
3617 */
3618 static void
3619f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3620{
3621#ifdef FEAT_GUI
3622 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003623 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003624 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003625 return;
3626 }
3627#endif
3628#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003629 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003630#endif
3631}
3632
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003633 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003634common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635{
3636 char_u *s;
3637 char_u *name;
3638 int use_string = FALSE;
3639 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003640 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003641 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003642
3643 if (argvars[0].v_type == VAR_FUNC)
3644 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003645 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003646 s = argvars[0].vval.v_string;
3647 }
3648 else if (argvars[0].v_type == VAR_PARTIAL
3649 && argvars[0].vval.v_partial != NULL)
3650 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003651 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003652 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003653 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 }
3655 else
3656 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003657 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003658 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003659 use_string = TRUE;
3660 }
3661
Bram Moolenaar843b8842016-08-21 14:36:15 +02003662 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003663 {
3664 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003665 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar32b3f822021-01-06 21:59:39 +01003666 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF,
3667 NULL, NULL, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003668 if (*name != NUL)
3669 s = NULL;
3670 }
3671
Bram Moolenaar843b8842016-08-21 14:36:15 +02003672 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3673 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003674 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003675 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003676 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003677 ? find_func(trans_name, is_global, NULL) == NULL
3678 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003679 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003680 else
3681 {
3682 int dict_idx = 0;
3683 int arg_idx = 0;
3684 list_T *list = NULL;
3685
3686 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3687 {
3688 char sid_buf[25];
3689 int off = *s == 's' ? 2 : 5;
3690
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003691 // Expand s: and <SID> into <SNR>nr_, so that the function can
3692 // also be called from another script. Using trans_function_name()
3693 // would also work, but some plugins depend on the name being
3694 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003695 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003696 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003697 if (name != NULL)
3698 {
3699 STRCPY(name, sid_buf);
3700 STRCAT(name, s + off);
3701 }
3702 }
3703 else
3704 name = vim_strsave(s);
3705
3706 if (argvars[1].v_type != VAR_UNKNOWN)
3707 {
3708 if (argvars[2].v_type != VAR_UNKNOWN)
3709 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003710 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003711 arg_idx = 1;
3712 dict_idx = 2;
3713 }
3714 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003715 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003716 dict_idx = 1;
3717 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003718 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003719 arg_idx = 1;
3720 if (dict_idx > 0)
3721 {
3722 if (argvars[dict_idx].v_type != VAR_DICT)
3723 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003724 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003725 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003726 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727 }
3728 if (argvars[dict_idx].vval.v_dict == NULL)
3729 dict_idx = 0;
3730 }
3731 if (arg_idx > 0)
3732 {
3733 if (argvars[arg_idx].v_type != VAR_LIST)
3734 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003735 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003736 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003737 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003738 }
3739 list = argvars[arg_idx].vval.v_list;
3740 if (list == NULL || list->lv_len == 0)
3741 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01003742 else if (list->lv_len > MAX_FUNC_ARGS)
3743 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01003744 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01003745 vim_free(name);
3746 goto theend;
3747 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003748 }
3749 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003750 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003751 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003752 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003753
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003754 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003755 if (pt == NULL)
3756 vim_free(name);
3757 else
3758 {
3759 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3760 {
3761 listitem_T *li;
3762 int i = 0;
3763 int arg_len = 0;
3764 int lv_len = 0;
3765
3766 if (arg_pt != NULL)
3767 arg_len = arg_pt->pt_argc;
3768 if (list != NULL)
3769 lv_len = list->lv_len;
3770 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003771 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003772 if (pt->pt_argv == NULL)
3773 {
3774 vim_free(pt);
3775 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003776 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003778 for (i = 0; i < arg_len; i++)
3779 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3780 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003781 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02003782 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003783 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003784 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01003785 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003786 }
3787
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003788 // For "function(dict.func, [], dict)" and "func" is a partial
3789 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003790 if (dict_idx > 0)
3791 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003792 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003793 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3794 ++pt->pt_dict->dv_refcount;
3795 }
3796 else if (arg_pt != NULL)
3797 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003798 // If the dict was bound automatically the result is also
3799 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003800 pt->pt_dict = arg_pt->pt_dict;
3801 pt->pt_auto = arg_pt->pt_auto;
3802 if (pt->pt_dict != NULL)
3803 ++pt->pt_dict->dv_refcount;
3804 }
3805
3806 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003807 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3808 {
3809 pt->pt_func = arg_pt->pt_func;
3810 func_ptr_ref(pt->pt_func);
3811 vim_free(name);
3812 }
3813 else if (is_funcref)
3814 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02003815 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003816 func_ptr_ref(pt->pt_func);
3817 vim_free(name);
3818 }
3819 else
3820 {
3821 pt->pt_name = name;
3822 func_ref(name);
3823 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003824 }
3825 rettv->v_type = VAR_PARTIAL;
3826 rettv->vval.v_partial = pt;
3827 }
3828 else
3829 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003830 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831 rettv->v_type = VAR_FUNC;
3832 rettv->vval.v_string = name;
3833 func_ref(name);
3834 }
3835 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003836theend:
3837 vim_free(trans_name);
3838}
3839
3840/*
3841 * "funcref()" function
3842 */
3843 static void
3844f_funcref(typval_T *argvars, typval_T *rettv)
3845{
3846 common_function(argvars, rettv, TRUE);
3847}
3848
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01003849 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02003850ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01003851{
3852 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
3853 return &t_func_any;
Bram Moolenaar5e654232020-09-16 15:22:00 +02003854 return &t_func_unknown;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01003855}
3856
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003857/*
3858 * "function()" function
3859 */
3860 static void
3861f_function(typval_T *argvars, typval_T *rettv)
3862{
3863 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864}
3865
3866/*
3867 * "garbagecollect()" function
3868 */
3869 static void
3870f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3871{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003872 // This is postponed until we are back at the toplevel, because we may be
3873 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003874 want_garbage_collect = TRUE;
3875
Bram Moolenaar2df47312020-09-05 17:30:44 +02003876 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003877 garbage_collect_at_exit = TRUE;
3878}
3879
3880/*
3881 * "get()" function
3882 */
3883 static void
3884f_get(typval_T *argvars, typval_T *rettv)
3885{
3886 listitem_T *li;
3887 list_T *l;
3888 dictitem_T *di;
3889 dict_T *d;
3890 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003891 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003892
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003893 if (argvars[0].v_type == VAR_BLOB)
3894 {
3895 int error = FALSE;
3896 int idx = tv_get_number_chk(&argvars[1], &error);
3897
3898 if (!error)
3899 {
3900 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003901 if (idx < 0)
3902 idx = blob_len(argvars[0].vval.v_blob) + idx;
3903 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
3904 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003905 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003906 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003907 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003908 tv = rettv;
3909 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003910 }
3911 }
3912 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003913 {
3914 if ((l = argvars[0].vval.v_list) != NULL)
3915 {
3916 int error = FALSE;
3917
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003918 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003919 if (!error && li != NULL)
3920 tv = &li->li_tv;
3921 }
3922 }
3923 else if (argvars[0].v_type == VAR_DICT)
3924 {
3925 if ((d = argvars[0].vval.v_dict) != NULL)
3926 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003927 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003928 if (di != NULL)
3929 tv = &di->di_tv;
3930 }
3931 }
3932 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3933 {
3934 partial_T *pt;
3935 partial_T fref_pt;
3936
3937 if (argvars[0].v_type == VAR_PARTIAL)
3938 pt = argvars[0].vval.v_partial;
3939 else
3940 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02003941 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942 fref_pt.pt_name = argvars[0].vval.v_string;
3943 pt = &fref_pt;
3944 }
3945
3946 if (pt != NULL)
3947 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003948 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003949 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003950
3951 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3952 {
3953 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003954 n = partial_name(pt);
3955 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956 rettv->vval.v_string = NULL;
3957 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003958 {
3959 rettv->vval.v_string = vim_strsave(n);
3960 if (rettv->v_type == VAR_FUNC)
3961 func_ref(rettv->vval.v_string);
3962 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003963 }
3964 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003965 {
3966 what_is_dict = TRUE;
3967 if (pt->pt_dict != NULL)
3968 rettv_dict_set(rettv, pt->pt_dict);
3969 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003970 else if (STRCMP(what, "args") == 0)
3971 {
3972 rettv->v_type = VAR_LIST;
3973 if (rettv_list_alloc(rettv) == OK)
3974 {
3975 int i;
3976
3977 for (i = 0; i < pt->pt_argc; ++i)
3978 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3979 }
3980 }
3981 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003982 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003983
3984 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3985 // third argument
3986 if (!what_is_dict)
3987 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003988 }
3989 }
3990 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003991 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003992
3993 if (tv == NULL)
3994 {
3995 if (argvars[2].v_type != VAR_UNKNOWN)
3996 copy_tv(&argvars[2], rettv);
3997 }
3998 else
3999 copy_tv(tv, rettv);
4000}
4001
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004002/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004003 * "getchangelist()" function
4004 */
4005 static void
4006f_getchangelist(typval_T *argvars, typval_T *rettv)
4007{
4008#ifdef FEAT_JUMPLIST
4009 buf_T *buf;
4010 int i;
4011 list_T *l;
4012 dict_T *d;
4013#endif
4014
4015 if (rettv_list_alloc(rettv) != OK)
4016 return;
4017
4018#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02004019 if (argvars[0].v_type == VAR_UNKNOWN)
4020 buf = curbuf;
4021 else
Bram Moolenaara5d38412020-09-02 21:02:35 +02004022 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004023 if (buf == NULL)
4024 return;
4025
4026 l = list_alloc();
4027 if (l == NULL)
4028 return;
4029
4030 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4031 return;
4032 /*
4033 * The current window change list index tracks only the position in the
4034 * current buffer change list. For other buffers, use the change list
4035 * length as the current index.
4036 */
4037 list_append_number(rettv->vval.v_list,
4038 (varnumber_T)((buf == curwin->w_buffer)
4039 ? curwin->w_changelistidx : buf->b_changelistlen));
4040
4041 for (i = 0; i < buf->b_changelistlen; ++i)
4042 {
4043 if (buf->b_changelist[i].lnum == 0)
4044 continue;
4045 if ((d = dict_alloc()) == NULL)
4046 return;
4047 if (list_append_dict(l, d) == FAIL)
4048 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004049 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4050 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004051 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004052 }
4053#endif
4054}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004055
Bram Moolenaar6f02b002021-01-10 20:22:54 +01004056 static void
4057getpos_both(
4058 typval_T *argvars,
4059 typval_T *rettv,
4060 int getcurpos,
4061 int charcol)
4062{
4063 pos_T *fp = NULL;
4064 pos_T pos;
4065 win_T *wp = curwin;
4066 list_T *l;
4067 int fnum = -1;
4068
4069 if (rettv_list_alloc(rettv) == OK)
4070 {
4071 l = rettv->vval.v_list;
4072 if (getcurpos)
4073 {
4074 if (argvars[0].v_type != VAR_UNKNOWN)
4075 {
4076 wp = find_win_by_nr_or_id(&argvars[0]);
4077 if (wp != NULL)
4078 fp = &wp->w_cursor;
4079 }
4080 else
4081 fp = &curwin->w_cursor;
4082 if (fp != NULL && charcol)
4083 {
4084 pos = *fp;
Bram Moolenaar91458462021-01-13 20:08:38 +01004085 pos.col =
4086 buf_byteidx_to_charidx(wp->w_buffer, pos.lnum, pos.col);
Bram Moolenaar6f02b002021-01-10 20:22:54 +01004087 fp = &pos;
4088 }
4089 }
4090 else
4091 fp = var2fpos(&argvars[0], TRUE, &fnum, charcol);
4092 if (fnum != -1)
4093 list_append_number(l, (varnumber_T)fnum);
4094 else
4095 list_append_number(l, (varnumber_T)0);
4096 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4097 : (varnumber_T)0);
4098 list_append_number(l, (fp != NULL)
4099 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4100 : (varnumber_T)0);
4101 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
4102 (varnumber_T)0);
4103 if (getcurpos)
4104 {
4105 int save_set_curswant = curwin->w_set_curswant;
4106 colnr_T save_curswant = curwin->w_curswant;
4107 colnr_T save_virtcol = curwin->w_virtcol;
4108
4109 if (wp == curwin)
4110 update_curswant();
4111 list_append_number(l, wp == NULL ? 0 : wp->w_curswant == MAXCOL
4112 ? (varnumber_T)MAXCOL : (varnumber_T)wp->w_curswant + 1);
4113
4114 // Do not change "curswant", as it is unexpected that a get
4115 // function has a side effect.
4116 if (wp == curwin && save_set_curswant)
4117 {
4118 curwin->w_set_curswant = save_set_curswant;
4119 curwin->w_curswant = save_curswant;
4120 curwin->w_virtcol = save_virtcol;
4121 curwin->w_valid &= ~VALID_VIRTCOL;
4122 }
4123 }
4124 }
4125 else
4126 rettv->vval.v_number = FALSE;
4127}
4128
4129/*
4130 * "getcharpos()" function
4131 */
4132 static void
4133f_getcharpos(typval_T *argvars UNUSED, typval_T *rettv)
4134{
4135 getpos_both(argvars, rettv, FALSE, TRUE);
4136}
4137
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004138/*
4139 * "getcharsearch()" function
4140 */
4141 static void
4142f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4143{
4144 if (rettv_dict_alloc(rettv) != FAIL)
4145 {
4146 dict_T *dict = rettv->vval.v_dict;
4147
Bram Moolenaare0be1672018-07-08 16:50:37 +02004148 dict_add_string(dict, "char", last_csearch());
4149 dict_add_number(dict, "forward", last_csearch_forward());
4150 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004151 }
4152}
4153
4154/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004155 * "getenv()" function
4156 */
4157 static void
4158f_getenv(typval_T *argvars, typval_T *rettv)
4159{
4160 int mustfree = FALSE;
4161 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4162
4163 if (p == NULL)
4164 {
4165 rettv->v_type = VAR_SPECIAL;
4166 rettv->vval.v_number = VVAL_NULL;
4167 return;
4168 }
4169 if (!mustfree)
4170 p = vim_strsave(p);
4171 rettv->vval.v_string = p;
4172 rettv->v_type = VAR_STRING;
4173}
4174
4175/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004176 * "getfontname()" function
4177 */
4178 static void
4179f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4180{
4181 rettv->v_type = VAR_STRING;
4182 rettv->vval.v_string = NULL;
4183#ifdef FEAT_GUI
4184 if (gui.in_use)
4185 {
4186 GuiFont font;
4187 char_u *name = NULL;
4188
4189 if (argvars[0].v_type == VAR_UNKNOWN)
4190 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004191 // Get the "Normal" font. Either the name saved by
4192 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004193 font = gui.norm_font;
4194 name = hl_get_font_name();
4195 }
4196 else
4197 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004198 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004199 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004200 return;
4201 font = gui_mch_get_font(name, FALSE);
4202 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004203 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004204 }
4205 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4206 if (argvars[0].v_type != VAR_UNKNOWN)
4207 gui_mch_free_font(font);
4208 }
4209#endif
4210}
4211
4212/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004213 * "getjumplist()" function
4214 */
4215 static void
4216f_getjumplist(typval_T *argvars, typval_T *rettv)
4217{
4218#ifdef FEAT_JUMPLIST
4219 win_T *wp;
4220 int i;
4221 list_T *l;
4222 dict_T *d;
4223#endif
4224
4225 if (rettv_list_alloc(rettv) != OK)
4226 return;
4227
4228#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004229 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004230 if (wp == NULL)
4231 return;
4232
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01004233 cleanup_jumplist(wp, TRUE);
4234
Bram Moolenaar4f505882018-02-10 21:06:32 +01004235 l = list_alloc();
4236 if (l == NULL)
4237 return;
4238
4239 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4240 return;
4241 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4242
4243 for (i = 0; i < wp->w_jumplistlen; ++i)
4244 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004245 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4246 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004247 if ((d = dict_alloc()) == NULL)
4248 return;
4249 if (list_append_dict(l, d) == FAIL)
4250 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004251 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4252 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004253 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004254 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004255 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02004256 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004257 }
4258#endif
4259}
4260
4261/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004262 * "getpid()" function
4263 */
4264 static void
4265f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4266{
4267 rettv->vval.v_number = mch_get_pid();
4268}
4269
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004270/*
4271 * "getcurpos()" function
4272 */
4273 static void
4274f_getcurpos(typval_T *argvars, typval_T *rettv)
4275{
Bram Moolenaar6f02b002021-01-10 20:22:54 +01004276 getpos_both(argvars, rettv, TRUE, FALSE);
4277}
4278
4279 static void
4280f_getcursorcharpos(typval_T *argvars, typval_T *rettv)
4281{
4282 getpos_both(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004283}
4284
4285/*
4286 * "getpos(string)" function
4287 */
4288 static void
4289f_getpos(typval_T *argvars, typval_T *rettv)
4290{
Bram Moolenaar6f02b002021-01-10 20:22:54 +01004291 getpos_both(argvars, rettv, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004292}
4293
4294/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004295 * "getreg()" function
4296 */
4297 static void
4298f_getreg(typval_T *argvars, typval_T *rettv)
4299{
4300 char_u *strregname;
4301 int regname;
4302 int arg2 = FALSE;
4303 int return_list = FALSE;
4304 int error = FALSE;
4305
4306 if (argvars[0].v_type != VAR_UNKNOWN)
4307 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004308 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar418a29f2021-02-10 22:23:41 +01004309 if (strregname == NULL)
4310 error = TRUE;
4311 else if (in_vim9script() && STRLEN(strregname) > 1)
4312 {
4313 semsg(_(e_register_name_must_be_one_char_str), strregname);
4314 error = TRUE;
4315 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004316 if (argvars[1].v_type != VAR_UNKNOWN)
4317 {
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02004318 arg2 = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004319 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar67ff97d2020-09-02 21:45:54 +02004320 return_list = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004321 }
4322 }
4323 else
4324 strregname = get_vim_var_str(VV_REG);
4325
4326 if (error)
4327 return;
4328
4329 regname = (strregname == NULL ? '"' : *strregname);
4330 if (regname == 0)
4331 regname = '"';
4332
4333 if (return_list)
4334 {
4335 rettv->v_type = VAR_LIST;
4336 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4337 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4338 if (rettv->vval.v_list == NULL)
4339 (void)rettv_list_alloc(rettv);
4340 else
4341 ++rettv->vval.v_list->lv_refcount;
4342 }
4343 else
4344 {
4345 rettv->v_type = VAR_STRING;
4346 rettv->vval.v_string = get_reg_contents(regname,
4347 arg2 ? GREG_EXPR_SRC : 0);
4348 }
4349}
4350
4351/*
4352 * "getregtype()" function
4353 */
4354 static void
4355f_getregtype(typval_T *argvars, typval_T *rettv)
4356{
4357 char_u *strregname;
4358 int regname;
4359 char_u buf[NUMBUFLEN + 2];
4360 long reglen = 0;
4361
4362 if (argvars[0].v_type != VAR_UNKNOWN)
4363 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004364 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar418a29f2021-02-10 22:23:41 +01004365 if (strregname != NULL && in_vim9script() && STRLEN(strregname) > 1)
4366 {
4367 semsg(_(e_register_name_must_be_one_char_str), strregname);
4368 strregname = NULL;
4369 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004370 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004371 {
4372 rettv->v_type = VAR_STRING;
4373 rettv->vval.v_string = NULL;
4374 return;
4375 }
4376 }
4377 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004378 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004379 strregname = get_vim_var_str(VV_REG);
4380
4381 regname = (strregname == NULL ? '"' : *strregname);
4382 if (regname == 0)
4383 regname = '"';
4384
4385 buf[0] = NUL;
4386 buf[1] = NUL;
4387 switch (get_reg_type(regname, &reglen))
4388 {
4389 case MLINE: buf[0] = 'V'; break;
4390 case MCHAR: buf[0] = 'v'; break;
4391 case MBLOCK:
4392 buf[0] = Ctrl_V;
4393 sprintf((char *)buf + 1, "%ld", reglen + 1);
4394 break;
4395 }
4396 rettv->v_type = VAR_STRING;
4397 rettv->vval.v_string = vim_strsave(buf);
4398}
4399
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004400/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01004401 * "gettagstack()" function
4402 */
4403 static void
4404f_gettagstack(typval_T *argvars, typval_T *rettv)
4405{
4406 win_T *wp = curwin; // default is current window
4407
4408 if (rettv_dict_alloc(rettv) != OK)
4409 return;
4410
4411 if (argvars[0].v_type != VAR_UNKNOWN)
4412 {
4413 wp = find_win_by_nr_or_id(&argvars[0]);
4414 if (wp == NULL)
4415 return;
4416 }
4417
4418 get_tagstack(wp, rettv->vval.v_dict);
4419}
4420
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +02004421/*
4422 * "gettext()" function
4423 */
4424 static void
4425f_gettext(typval_T *argvars, typval_T *rettv)
4426{
4427 if (argvars[0].v_type != VAR_STRING
4428 || argvars[0].vval.v_string == NULL
4429 || *argvars[0].vval.v_string == NUL)
4430 {
4431 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
4432 }
4433 else
4434 {
4435 rettv->v_type = VAR_STRING;
4436 rettv->vval.v_string = vim_strsave(
4437 (char_u *)_(argvars[0].vval.v_string));
4438 }
4439}
4440
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004441// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004442#include "version.h"
4443
4444/*
4445 * "has()" function
4446 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01004447 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448f_has(typval_T *argvars, typval_T *rettv)
4449{
4450 int i;
4451 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01004452 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004453 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01004454 typedef struct {
4455 char *name;
4456 short present;
4457 } has_item_T;
4458 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004460 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004461#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01004462 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004463#else
Bram Moolenaar79296512020-03-22 16:17:14 +01004464 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004465#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004466 },
4467 {"arp",
4468#if defined(AMIGA) && defined(FEAT_ARP)
4469 1
4470#else
4471 0
4472#endif
4473 },
Bram Moolenaar79296512020-03-22 16:17:14 +01004474 {"haiku",
4475#ifdef __HAIKU__
4476 1
4477#else
4478 0
4479#endif
4480 },
4481 {"bsd",
4482#if defined(BSD) && !defined(MACOS_X)
4483 1
4484#else
4485 0
4486#endif
4487 },
4488 {"hpux",
4489#ifdef hpux
4490 1
4491#else
4492 0
4493#endif
4494 },
4495 {"linux",
4496#ifdef __linux__
4497 1
4498#else
4499 0
4500#endif
4501 },
4502 {"mac", // Mac OS X (and, once, Mac OS Classic)
4503#ifdef MACOS_X
4504 1
4505#else
4506 0
4507#endif
4508 },
4509 {"osx", // Mac OS X
4510#ifdef MACOS_X
4511 1
4512#else
4513 0
4514#endif
4515 },
4516 {"macunix", // Mac OS X, with the darwin feature
4517#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4518 1
4519#else
4520 0
4521#endif
4522 },
4523 {"osxdarwin", // synonym for macunix
4524#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
4525 1
4526#else
4527 0
4528#endif
4529 },
4530 {"qnx",
4531#ifdef __QNX__
4532 1
4533#else
4534 0
4535#endif
4536 },
4537 {"sun",
4538#ifdef SUN_SYSTEM
4539 1
4540#else
4541 0
4542#endif
4543 },
4544 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004545#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01004546 1
4547#else
4548 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004550 },
4551 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004552#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01004553 1
4554#else
4555 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004556#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004557 },
4558 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01004559#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01004560 1
4561#else
4562 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004564 },
4565 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01004566#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01004567 1
4568#else
4569 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004570#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004571 },
4572 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01004573#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01004574 1
4575#else
4576 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004577#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004578 },
4579 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004580#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01004581 1
4582#else
4583 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004584#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004585 },
4586 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004587#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01004588 1
4589#else
4590 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004591#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004592 },
4593 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01004595 1
4596#else
4597 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004598#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004599 },
4600 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004601#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01004602 1
4603#else
4604 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004605#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004606 },
4607 {"autocmd", 1},
4608 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004609#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01004610 1
4611#else
4612 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004613#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004614 },
4615 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01004616#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01004617 1
4618#else
4619 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01004620#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004621 },
4622 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004623#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01004624 1
4625#else
4626 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004627#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004628 },
4629 {"balloon_multiline",
4630#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
4631 // MS-Windows requires runtime check, see below
4632 1
4633#else
4634 0
4635#endif
4636 },
4637 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004638#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01004639 1
4640#else
4641 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01004642#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004643 },
4644 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004645#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01004646 1
4647#else
4648 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004649#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004650 },
4651 {"all_builtin_terms",
4652#if defined(ALL_BUILTIN_TCAPS)
4653 1
4654#else
4655 0
4656#endif
4657 },
4658 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004659#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01004660 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01004662 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663#else
Bram Moolenaar79296512020-03-22 16:17:14 +01004664 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004665#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004666 },
4667 {"byte_offset",
4668#ifdef FEAT_BYTEOFF
4669 1
4670#else
4671 0
4672#endif
4673 },
4674 {"channel",
4675#ifdef FEAT_JOB_CHANNEL
4676 1
4677#else
4678 0
4679#endif
4680 },
4681 {"cindent",
4682#ifdef FEAT_CINDENT
4683 1
4684#else
4685 0
4686#endif
4687 },
4688 {"clientserver",
4689#ifdef FEAT_CLIENTSERVER
4690 1
4691#else
4692 0
4693#endif
4694 },
4695 {"clipboard",
4696#ifdef FEAT_CLIPBOARD
4697 1
4698#else
4699 0
4700#endif
4701 },
4702 {"cmdline_compl", 1},
4703 {"cmdline_hist", 1},
Bram Moolenaar21829c52021-01-26 22:42:21 +01004704 {"cmdwin",
4705#ifdef FEAT_CMDWIN
4706 1
4707#else
4708 0
4709#endif
4710 },
Bram Moolenaar79296512020-03-22 16:17:14 +01004711 {"comments", 1},
4712 {"conceal",
4713#ifdef FEAT_CONCEAL
4714 1
4715#else
4716 0
4717#endif
4718 },
4719 {"cryptv",
4720#ifdef FEAT_CRYPT
4721 1
4722#else
4723 0
4724#endif
4725 },
4726 {"crypt-blowfish",
4727#ifdef FEAT_CRYPT
4728 1
4729#else
4730 0
4731#endif
4732 },
4733 {"crypt-blowfish2",
4734#ifdef FEAT_CRYPT
4735 1
4736#else
4737 0
4738#endif
4739 },
4740 {"cscope",
4741#ifdef FEAT_CSCOPE
4742 1
4743#else
4744 0
4745#endif
4746 },
4747 {"cursorbind", 1},
4748 {"cursorshape",
4749#ifdef CURSOR_SHAPE
4750 1
4751#else
4752 0
4753#endif
4754 },
4755 {"debug",
4756#ifdef DEBUG
4757 1
4758#else
4759 0
4760#endif
4761 },
4762 {"dialog_con",
4763#ifdef FEAT_CON_DIALOG
4764 1
4765#else
4766 0
4767#endif
4768 },
4769 {"dialog_gui",
4770#ifdef FEAT_GUI_DIALOG
4771 1
4772#else
4773 0
4774#endif
4775 },
4776 {"diff",
4777#ifdef FEAT_DIFF
4778 1
4779#else
4780 0
4781#endif
4782 },
4783 {"digraphs",
4784#ifdef FEAT_DIGRAPHS
4785 1
4786#else
4787 0
4788#endif
4789 },
4790 {"directx",
4791#ifdef FEAT_DIRECTX
4792 1
4793#else
4794 0
4795#endif
4796 },
4797 {"dnd",
4798#ifdef FEAT_DND
4799 1
4800#else
4801 0
4802#endif
4803 },
4804 {"emacs_tags",
4805#ifdef FEAT_EMACS_TAGS
4806 1
4807#else
4808 0
4809#endif
4810 },
4811 {"eval", 1}, // always present, of course!
4812 {"ex_extra", 1}, // graduated feature
4813 {"extra_search",
4814#ifdef FEAT_SEARCH_EXTRA
4815 1
4816#else
4817 0
4818#endif
4819 },
4820 {"file_in_path",
4821#ifdef FEAT_SEARCHPATH
4822 1
4823#else
4824 0
4825#endif
4826 },
4827 {"filterpipe",
4828#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
4829 1
4830#else
4831 0
4832#endif
4833 },
4834 {"find_in_path",
4835#ifdef FEAT_FIND_ID
4836 1
4837#else
4838 0
4839#endif
4840 },
4841 {"float",
4842#ifdef FEAT_FLOAT
4843 1
4844#else
4845 0
4846#endif
4847 },
4848 {"folding",
4849#ifdef FEAT_FOLDING
4850 1
4851#else
4852 0
4853#endif
4854 },
4855 {"footer",
4856#ifdef FEAT_FOOTER
4857 1
4858#else
4859 0
4860#endif
4861 },
4862 {"fork",
4863#if !defined(USE_SYSTEM) && defined(UNIX)
4864 1
4865#else
4866 0
4867#endif
4868 },
4869 {"gettext",
4870#ifdef FEAT_GETTEXT
4871 1
4872#else
4873 0
4874#endif
4875 },
4876 {"gui",
4877#ifdef FEAT_GUI
4878 1
4879#else
4880 0
4881#endif
4882 },
4883 {"gui_neXtaw",
4884#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
4885 1
4886#else
4887 0
4888#endif
4889 },
4890 {"gui_athena",
4891#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
4892 1
4893#else
4894 0
4895#endif
4896 },
4897 {"gui_gtk",
4898#ifdef FEAT_GUI_GTK
4899 1
4900#else
4901 0
4902#endif
4903 },
4904 {"gui_gtk2",
4905#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
4906 1
4907#else
4908 0
4909#endif
4910 },
4911 {"gui_gtk3",
4912#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
4913 1
4914#else
4915 0
4916#endif
4917 },
4918 {"gui_gnome",
4919#ifdef FEAT_GUI_GNOME
4920 1
4921#else
4922 0
4923#endif
4924 },
4925 {"gui_haiku",
4926#ifdef FEAT_GUI_HAIKU
4927 1
4928#else
4929 0
4930#endif
4931 },
Bram Moolenaar097148e2020-08-11 21:58:20 +02004932 {"gui_mac", 0},
Bram Moolenaar79296512020-03-22 16:17:14 +01004933 {"gui_motif",
4934#ifdef FEAT_GUI_MOTIF
4935 1
4936#else
4937 0
4938#endif
4939 },
4940 {"gui_photon",
4941#ifdef FEAT_GUI_PHOTON
4942 1
4943#else
4944 0
4945#endif
4946 },
4947 {"gui_win32",
4948#ifdef FEAT_GUI_MSWIN
4949 1
4950#else
4951 0
4952#endif
4953 },
4954 {"iconv",
4955#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
4956 1
4957#else
4958 0
4959#endif
4960 },
4961 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02004962 {"ipv6",
4963#ifdef FEAT_IPV6
4964 1
4965#else
4966 0
4967#endif
4968 },
Bram Moolenaar79296512020-03-22 16:17:14 +01004969 {"job",
4970#ifdef FEAT_JOB_CHANNEL
4971 1
4972#else
4973 0
4974#endif
4975 },
4976 {"jumplist",
4977#ifdef FEAT_JUMPLIST
4978 1
4979#else
4980 0
4981#endif
4982 },
4983 {"keymap",
4984#ifdef FEAT_KEYMAP
4985 1
4986#else
4987 0
4988#endif
4989 },
4990 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
4991 {"langmap",
4992#ifdef FEAT_LANGMAP
4993 1
4994#else
4995 0
4996#endif
4997 },
4998 {"libcall",
4999#ifdef FEAT_LIBCALL
5000 1
5001#else
5002 0
5003#endif
5004 },
5005 {"linebreak",
5006#ifdef FEAT_LINEBREAK
5007 1
5008#else
5009 0
5010#endif
5011 },
5012 {"lispindent",
5013#ifdef FEAT_LISP
5014 1
5015#else
5016 0
5017#endif
5018 },
5019 {"listcmds", 1},
5020 {"localmap", 1},
5021 {"lua",
5022#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
5023 1
5024#else
5025 0
5026#endif
5027 },
5028 {"menu",
5029#ifdef FEAT_MENU
5030 1
5031#else
5032 0
5033#endif
5034 },
5035 {"mksession",
5036#ifdef FEAT_SESSION
5037 1
5038#else
5039 0
5040#endif
5041 },
5042 {"modify_fname", 1},
5043 {"mouse", 1},
5044 {"mouseshape",
5045#ifdef FEAT_MOUSESHAPE
5046 1
5047#else
5048 0
5049#endif
5050 },
5051 {"mouse_dec",
5052#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
5053 1
5054#else
5055 0
5056#endif
5057 },
5058 {"mouse_gpm",
5059#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
5060 1
5061#else
5062 0
5063#endif
5064 },
5065 {"mouse_jsbterm",
5066#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
5067 1
5068#else
5069 0
5070#endif
5071 },
5072 {"mouse_netterm",
5073#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
5074 1
5075#else
5076 0
5077#endif
5078 },
5079 {"mouse_pterm",
5080#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
5081 1
5082#else
5083 0
5084#endif
5085 },
5086 {"mouse_sgr",
5087#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
5088 1
5089#else
5090 0
5091#endif
5092 },
5093 {"mouse_sysmouse",
5094#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
5095 1
5096#else
5097 0
5098#endif
5099 },
5100 {"mouse_urxvt",
5101#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
5102 1
5103#else
5104 0
5105#endif
5106 },
5107 {"mouse_xterm",
5108#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
5109 1
5110#else
5111 0
5112#endif
5113 },
5114 {"multi_byte", 1},
5115 {"multi_byte_ime",
5116#ifdef FEAT_MBYTE_IME
5117 1
5118#else
5119 0
5120#endif
5121 },
5122 {"multi_lang",
5123#ifdef FEAT_MULTI_LANG
5124 1
5125#else
5126 0
5127#endif
5128 },
5129 {"mzscheme",
5130#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
5131 1
5132#else
5133 0
5134#endif
5135 },
5136 {"num64", 1},
5137 {"ole",
5138#ifdef FEAT_OLE
5139 1
5140#else
5141 0
5142#endif
5143 },
5144 {"packages",
5145#ifdef FEAT_EVAL
5146 1
5147#else
5148 0
5149#endif
5150 },
5151 {"path_extra",
5152#ifdef FEAT_PATH_EXTRA
5153 1
5154#else
5155 0
5156#endif
5157 },
5158 {"perl",
5159#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
5160 1
5161#else
5162 0
5163#endif
5164 },
5165 {"persistent_undo",
5166#ifdef FEAT_PERSISTENT_UNDO
5167 1
5168#else
5169 0
5170#endif
5171 },
5172 {"python_compiled",
5173#if defined(FEAT_PYTHON)
5174 1
5175#else
5176 0
5177#endif
5178 },
5179 {"python_dynamic",
5180#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
5181 1
5182#else
5183 0
5184#endif
5185 },
5186 {"python",
5187#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
5188 1
5189#else
5190 0
5191#endif
5192 },
5193 {"pythonx",
5194#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
5195 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
5196 1
5197#else
5198 0
5199#endif
5200 },
5201 {"python3_compiled",
5202#if defined(FEAT_PYTHON3)
5203 1
5204#else
5205 0
5206#endif
5207 },
5208 {"python3_dynamic",
5209#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
5210 1
5211#else
5212 0
5213#endif
5214 },
5215 {"python3",
5216#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
5217 1
5218#else
5219 0
5220#endif
5221 },
5222 {"popupwin",
5223#ifdef FEAT_PROP_POPUP
5224 1
5225#else
5226 0
5227#endif
5228 },
5229 {"postscript",
5230#ifdef FEAT_POSTSCRIPT
5231 1
5232#else
5233 0
5234#endif
5235 },
5236 {"printer",
5237#ifdef FEAT_PRINTER
5238 1
5239#else
5240 0
5241#endif
5242 },
5243 {"profile",
5244#ifdef FEAT_PROFILE
5245 1
5246#else
5247 0
5248#endif
5249 },
5250 {"reltime",
5251#ifdef FEAT_RELTIME
5252 1
5253#else
5254 0
5255#endif
5256 },
5257 {"quickfix",
5258#ifdef FEAT_QUICKFIX
5259 1
5260#else
5261 0
5262#endif
5263 },
5264 {"rightleft",
5265#ifdef FEAT_RIGHTLEFT
5266 1
5267#else
5268 0
5269#endif
5270 },
5271 {"ruby",
5272#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5273 1
5274#else
5275 0
5276#endif
5277 },
5278 {"scrollbind", 1},
5279 {"showcmd",
5280#ifdef FEAT_CMDL_INFO
5281 1
5282#else
5283 0
5284#endif
5285 },
5286 {"cmdline_info",
5287#ifdef FEAT_CMDL_INFO
5288 1
5289#else
5290 0
5291#endif
5292 },
5293 {"signs",
5294#ifdef FEAT_SIGNS
5295 1
5296#else
5297 0
5298#endif
5299 },
5300 {"smartindent",
5301#ifdef FEAT_SMARTINDENT
5302 1
5303#else
5304 0
5305#endif
5306 },
5307 {"startuptime",
5308#ifdef STARTUPTIME
5309 1
5310#else
5311 0
5312#endif
5313 },
5314 {"statusline",
5315#ifdef FEAT_STL_OPT
5316 1
5317#else
5318 0
5319#endif
5320 },
5321 {"netbeans_intg",
5322#ifdef FEAT_NETBEANS_INTG
5323 1
5324#else
5325 0
5326#endif
5327 },
5328 {"sound",
5329#ifdef FEAT_SOUND
5330 1
5331#else
5332 0
5333#endif
5334 },
5335 {"spell",
5336#ifdef FEAT_SPELL
5337 1
5338#else
5339 0
5340#endif
5341 },
5342 {"syntax",
5343#ifdef FEAT_SYN_HL
5344 1
5345#else
5346 0
5347#endif
5348 },
5349 {"system",
5350#if defined(USE_SYSTEM) || !defined(UNIX)
5351 1
5352#else
5353 0
5354#endif
5355 },
5356 {"tag_binary",
5357#ifdef FEAT_TAG_BINS
5358 1
5359#else
5360 0
5361#endif
5362 },
5363 {"tcl",
5364#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
5365 1
5366#else
5367 0
5368#endif
5369 },
5370 {"termguicolors",
5371#ifdef FEAT_TERMGUICOLORS
5372 1
5373#else
5374 0
5375#endif
5376 },
5377 {"terminal",
5378#if defined(FEAT_TERMINAL) && !defined(MSWIN)
5379 1
5380#else
5381 0
5382#endif
5383 },
5384 {"terminfo",
5385#ifdef TERMINFO
5386 1
5387#else
5388 0
5389#endif
5390 },
5391 {"termresponse",
5392#ifdef FEAT_TERMRESPONSE
5393 1
5394#else
5395 0
5396#endif
5397 },
5398 {"textobjects",
5399#ifdef FEAT_TEXTOBJ
5400 1
5401#else
5402 0
5403#endif
5404 },
5405 {"textprop",
5406#ifdef FEAT_PROP_POPUP
5407 1
5408#else
5409 0
5410#endif
5411 },
5412 {"tgetent",
5413#ifdef HAVE_TGETENT
5414 1
5415#else
5416 0
5417#endif
5418 },
5419 {"timers",
5420#ifdef FEAT_TIMERS
5421 1
5422#else
5423 0
5424#endif
5425 },
5426 {"title",
5427#ifdef FEAT_TITLE
5428 1
5429#else
5430 0
5431#endif
5432 },
5433 {"toolbar",
5434#ifdef FEAT_TOOLBAR
5435 1
5436#else
5437 0
5438#endif
5439 },
5440 {"unnamedplus",
5441#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5442 1
5443#else
5444 0
5445#endif
5446 },
5447 {"user-commands", 1}, // was accidentally included in 5.4
5448 {"user_commands", 1},
5449 {"vartabs",
5450#ifdef FEAT_VARTABS
5451 1
5452#else
5453 0
5454#endif
5455 },
5456 {"vertsplit", 1},
5457 {"viminfo",
5458#ifdef FEAT_VIMINFO
5459 1
5460#else
5461 0
5462#endif
5463 },
5464 {"vimscript-1", 1},
5465 {"vimscript-2", 1},
5466 {"vimscript-3", 1},
5467 {"vimscript-4", 1},
5468 {"virtualedit", 1},
5469 {"visual", 1},
5470 {"visualextra", 1},
5471 {"vreplace", 1},
5472 {"vtp",
5473#ifdef FEAT_VTP
5474 1
5475#else
5476 0
5477#endif
5478 },
5479 {"wildignore",
5480#ifdef FEAT_WILDIGN
5481 1
5482#else
5483 0
5484#endif
5485 },
5486 {"wildmenu",
5487#ifdef FEAT_WILDMENU
5488 1
5489#else
5490 0
5491#endif
5492 },
5493 {"windows", 1},
5494 {"winaltkeys",
5495#ifdef FEAT_WAK
5496 1
5497#else
5498 0
5499#endif
5500 },
5501 {"writebackup",
5502#ifdef FEAT_WRITEBACKUP
5503 1
5504#else
5505 0
5506#endif
5507 },
5508 {"xim",
5509#ifdef FEAT_XIM
5510 1
5511#else
5512 0
5513#endif
5514 },
5515 {"xfontset",
5516#ifdef FEAT_XFONTSET
5517 1
5518#else
5519 0
5520#endif
5521 },
5522 {"xpm",
5523#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
5524 1
5525#else
5526 0
5527#endif
5528 },
5529 {"xpm_w32", // for backward compatibility
5530#ifdef FEAT_XPM_W32
5531 1
5532#else
5533 0
5534#endif
5535 },
5536 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005537#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01005538 1
5539#else
5540 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005541#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005542 },
5543 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01005545 1
5546#else
5547 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005549 },
5550 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005551#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01005552 1
5553#else
5554 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005555#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005556 },
5557 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005558#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01005559 1
5560#else
5561 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005562#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005563 },
5564 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005565#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01005566 1
5567#else
5568 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005569#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005570 },
5571 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005572 };
5573
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005574 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01005575 for (i = 0; has_list[i].name != NULL; ++i)
5576 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 {
Bram Moolenaar79296512020-03-22 16:17:14 +01005578 x = TRUE;
5579 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005580 break;
5581 }
5582
Bram Moolenaar79296512020-03-22 16:17:14 +01005583 // features also in has_list[] but sometimes enabled at runtime
5584 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005585 {
Bram Moolenaar79296512020-03-22 16:17:14 +01005586 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02005587 {
5588 // intentionally empty
5589 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005590#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005591 else if (STRICMP(name, "balloon_multiline") == 0)
5592 n = multiline_balloon_available();
5593#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005594#ifdef VIMDLL
5595 else if (STRICMP(name, "filterpipe") == 0)
5596 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005597#endif
5598#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5599 else if (STRICMP(name, "iconv") == 0)
5600 n = iconv_enabled(FALSE);
5601#endif
5602#ifdef DYNAMIC_LUA
5603 else if (STRICMP(name, "lua") == 0)
5604 n = lua_enabled(FALSE);
5605#endif
5606#ifdef DYNAMIC_MZSCHEME
5607 else if (STRICMP(name, "mzscheme") == 0)
5608 n = mzscheme_enabled(FALSE);
5609#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005610#ifdef DYNAMIC_PERL
5611 else if (STRICMP(name, "perl") == 0)
5612 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005613#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005614#ifdef DYNAMIC_PYTHON
5615 else if (STRICMP(name, "python") == 0)
5616 n = python_enabled(FALSE);
5617#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005618#ifdef DYNAMIC_PYTHON3
5619 else if (STRICMP(name, "python3") == 0)
5620 n = python3_enabled(FALSE);
5621#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005622#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5623 else if (STRICMP(name, "pythonx") == 0)
5624 {
5625# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
5626 if (p_pyx == 0)
5627 n = python3_enabled(FALSE) || python_enabled(FALSE);
5628 else if (p_pyx == 3)
5629 n = python3_enabled(FALSE);
5630 else if (p_pyx == 2)
5631 n = python_enabled(FALSE);
5632# elif defined(DYNAMIC_PYTHON)
5633 n = python_enabled(FALSE);
5634# elif defined(DYNAMIC_PYTHON3)
5635 n = python3_enabled(FALSE);
5636# endif
5637 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005638#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005639#ifdef DYNAMIC_RUBY
5640 else if (STRICMP(name, "ruby") == 0)
5641 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01005643#ifdef DYNAMIC_TCL
5644 else if (STRICMP(name, "tcl") == 0)
5645 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02005646#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005647#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02005648 else if (STRICMP(name, "terminal") == 0)
5649 n = terminal_enabled();
5650#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005651 }
5652
Bram Moolenaar79296512020-03-22 16:17:14 +01005653 // features not in has_list[]
5654 if (x == FALSE)
5655 {
5656 if (STRNICMP(name, "patch", 5) == 0)
5657 {
5658 x = TRUE;
5659 if (name[5] == '-'
5660 && STRLEN(name) >= 11
5661 && vim_isdigit(name[6])
5662 && vim_isdigit(name[8])
5663 && vim_isdigit(name[10]))
5664 {
5665 int major = atoi((char *)name + 6);
5666 int minor = atoi((char *)name + 8);
5667
5668 // Expect "patch-9.9.01234".
5669 n = (major < VIM_VERSION_MAJOR
5670 || (major == VIM_VERSION_MAJOR
5671 && (minor < VIM_VERSION_MINOR
5672 || (minor == VIM_VERSION_MINOR
5673 && has_patch(atoi((char *)name + 10))))));
5674 }
5675 else
5676 n = has_patch(atoi((char *)name + 5));
5677 }
5678 else if (STRICMP(name, "vim_starting") == 0)
5679 {
5680 x = TRUE;
5681 n = (starting != 0);
5682 }
5683 else if (STRICMP(name, "ttyin") == 0)
5684 {
5685 x = TRUE;
5686 n = mch_input_isatty();
5687 }
5688 else if (STRICMP(name, "ttyout") == 0)
5689 {
5690 x = TRUE;
5691 n = stdout_isatty;
5692 }
5693 else if (STRICMP(name, "multi_byte_encoding") == 0)
5694 {
5695 x = TRUE;
5696 n = has_mbyte;
5697 }
5698 else if (STRICMP(name, "gui_running") == 0)
5699 {
5700 x = TRUE;
5701#ifdef FEAT_GUI
5702 n = (gui.in_use || gui.starting);
5703#endif
5704 }
5705 else if (STRICMP(name, "browse") == 0)
5706 {
5707 x = TRUE;
5708#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
5709 n = gui.in_use; // gui_mch_browse() works when GUI is running
5710#endif
5711 }
5712 else if (STRICMP(name, "syntax_items") == 0)
5713 {
5714 x = TRUE;
5715#ifdef FEAT_SYN_HL
5716 n = syntax_present(curwin);
5717#endif
5718 }
5719 else if (STRICMP(name, "vcon") == 0)
5720 {
5721 x = TRUE;
5722#ifdef FEAT_VTP
5723 n = is_term_win32() && has_vtp_working();
5724#endif
5725 }
5726 else if (STRICMP(name, "netbeans_enabled") == 0)
5727 {
5728 x = TRUE;
5729#ifdef FEAT_NETBEANS_INTG
5730 n = netbeans_active();
5731#endif
5732 }
5733 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
5734 {
5735 x = TRUE;
5736#ifdef FEAT_MOUSE_GPM
5737 n = gpm_enabled();
5738#endif
5739 }
5740 else if (STRICMP(name, "conpty") == 0)
5741 {
5742 x = TRUE;
5743#if defined(FEAT_TERMINAL) && defined(MSWIN)
5744 n = use_conpty();
5745#endif
5746 }
5747 else if (STRICMP(name, "clipboard_working") == 0)
5748 {
5749 x = TRUE;
5750#ifdef FEAT_CLIPBOARD
5751 n = clip_star.available;
5752#endif
5753 }
5754 }
5755
Bram Moolenaar04637e22020-09-05 18:45:29 +02005756 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]))
Bram Moolenaar79296512020-03-22 16:17:14 +01005757 // return whether feature could ever be enabled
5758 rettv->vval.v_number = x;
5759 else
5760 // return whether feature is enabled
5761 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005762}
5763
5764/*
Bram Moolenaar8cebd432020-11-08 12:49:47 +01005765 * Return TRUE if "feature" can change later.
5766 * Also when checking for the feature has side effects, such as loading a DLL.
5767 */
5768 int
5769dynamic_feature(char_u *feature)
5770{
5771 return (feature == NULL
5772#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
5773 || STRICMP(feature, "balloon_multiline") == 0
5774#endif
5775#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
5776 || (STRICMP(feature, "browse") == 0 && !gui.in_use)
5777#endif
5778#ifdef VIMDLL
5779 || STRICMP(feature, "filterpipe") == 0
5780#endif
Bram Moolenaar29b281b2020-11-10 20:58:00 +01005781#if defined(FEAT_GUI) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL)
Bram Moolenaar8cebd432020-11-08 12:49:47 +01005782 // this can only change on Unix where the ":gui" command could be
5783 // used.
5784 || (STRICMP(feature, "gui_running") == 0 && !gui.in_use)
5785#endif
5786#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5787 || STRICMP(feature, "iconv") == 0
5788#endif
5789#ifdef DYNAMIC_LUA
5790 || STRICMP(feature, "lua") == 0
5791#endif
5792#ifdef FEAT_MOUSE_GPM
5793 || (STRICMP(feature, "mouse_gpm_enabled") == 0 && !gpm_enabled())
5794#endif
5795#ifdef DYNAMIC_MZSCHEME
5796 || STRICMP(feature, "mzscheme") == 0
5797#endif
5798#ifdef FEAT_NETBEANS_INTG
5799 || STRICMP(feature, "netbeans_enabled") == 0
5800#endif
5801#ifdef DYNAMIC_PERL
5802 || STRICMP(feature, "perl") == 0
5803#endif
5804#ifdef DYNAMIC_PYTHON
5805 || STRICMP(feature, "python") == 0
5806#endif
5807#ifdef DYNAMIC_PYTHON3
5808 || STRICMP(feature, "python3") == 0
5809#endif
5810#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5811 || STRICMP(feature, "pythonx") == 0
5812#endif
5813#ifdef DYNAMIC_RUBY
5814 || STRICMP(feature, "ruby") == 0
5815#endif
5816#ifdef FEAT_SYN_HL
5817 || STRICMP(feature, "syntax_items") == 0
5818#endif
5819#ifdef DYNAMIC_TCL
5820 || STRICMP(feature, "tcl") == 0
5821#endif
5822 // once "starting" is zero it will stay that way
5823 || (STRICMP(feature, "vim_starting") == 0 && starting != 0)
5824 || STRICMP(feature, "multi_byte_encoding") == 0
5825#if defined(FEAT_TERMINAL) && defined(MSWIN)
5826 || STRICMP(feature, "conpty") == 0
5827#endif
5828 );
5829}
5830
5831/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005832 * "haslocaldir()" function
5833 */
5834 static void
5835f_haslocaldir(typval_T *argvars, typval_T *rettv)
5836{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005837 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005838 win_T *wp = NULL;
5839
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005840 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
5841
5842 // Check for window-local and tab-local directories
5843 if (wp != NULL && wp->w_localdir != NULL)
5844 rettv->vval.v_number = 1;
5845 else if (tp != NULL && tp->tp_localdir != NULL)
5846 rettv->vval.v_number = 2;
5847 else
5848 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005849}
5850
5851/*
5852 * "hasmapto()" function
5853 */
5854 static void
5855f_hasmapto(typval_T *argvars, typval_T *rettv)
5856{
5857 char_u *name;
5858 char_u *mode;
5859 char_u buf[NUMBUFLEN];
5860 int abbr = FALSE;
5861
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005862 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005863 if (argvars[1].v_type == VAR_UNKNOWN)
5864 mode = (char_u *)"nvo";
5865 else
5866 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005867 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar04d594b2020-09-02 22:25:35 +02005869 abbr = (int)tv_get_bool(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005870 }
5871
5872 if (map_to_exists(name, mode, abbr))
5873 rettv->vval.v_number = TRUE;
5874 else
5875 rettv->vval.v_number = FALSE;
5876}
5877
5878/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005879 * "highlightID(name)" function
5880 */
5881 static void
5882f_hlID(typval_T *argvars, typval_T *rettv)
5883{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005884 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885}
5886
5887/*
5888 * "highlight_exists()" function
5889 */
5890 static void
5891f_hlexists(typval_T *argvars, typval_T *rettv)
5892{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005893 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005894}
5895
5896/*
5897 * "hostname()" function
5898 */
5899 static void
5900f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5901{
5902 char_u hostname[256];
5903
5904 mch_get_host_name(hostname, 256);
5905 rettv->v_type = VAR_STRING;
5906 rettv->vval.v_string = vim_strsave(hostname);
5907}
5908
5909/*
5910 * iconv() function
5911 */
5912 static void
5913f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5914{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005915 char_u buf1[NUMBUFLEN];
5916 char_u buf2[NUMBUFLEN];
5917 char_u *from, *to, *str;
5918 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005919
5920 rettv->v_type = VAR_STRING;
5921 rettv->vval.v_string = NULL;
5922
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005923 str = tv_get_string(&argvars[0]);
5924 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
5925 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005926 vimconv.vc_type = CONV_NONE;
5927 convert_setup(&vimconv, from, to);
5928
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005929 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005930 if (vimconv.vc_type == CONV_NONE)
5931 rettv->vval.v_string = vim_strsave(str);
5932 else
5933 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5934
5935 convert_setup(&vimconv, NULL, NULL);
5936 vim_free(from);
5937 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005938}
5939
5940/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005941 * "index()" function
5942 */
5943 static void
5944f_index(typval_T *argvars, typval_T *rettv)
5945{
5946 list_T *l;
5947 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005948 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005949 long idx = 0;
5950 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005951 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005952
5953 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005954 if (argvars[0].v_type == VAR_BLOB)
5955 {
5956 typval_T tv;
5957 int start = 0;
5958
5959 if (argvars[2].v_type != VAR_UNKNOWN)
5960 {
5961 start = tv_get_number_chk(&argvars[2], &error);
5962 if (error)
5963 return;
5964 }
5965 b = argvars[0].vval.v_blob;
5966 if (b == NULL)
5967 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01005968 if (start < 0)
5969 {
5970 start = blob_len(b) + start;
5971 if (start < 0)
5972 start = 0;
5973 }
5974
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005975 for (idx = start; idx < blob_len(b); ++idx)
5976 {
5977 tv.v_type = VAR_NUMBER;
5978 tv.vval.v_number = blob_get(b, idx);
5979 if (tv_equal(&tv, &argvars[1], ic, FALSE))
5980 {
5981 rettv->vval.v_number = idx;
5982 return;
5983 }
5984 }
5985 return;
5986 }
5987 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005988 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01005989 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005990 return;
5991 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005992
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005993 l = argvars[0].vval.v_list;
5994 if (l != NULL)
5995 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005996 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997 item = l->lv_first;
5998 if (argvars[2].v_type != VAR_UNKNOWN)
5999 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006000 // Start at specified item. Use the cached index that list_find()
6001 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006002 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006003 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006004 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaar6c553f92020-09-02 22:10:34 +02006005 ic = (int)tv_get_bool_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006 if (error)
6007 item = NULL;
6008 }
6009
6010 for ( ; item != NULL; item = item->li_next, ++idx)
6011 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6012 {
6013 rettv->vval.v_number = idx;
6014 break;
6015 }
6016 }
6017}
6018
6019static int inputsecret_flag = 0;
6020
6021/*
6022 * "input()" function
6023 * Also handles inputsecret() when inputsecret is set.
6024 */
6025 static void
6026f_input(typval_T *argvars, typval_T *rettv)
6027{
6028 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6029}
6030
6031/*
6032 * "inputdialog()" function
6033 */
6034 static void
6035f_inputdialog(typval_T *argvars, typval_T *rettv)
6036{
6037#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006038 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006039 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6040 {
6041 char_u *message;
6042 char_u buf[NUMBUFLEN];
6043 char_u *defstr = (char_u *)"";
6044
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006045 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006046 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006047 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006048 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6049 else
6050 IObuff[0] = NUL;
6051 if (message != NULL && defstr != NULL
6052 && do_dialog(VIM_QUESTION, NULL, message,
6053 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6054 rettv->vval.v_string = vim_strsave(IObuff);
6055 else
6056 {
6057 if (message != NULL && defstr != NULL
6058 && argvars[1].v_type != VAR_UNKNOWN
6059 && argvars[2].v_type != VAR_UNKNOWN)
6060 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006061 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006062 else
6063 rettv->vval.v_string = NULL;
6064 }
6065 rettv->v_type = VAR_STRING;
6066 }
6067 else
6068#endif
6069 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6070}
6071
6072/*
6073 * "inputlist()" function
6074 */
6075 static void
6076f_inputlist(typval_T *argvars, typval_T *rettv)
6077{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006078 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006079 listitem_T *li;
6080 int selected;
6081 int mouse_used;
6082
6083#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006084 // While starting up, there is no place to enter text. When running tests
6085 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006086 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087 return;
6088#endif
6089 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6090 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006091 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006092 return;
6093 }
6094
6095 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006096 msg_row = Rows - 1; // for when 'cmdheight' > 1
6097 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006098 msg_scroll = TRUE;
6099 msg_clr_eos();
6100
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006101 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006102 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02006103 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006104 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006105 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006106 msg_putchar('\n');
6107 }
6108
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006109 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006110 selected = prompt_for_number(&mouse_used);
6111 if (mouse_used)
6112 selected -= lines_left;
6113
6114 rettv->vval.v_number = selected;
6115}
6116
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006117static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6118
6119/*
6120 * "inputrestore()" function
6121 */
6122 static void
6123f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6124{
6125 if (ga_userinput.ga_len > 0)
6126 {
6127 --ga_userinput.ga_len;
6128 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6129 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006130 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006131 }
6132 else if (p_verbose > 1)
6133 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006134 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006135 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006136 }
6137}
6138
6139/*
6140 * "inputsave()" function
6141 */
6142 static void
6143f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6144{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006145 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006146 if (ga_grow(&ga_userinput, 1) == OK)
6147 {
6148 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6149 + ga_userinput.ga_len);
6150 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006151 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006152 }
6153 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006154 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006155}
6156
6157/*
6158 * "inputsecret()" function
6159 */
6160 static void
6161f_inputsecret(typval_T *argvars, typval_T *rettv)
6162{
6163 ++cmdline_star;
6164 ++inputsecret_flag;
6165 f_input(argvars, rettv);
6166 --cmdline_star;
6167 --inputsecret_flag;
6168}
6169
6170/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01006171 * "interrupt()" function
6172 */
6173 static void
6174f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6175{
6176 got_int = TRUE;
6177}
6178
6179/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006180 * "invert(expr)" function
6181 */
6182 static void
6183f_invert(typval_T *argvars, typval_T *rettv)
6184{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006185 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186}
6187
6188/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006189 * "islocked()" function
6190 */
6191 static void
6192f_islocked(typval_T *argvars, typval_T *rettv)
6193{
6194 lval_T lv;
6195 char_u *end;
6196 dictitem_T *di;
6197
6198 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006199 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006200 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006201 if (end != NULL && lv.ll_name != NULL)
6202 {
6203 if (*end != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02006204 semsg(_(e_trailing_arg), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006205 else
6206 {
6207 if (lv.ll_tv == NULL)
6208 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006209 di = find_var(lv.ll_name, NULL, TRUE);
6210 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006211 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006212 // Consider a variable locked when:
6213 // 1. the variable itself is locked
6214 // 2. the value of the variable is locked.
6215 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01006216 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6217 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218 }
6219 }
6220 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006221 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006222 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006223 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006224 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006225 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006226 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6227 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006228 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006229 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6230 }
6231 }
6232
6233 clear_lval(&lv);
6234}
6235
6236#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6237/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006238 * "isinf()" function
6239 */
6240 static void
6241f_isinf(typval_T *argvars, typval_T *rettv)
6242{
6243 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6244 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6245}
6246
6247/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006248 * "isnan()" function
6249 */
6250 static void
6251f_isnan(typval_T *argvars, typval_T *rettv)
6252{
6253 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6254 && isnan(argvars[0].vval.v_float);
6255}
6256#endif
6257
6258/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006259 * "last_buffer_nr()" function.
6260 */
6261 static void
6262f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6263{
6264 int n = 0;
6265 buf_T *buf;
6266
Bram Moolenaar29323592016-07-24 22:04:11 +02006267 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268 if (n < buf->b_fnum)
6269 n = buf->b_fnum;
6270
6271 rettv->vval.v_number = n;
6272}
6273
6274/*
6275 * "len()" function
6276 */
6277 static void
6278f_len(typval_T *argvars, typval_T *rettv)
6279{
6280 switch (argvars[0].v_type)
6281 {
6282 case VAR_STRING:
6283 case VAR_NUMBER:
6284 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006285 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006286 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006287 case VAR_BLOB:
6288 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6289 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 case VAR_LIST:
6291 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6292 break;
6293 case VAR_DICT:
6294 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6295 break;
6296 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02006297 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006298 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01006299 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300 case VAR_SPECIAL:
6301 case VAR_FLOAT:
6302 case VAR_FUNC:
6303 case VAR_PARTIAL:
6304 case VAR_JOB:
6305 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006306 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307 break;
6308 }
6309}
6310
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006311 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006312libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313{
6314#ifdef FEAT_LIBCALL
6315 char_u *string_in;
6316 char_u **string_result;
6317 int nr_result;
6318#endif
6319
6320 rettv->v_type = type;
6321 if (type != VAR_NUMBER)
6322 rettv->vval.v_string = NULL;
6323
6324 if (check_restricted() || check_secure())
6325 return;
6326
6327#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006328 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006329 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6330 {
6331 string_in = NULL;
6332 if (argvars[2].v_type == VAR_STRING)
6333 string_in = argvars[2].vval.v_string;
6334 if (type == VAR_NUMBER)
6335 string_result = NULL;
6336 else
6337 string_result = &rettv->vval.v_string;
6338 if (mch_libcall(argvars[0].vval.v_string,
6339 argvars[1].vval.v_string,
6340 string_in,
6341 argvars[2].vval.v_number,
6342 string_result,
6343 &nr_result) == OK
6344 && type == VAR_NUMBER)
6345 rettv->vval.v_number = nr_result;
6346 }
6347#endif
6348}
6349
6350/*
6351 * "libcall()" function
6352 */
6353 static void
6354f_libcall(typval_T *argvars, typval_T *rettv)
6355{
6356 libcall_common(argvars, rettv, VAR_STRING);
6357}
6358
6359/*
6360 * "libcallnr()" function
6361 */
6362 static void
6363f_libcallnr(typval_T *argvars, typval_T *rettv)
6364{
6365 libcall_common(argvars, rettv, VAR_NUMBER);
6366}
6367
6368/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006369 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006370 */
6371 static void
6372f_line(typval_T *argvars, typval_T *rettv)
6373{
6374 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006375 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006377 int id;
6378 tabpage_T *tp;
6379 win_T *wp;
6380 win_T *save_curwin;
6381 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006382
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006383 if (argvars[1].v_type != VAR_UNKNOWN)
6384 {
6385 // use window specified in the second argument
6386 id = (int)tv_get_number(&argvars[1]);
6387 wp = win_id2wp_tp(id, &tp);
6388 if (wp != NULL && tp != NULL)
6389 {
6390 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
6391 == OK)
6392 {
6393 check_cursor();
Bram Moolenaar6f02b002021-01-10 20:22:54 +01006394 fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006395 }
6396 restore_win_noblock(save_curwin, save_curtab, TRUE);
6397 }
6398 }
6399 else
6400 // use current window
Bram Moolenaar6f02b002021-01-10 20:22:54 +01006401 fp = var2fpos(&argvars[0], TRUE, &fnum, FALSE);
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006402
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006403 if (fp != NULL)
6404 lnum = fp->lnum;
6405 rettv->vval.v_number = lnum;
6406}
6407
6408/*
6409 * "line2byte(lnum)" function
6410 */
6411 static void
6412f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6413{
6414#ifndef FEAT_BYTEOFF
6415 rettv->vval.v_number = -1;
6416#else
6417 linenr_T lnum;
6418
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006419 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6421 rettv->vval.v_number = -1;
6422 else
6423 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6424 if (rettv->vval.v_number >= 0)
6425 ++rettv->vval.v_number;
6426#endif
6427}
6428
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006429#ifdef FEAT_FLOAT
6430/*
6431 * "log()" function
6432 */
6433 static void
6434f_log(typval_T *argvars, typval_T *rettv)
6435{
6436 float_T f = 0.0;
6437
6438 rettv->v_type = VAR_FLOAT;
6439 if (get_float_arg(argvars, &f) == OK)
6440 rettv->vval.v_float = log(f);
6441 else
6442 rettv->vval.v_float = 0.0;
6443}
6444
6445/*
6446 * "log10()" function
6447 */
6448 static void
6449f_log10(typval_T *argvars, typval_T *rettv)
6450{
6451 float_T f = 0.0;
6452
6453 rettv->v_type = VAR_FLOAT;
6454 if (get_float_arg(argvars, &f) == OK)
6455 rettv->vval.v_float = log10(f);
6456 else
6457 rettv->vval.v_float = 0.0;
6458}
6459#endif
6460
6461#ifdef FEAT_LUA
6462/*
6463 * "luaeval()" function
6464 */
6465 static void
6466f_luaeval(typval_T *argvars, typval_T *rettv)
6467{
6468 char_u *str;
6469 char_u buf[NUMBUFLEN];
6470
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006471 if (check_restricted() || check_secure())
6472 return;
6473
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006474 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 do_luaeval(str, argvars + 1, rettv);
6476}
6477#endif
6478
6479/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006480 * "maparg()" function
6481 */
6482 static void
6483f_maparg(typval_T *argvars, typval_T *rettv)
6484{
6485 get_maparg(argvars, rettv, TRUE);
6486}
6487
6488/*
6489 * "mapcheck()" function
6490 */
6491 static void
6492f_mapcheck(typval_T *argvars, typval_T *rettv)
6493{
6494 get_maparg(argvars, rettv, FALSE);
6495}
6496
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006497typedef enum
6498{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006499 MATCH_END, // matchend()
6500 MATCH_MATCH, // match()
6501 MATCH_STR, // matchstr()
6502 MATCH_LIST, // matchlist()
6503 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006504} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505
6506 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006507find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508{
6509 char_u *str = NULL;
6510 long len = 0;
6511 char_u *expr = NULL;
6512 char_u *pat;
6513 regmatch_T regmatch;
6514 char_u patbuf[NUMBUFLEN];
6515 char_u strbuf[NUMBUFLEN];
6516 char_u *save_cpo;
6517 long start = 0;
6518 long nth = 1;
6519 colnr_T startcol = 0;
6520 int match = 0;
6521 list_T *l = NULL;
6522 listitem_T *li = NULL;
6523 long idx = 0;
6524 char_u *tofree = NULL;
6525
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006526 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527 save_cpo = p_cpo;
Bram Moolenaare5a2dc82021-01-03 19:52:05 +01006528 p_cpo = empty_option;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006529
6530 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006531 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006532 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006533 // type MATCH_LIST: return empty list when there are no matches.
6534 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006535 if (rettv_list_alloc(rettv) == FAIL)
6536 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006537 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 && (list_append_string(rettv->vval.v_list,
6539 (char_u *)"", 0) == FAIL
6540 || list_append_number(rettv->vval.v_list,
6541 (varnumber_T)-1) == FAIL
6542 || list_append_number(rettv->vval.v_list,
6543 (varnumber_T)-1) == FAIL
6544 || list_append_number(rettv->vval.v_list,
6545 (varnumber_T)-1) == FAIL))
6546 {
6547 list_free(rettv->vval.v_list);
6548 rettv->vval.v_list = NULL;
6549 goto theend;
6550 }
6551 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006552 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006553 {
6554 rettv->v_type = VAR_STRING;
6555 rettv->vval.v_string = NULL;
6556 }
6557
6558 if (argvars[0].v_type == VAR_LIST)
6559 {
6560 if ((l = argvars[0].vval.v_list) == NULL)
6561 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006562 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006563 li = l->lv_first;
6564 }
6565 else
6566 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006567 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568 len = (long)STRLEN(str);
6569 }
6570
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006571 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006572 if (pat == NULL)
6573 goto theend;
6574
6575 if (argvars[2].v_type != VAR_UNKNOWN)
6576 {
6577 int error = FALSE;
6578
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006579 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006580 if (error)
6581 goto theend;
6582 if (l != NULL)
6583 {
6584 li = list_find(l, start);
6585 if (li == NULL)
6586 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006587 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 }
6589 else
6590 {
6591 if (start < 0)
6592 start = 0;
6593 if (start > len)
6594 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006595 // When "count" argument is there ignore matches before "start",
6596 // otherwise skip part of the string. Differs when pattern is "^"
6597 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006598 if (argvars[3].v_type != VAR_UNKNOWN)
6599 startcol = start;
6600 else
6601 {
6602 str += start;
6603 len -= start;
6604 }
6605 }
6606
6607 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006608 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006609 if (error)
6610 goto theend;
6611 }
6612
6613 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6614 if (regmatch.regprog != NULL)
6615 {
6616 regmatch.rm_ic = p_ic;
6617
6618 for (;;)
6619 {
6620 if (l != NULL)
6621 {
6622 if (li == NULL)
6623 {
6624 match = FALSE;
6625 break;
6626 }
6627 vim_free(tofree);
6628 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6629 if (str == NULL)
6630 break;
6631 }
6632
6633 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6634
6635 if (match && --nth <= 0)
6636 break;
6637 if (l == NULL && !match)
6638 break;
6639
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006640 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 if (l != NULL)
6642 {
6643 li = li->li_next;
6644 ++idx;
6645 }
6646 else
6647 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006648 startcol = (colnr_T)(regmatch.startp[0]
6649 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650 if (startcol > (colnr_T)len
6651 || str + startcol <= regmatch.startp[0])
6652 {
6653 match = FALSE;
6654 break;
6655 }
6656 }
6657 }
6658
6659 if (match)
6660 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006661 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006662 {
6663 listitem_T *li1 = rettv->vval.v_list->lv_first;
6664 listitem_T *li2 = li1->li_next;
6665 listitem_T *li3 = li2->li_next;
6666 listitem_T *li4 = li3->li_next;
6667
6668 vim_free(li1->li_tv.vval.v_string);
6669 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02006670 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006671 li3->li_tv.vval.v_number =
6672 (varnumber_T)(regmatch.startp[0] - expr);
6673 li4->li_tv.vval.v_number =
6674 (varnumber_T)(regmatch.endp[0] - expr);
6675 if (l != NULL)
6676 li2->li_tv.vval.v_number = (varnumber_T)idx;
6677 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006678 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006679 {
6680 int i;
6681
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006682 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683 for (i = 0; i < NSUBEXP; ++i)
6684 {
6685 if (regmatch.endp[i] == NULL)
6686 {
6687 if (list_append_string(rettv->vval.v_list,
6688 (char_u *)"", 0) == FAIL)
6689 break;
6690 }
6691 else if (list_append_string(rettv->vval.v_list,
6692 regmatch.startp[i],
6693 (int)(regmatch.endp[i] - regmatch.startp[i]))
6694 == FAIL)
6695 break;
6696 }
6697 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006698 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006700 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 if (l != NULL)
6702 copy_tv(&li->li_tv, rettv);
6703 else
6704 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02006705 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006706 }
6707 else if (l != NULL)
6708 rettv->vval.v_number = idx;
6709 else
6710 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006711 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006712 rettv->vval.v_number =
6713 (varnumber_T)(regmatch.startp[0] - str);
6714 else
6715 rettv->vval.v_number =
6716 (varnumber_T)(regmatch.endp[0] - str);
6717 rettv->vval.v_number += (varnumber_T)(str - expr);
6718 }
6719 }
6720 vim_regfree(regmatch.regprog);
6721 }
6722
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006723theend:
6724 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006725 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 listitem_remove(rettv->vval.v_list,
6727 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006728 vim_free(tofree);
6729 p_cpo = save_cpo;
6730}
6731
6732/*
6733 * "match()" function
6734 */
6735 static void
6736f_match(typval_T *argvars, typval_T *rettv)
6737{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006738 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739}
6740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741/*
6742 * "matchend()" function
6743 */
6744 static void
6745f_matchend(typval_T *argvars, typval_T *rettv)
6746{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006747 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006748}
6749
6750/*
6751 * "matchlist()" function
6752 */
6753 static void
6754f_matchlist(typval_T *argvars, typval_T *rettv)
6755{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006756 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006757}
6758
6759/*
6760 * "matchstr()" function
6761 */
6762 static void
6763f_matchstr(typval_T *argvars, typval_T *rettv)
6764{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006765 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006766}
6767
6768/*
6769 * "matchstrpos()" function
6770 */
6771 static void
6772f_matchstrpos(typval_T *argvars, typval_T *rettv)
6773{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006774 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006775}
6776
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006777 static void
6778max_min(typval_T *argvars, typval_T *rettv, int domax)
6779{
6780 varnumber_T n = 0;
6781 varnumber_T i;
6782 int error = FALSE;
6783
6784 if (argvars[0].v_type == VAR_LIST)
6785 {
6786 list_T *l;
6787 listitem_T *li;
6788
6789 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006790 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006791 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006792 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006793 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006794 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
6795 n = l->lv_u.nonmat.lv_start;
6796 else
6797 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
6798 * l->lv_u.nonmat.lv_stride;
6799 }
6800 else
6801 {
6802 li = l->lv_first;
6803 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006805 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaarab65fc72021-02-04 22:07:16 +01006806 if (error)
6807 return; // type error; errmsg already given
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006808 for (;;)
6809 {
6810 li = li->li_next;
6811 if (li == NULL)
6812 break;
6813 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaarab65fc72021-02-04 22:07:16 +01006814 if (error)
6815 return; // type error; errmsg already given
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01006816 if (domax ? i > n : i < n)
6817 n = i;
6818 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006819 }
6820 }
6821 }
6822 }
6823 else if (argvars[0].v_type == VAR_DICT)
6824 {
6825 dict_T *d;
6826 int first = TRUE;
6827 hashitem_T *hi;
6828 int todo;
6829
6830 d = argvars[0].vval.v_dict;
6831 if (d != NULL)
6832 {
6833 todo = (int)d->dv_hashtab.ht_used;
6834 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
6835 {
6836 if (!HASHITEM_EMPTY(hi))
6837 {
6838 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006839 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaarab65fc72021-02-04 22:07:16 +01006840 if (error)
6841 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842 if (first)
6843 {
6844 n = i;
6845 first = FALSE;
6846 }
6847 else if (domax ? i > n : i < n)
6848 n = i;
6849 }
6850 }
6851 }
6852 }
6853 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006854 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaarab65fc72021-02-04 22:07:16 +01006855
6856 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006857}
6858
6859/*
6860 * "max()" function
6861 */
6862 static void
6863f_max(typval_T *argvars, typval_T *rettv)
6864{
6865 max_min(argvars, rettv, TRUE);
6866}
6867
6868/*
6869 * "min()" function
6870 */
6871 static void
6872f_min(typval_T *argvars, typval_T *rettv)
6873{
6874 max_min(argvars, rettv, FALSE);
6875}
6876
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877#if defined(FEAT_MZSCHEME) || defined(PROTO)
6878/*
6879 * "mzeval()" function
6880 */
6881 static void
6882f_mzeval(typval_T *argvars, typval_T *rettv)
6883{
6884 char_u *str;
6885 char_u buf[NUMBUFLEN];
6886
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006887 if (check_restricted() || check_secure())
6888 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006889 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006890 do_mzeval(str, rettv);
6891}
6892
6893 void
6894mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
6895{
6896 typval_T argvars[3];
6897
6898 argvars[0].v_type = VAR_STRING;
6899 argvars[0].vval.v_string = name;
6900 copy_tv(args, &argvars[1]);
6901 argvars[2].v_type = VAR_UNKNOWN;
6902 f_call(argvars, rettv);
6903 clear_tv(&argvars[1]);
6904}
6905#endif
6906
6907/*
6908 * "nextnonblank()" function
6909 */
6910 static void
6911f_nextnonblank(typval_T *argvars, typval_T *rettv)
6912{
6913 linenr_T lnum;
6914
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006915 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916 {
6917 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
6918 {
6919 lnum = 0;
6920 break;
6921 }
6922 if (*skipwhite(ml_get(lnum)) != NUL)
6923 break;
6924 }
6925 rettv->vval.v_number = lnum;
6926}
6927
6928/*
6929 * "nr2char()" function
6930 */
6931 static void
6932f_nr2char(typval_T *argvars, typval_T *rettv)
6933{
6934 char_u buf[NUMBUFLEN];
6935
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 if (has_mbyte)
6937 {
6938 int utf8 = 0;
6939
6940 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaared6a4302020-09-05 20:29:41 +02006941 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006942 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01006943 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006944 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006945 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006946 }
6947 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006949 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950 buf[1] = NUL;
6951 }
6952 rettv->v_type = VAR_STRING;
6953 rettv->vval.v_string = vim_strsave(buf);
6954}
6955
6956/*
6957 * "or(expr, expr)" function
6958 */
6959 static void
6960f_or(typval_T *argvars, typval_T *rettv)
6961{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006962 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
6963 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006964}
6965
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966#ifdef FEAT_PERL
6967/*
6968 * "perleval()" function
6969 */
6970 static void
6971f_perleval(typval_T *argvars, typval_T *rettv)
6972{
6973 char_u *str;
6974 char_u buf[NUMBUFLEN];
6975
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006976 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006977 do_perleval(str, rettv);
6978}
6979#endif
6980
6981#ifdef FEAT_FLOAT
6982/*
6983 * "pow()" function
6984 */
6985 static void
6986f_pow(typval_T *argvars, typval_T *rettv)
6987{
6988 float_T fx = 0.0, fy = 0.0;
6989
6990 rettv->v_type = VAR_FLOAT;
6991 if (get_float_arg(argvars, &fx) == OK
6992 && get_float_arg(&argvars[1], &fy) == OK)
6993 rettv->vval.v_float = pow(fx, fy);
6994 else
6995 rettv->vval.v_float = 0.0;
6996}
6997#endif
6998
6999/*
7000 * "prevnonblank()" function
7001 */
7002 static void
7003f_prevnonblank(typval_T *argvars, typval_T *rettv)
7004{
7005 linenr_T lnum;
7006
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007007 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007008 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7009 lnum = 0;
7010 else
7011 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7012 --lnum;
7013 rettv->vval.v_number = lnum;
7014}
7015
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007016// This dummy va_list is here because:
7017// - passing a NULL pointer doesn't work when va_list isn't a pointer
7018// - locally in the function results in a "used before set" warning
7019// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007020static va_list ap;
7021
7022/*
7023 * "printf()" function
7024 */
7025 static void
7026f_printf(typval_T *argvars, typval_T *rettv)
7027{
7028 char_u buf[NUMBUFLEN];
7029 int len;
7030 char_u *s;
7031 int saved_did_emsg = did_emsg;
7032 char *fmt;
7033
7034 rettv->v_type = VAR_STRING;
7035 rettv->vval.v_string = NULL;
7036
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007037 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007039 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007040 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007041 if (!did_emsg)
7042 {
7043 s = alloc(len + 1);
7044 if (s != NULL)
7045 {
7046 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007047 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7048 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007049 }
7050 }
7051 did_emsg |= saved_did_emsg;
7052}
7053
7054/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007055 * "pum_getpos()" function
7056 */
7057 static void
7058f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7059{
7060 if (rettv_dict_alloc(rettv) != OK)
7061 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007062 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007063}
7064
7065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007066 * "pumvisible()" function
7067 */
7068 static void
7069f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7070{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 if (pum_visible())
7072 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007073}
7074
7075#ifdef FEAT_PYTHON3
7076/*
7077 * "py3eval()" function
7078 */
7079 static void
7080f_py3eval(typval_T *argvars, typval_T *rettv)
7081{
7082 char_u *str;
7083 char_u buf[NUMBUFLEN];
7084
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007085 if (check_restricted() || check_secure())
7086 return;
7087
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007088 if (p_pyx == 0)
7089 p_pyx = 3;
7090
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007091 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 do_py3eval(str, rettv);
7093}
7094#endif
7095
7096#ifdef FEAT_PYTHON
7097/*
7098 * "pyeval()" function
7099 */
7100 static void
7101f_pyeval(typval_T *argvars, typval_T *rettv)
7102{
7103 char_u *str;
7104 char_u buf[NUMBUFLEN];
7105
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007106 if (check_restricted() || check_secure())
7107 return;
7108
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007109 if (p_pyx == 0)
7110 p_pyx = 2;
7111
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007112 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007113 do_pyeval(str, rettv);
7114}
7115#endif
7116
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007117#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7118/*
7119 * "pyxeval()" function
7120 */
7121 static void
7122f_pyxeval(typval_T *argvars, typval_T *rettv)
7123{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007124 if (check_restricted() || check_secure())
7125 return;
7126
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007127# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7128 init_pyxversion();
7129 if (p_pyx == 2)
7130 f_pyeval(argvars, rettv);
7131 else
7132 f_py3eval(argvars, rettv);
7133# elif defined(FEAT_PYTHON)
7134 f_pyeval(argvars, rettv);
7135# elif defined(FEAT_PYTHON3)
7136 f_py3eval(argvars, rettv);
7137# endif
7138}
7139#endif
7140
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007141static UINT32_T srand_seed_for_testing = 0;
7142static int srand_seed_for_testing_is_used = FALSE;
7143
7144 static void
7145f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
7146{
7147 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007148 srand_seed_for_testing_is_used = FALSE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007149 else
7150 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007151 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
7152 srand_seed_for_testing_is_used = TRUE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007153 }
7154}
7155
7156 static void
7157init_srand(UINT32_T *x)
7158{
7159#ifndef MSWIN
7160 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
7161#endif
7162
7163 if (srand_seed_for_testing_is_used)
7164 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007165 *x = srand_seed_for_testing;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007166 return;
7167 }
7168#ifndef MSWIN
7169 if (dev_urandom_state != FAIL)
7170 {
7171 int fd = open("/dev/urandom", O_RDONLY);
7172 struct {
7173 union {
7174 UINT32_T number;
7175 char bytes[sizeof(UINT32_T)];
7176 } contents;
7177 } buf;
7178
7179 // Attempt reading /dev/urandom.
7180 if (fd == -1)
7181 dev_urandom_state = FAIL;
7182 else
7183 {
7184 buf.contents.number = 0;
7185 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
7186 != sizeof(UINT32_T))
7187 dev_urandom_state = FAIL;
7188 else
7189 {
7190 dev_urandom_state = OK;
7191 *x = buf.contents.number;
7192 }
7193 close(fd);
7194 }
7195 }
7196 if (dev_urandom_state != OK)
7197 // Reading /dev/urandom doesn't work, fall back to time().
7198#endif
7199 *x = vim_time();
7200}
7201
7202#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
7203#define SPLITMIX32(x, z) ( \
7204 z = (x += 0x9e3779b9), \
7205 z = (z ^ (z >> 16)) * 0x85ebca6b, \
7206 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
7207 z ^ (z >> 16) \
7208 )
7209#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
7210 result = ROTL(y * 5, 7) * 9; \
7211 t = y << 9; \
7212 z ^= x; \
7213 w ^= y; \
7214 y ^= z, x ^= w; \
7215 z ^= t; \
7216 w = ROTL(w, 11);
7217
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007219 * "rand()" function
7220 */
7221 static void
7222f_rand(typval_T *argvars, typval_T *rettv)
7223{
7224 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007225 static UINT32_T gx, gy, gz, gw;
7226 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007227 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar0fd797e2020-11-05 20:46:32 +01007228 UINT32_T x = 0, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007229
7230 if (argvars[0].v_type == VAR_UNKNOWN)
7231 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007232 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007233 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007234 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007235 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007236 init_srand(&x);
7237
7238 gx = SPLITMIX32(x, z);
7239 gy = SPLITMIX32(x, z);
7240 gz = SPLITMIX32(x, z);
7241 gw = SPLITMIX32(x, z);
7242 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007243 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007244
7245 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007246 }
7247 else if (argvars[0].v_type == VAR_LIST)
7248 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007249 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007250 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007251 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007252
7253 lx = list_find(l, 0L);
7254 ly = list_find(l, 1L);
7255 lz = list_find(l, 2L);
7256 lw = list_find(l, 3L);
7257 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
7258 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
7259 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
7260 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
7261 x = (UINT32_T)lx->li_tv.vval.v_number;
7262 y = (UINT32_T)ly->li_tv.vval.v_number;
7263 z = (UINT32_T)lz->li_tv.vval.v_number;
7264 w = (UINT32_T)lw->li_tv.vval.v_number;
7265
7266 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
7267
7268 lx->li_tv.vval.v_number = (varnumber_T)x;
7269 ly->li_tv.vval.v_number = (varnumber_T)y;
7270 lz->li_tv.vval.v_number = (varnumber_T)z;
7271 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007272 }
7273 else
7274 goto theend;
7275
7276 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007277 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007278 return;
7279
7280theend:
7281 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007282 rettv->v_type = VAR_NUMBER;
7283 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007284}
7285
7286/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01007287 * "srand()" function
7288 */
7289 static void
7290f_srand(typval_T *argvars, typval_T *rettv)
7291{
7292 UINT32_T x = 0, z;
7293
7294 if (rettv_list_alloc(rettv) == FAIL)
7295 return;
7296 if (argvars[0].v_type == VAR_UNKNOWN)
7297 {
7298 init_srand(&x);
7299 }
7300 else
7301 {
7302 int error = FALSE;
7303
7304 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
7305 if (error)
7306 return;
7307 }
7308
7309 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7310 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7311 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7312 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
7313}
7314
7315#undef ROTL
7316#undef SPLITMIX32
7317#undef SHUFFLE_XOSHIRO128STARSTAR
7318
7319/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007320 * "range()" function
7321 */
7322 static void
7323f_range(typval_T *argvars, typval_T *rettv)
7324{
7325 varnumber_T start;
7326 varnumber_T end;
7327 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007328 int error = FALSE;
7329
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007330 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007331 if (argvars[1].v_type == VAR_UNKNOWN)
7332 {
7333 end = start - 1;
7334 start = 0;
7335 }
7336 else
7337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007338 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007339 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007340 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007341 }
7342
7343 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007344 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007346 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007348 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007349 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007351 list_T *list = rettv->vval.v_list;
7352
7353 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007354 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007355 // be called.
7356 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01007357 list->lv_u.nonmat.lv_start = start;
7358 list->lv_u.nonmat.lv_end = end;
7359 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007360 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007361 }
7362}
7363
7364/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007365 * Materialize "list".
7366 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007367 */
7368 void
7369range_list_materialize(list_T *list)
7370{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007371 varnumber_T start = list->lv_u.nonmat.lv_start;
7372 varnumber_T end = list->lv_u.nonmat.lv_end;
7373 int stride = list->lv_u.nonmat.lv_stride;
7374 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01007375
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007376 list->lv_first = NULL;
7377 list->lv_u.mat.lv_last = NULL;
7378 list->lv_len = 0;
7379 list->lv_u.mat.lv_idx_item = NULL;
7380 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7381 if (list_append_number(list, (varnumber_T)i) == FAIL)
7382 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383}
7384
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007385/*
7386 * "getreginfo()" function
7387 */
7388 static void
7389f_getreginfo(typval_T *argvars, typval_T *rettv)
7390{
7391 char_u *strregname;
7392 int regname;
7393 char_u buf[NUMBUFLEN + 2];
7394 long reglen = 0;
7395 dict_T *dict;
7396 list_T *list;
7397
7398 if (argvars[0].v_type != VAR_UNKNOWN)
7399 {
7400 strregname = tv_get_string_chk(&argvars[0]);
7401 if (strregname == NULL)
7402 return;
Bram Moolenaar418a29f2021-02-10 22:23:41 +01007403 if (in_vim9script() && STRLEN(strregname) > 1)
7404 {
7405 semsg(_(e_register_name_must_be_one_char_str), strregname);
7406 return;
7407 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007408 }
7409 else
7410 strregname = get_vim_var_str(VV_REG);
7411
7412 regname = (strregname == NULL ? '"' : *strregname);
7413 if (regname == 0 || regname == '@')
7414 regname = '"';
7415
7416 if (rettv_dict_alloc(rettv) == FAIL)
7417 return;
7418 dict = rettv->vval.v_dict;
7419
7420 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
7421 if (list == NULL)
7422 return;
Bram Moolenaar91639192020-06-29 19:55:58 +02007423 (void)dict_add_list(dict, "regcontents", list);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007424
7425 buf[0] = NUL;
7426 buf[1] = NUL;
7427 switch (get_reg_type(regname, &reglen))
7428 {
7429 case MLINE: buf[0] = 'V'; break;
7430 case MCHAR: buf[0] = 'v'; break;
7431 case MBLOCK:
7432 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
7433 reglen + 1);
7434 break;
7435 }
Bram Moolenaar91639192020-06-29 19:55:58 +02007436 (void)dict_add_string(dict, (char *)"regtype", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007437
7438 buf[0] = get_register_name(get_unname_register());
7439 buf[1] = NUL;
7440 if (regname == '"')
Bram Moolenaar91639192020-06-29 19:55:58 +02007441 (void)dict_add_string(dict, (char *)"points_to", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007442 else
7443 {
7444 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
7445
7446 if (item != NULL)
7447 {
7448 item->di_tv.v_type = VAR_SPECIAL;
7449 item->di_tv.vval.v_number = regname == buf[0]
Bram Moolenaar418a29f2021-02-10 22:23:41 +01007450 ? VVAL_TRUE : VVAL_FALSE;
Bram Moolenaar91639192020-06-29 19:55:58 +02007451 (void)dict_add(dict, item);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007452 }
7453 }
7454}
7455
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02007456 static void
7457return_register(int regname, typval_T *rettv)
7458{
7459 char_u buf[2] = {0, 0};
7460
7461 buf[0] = (char_u)regname;
7462 rettv->v_type = VAR_STRING;
7463 rettv->vval.v_string = vim_strsave(buf);
7464}
7465
7466/*
7467 * "reg_executing()" function
7468 */
7469 static void
7470f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
7471{
7472 return_register(reg_executing, rettv);
7473}
7474
7475/*
7476 * "reg_recording()" function
7477 */
7478 static void
7479f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
7480{
7481 return_register(reg_recording, rettv);
7482}
7483
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01007484/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007485 * "rename({from}, {to})" function
7486 */
7487 static void
7488f_rename(typval_T *argvars, typval_T *rettv)
7489{
7490 char_u buf[NUMBUFLEN];
7491
7492 if (check_restricted() || check_secure())
7493 rettv->vval.v_number = -1;
7494 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007495 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
7496 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007497}
7498
7499/*
7500 * "repeat()" function
7501 */
7502 static void
7503f_repeat(typval_T *argvars, typval_T *rettv)
7504{
7505 char_u *p;
7506 int n;
7507 int slen;
7508 int len;
7509 char_u *r;
7510 int i;
7511
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007512 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513 if (argvars[0].v_type == VAR_LIST)
7514 {
7515 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
7516 while (n-- > 0)
7517 if (list_extend(rettv->vval.v_list,
7518 argvars[0].vval.v_list, NULL) == FAIL)
7519 break;
7520 }
7521 else
7522 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007523 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524 rettv->v_type = VAR_STRING;
7525 rettv->vval.v_string = NULL;
7526
7527 slen = (int)STRLEN(p);
7528 len = slen * n;
7529 if (len <= 0)
7530 return;
7531
7532 r = alloc(len + 1);
7533 if (r != NULL)
7534 {
7535 for (i = 0; i < n; i++)
7536 mch_memmove(r + i * slen, p, (size_t)slen);
7537 r[len] = NUL;
7538 }
7539
7540 rettv->vval.v_string = r;
7541 }
7542}
7543
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007544#define SP_NOMOVE 0x01 // don't move cursor
7545#define SP_REPEAT 0x02 // repeat to find outer pair
7546#define SP_RETCOUNT 0x04 // return matchcount
7547#define SP_SETPCMARK 0x08 // set previous context mark
7548#define SP_START 0x10 // accept match at start position
7549#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
7550#define SP_END 0x40 // leave cursor at end of match
7551#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007553/*
7554 * Get flags for a search function.
7555 * Possibly sets "p_ws".
7556 * Returns BACKWARD, FORWARD or zero (for an error).
7557 */
7558 static int
7559get_search_arg(typval_T *varp, int *flagsp)
7560{
7561 int dir = FORWARD;
7562 char_u *flags;
7563 char_u nbuf[NUMBUFLEN];
7564 int mask;
7565
7566 if (varp->v_type != VAR_UNKNOWN)
7567 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007568 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007569 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007570 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007571 while (*flags != NUL)
7572 {
7573 switch (*flags)
7574 {
7575 case 'b': dir = BACKWARD; break;
7576 case 'w': p_ws = TRUE; break;
7577 case 'W': p_ws = FALSE; break;
7578 default: mask = 0;
7579 if (flagsp != NULL)
7580 switch (*flags)
7581 {
7582 case 'c': mask = SP_START; break;
7583 case 'e': mask = SP_END; break;
7584 case 'm': mask = SP_RETCOUNT; break;
7585 case 'n': mask = SP_NOMOVE; break;
7586 case 'p': mask = SP_SUBPAT; break;
7587 case 'r': mask = SP_REPEAT; break;
7588 case 's': mask = SP_SETPCMARK; break;
7589 case 'z': mask = SP_COLUMN; break;
7590 }
7591 if (mask == 0)
7592 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007593 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007594 dir = 0;
7595 }
7596 else
7597 *flagsp |= mask;
7598 }
7599 if (dir == 0)
7600 break;
7601 ++flags;
7602 }
7603 }
7604 return dir;
7605}
7606
7607/*
7608 * Shared by search() and searchpos() functions.
7609 */
7610 static int
7611search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
7612{
7613 int flags;
7614 char_u *pat;
7615 pos_T pos;
7616 pos_T save_cursor;
7617 int save_p_ws = p_ws;
7618 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007619 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007620 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007621#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007622 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007623 long time_limit = 0;
7624#endif
7625 int options = SEARCH_KEEP;
7626 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007627 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02007628 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007629 pos_T firstpos;
7630
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007631 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007632 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633 if (dir == 0)
7634 goto theend;
7635 flags = *flagsp;
7636 if (flags & SP_START)
7637 options |= SEARCH_START;
7638 if (flags & SP_END)
7639 options |= SEARCH_END;
7640 if (flags & SP_COLUMN)
7641 options |= SEARCH_COL;
7642
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007643 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007644 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
7645 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007646 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 if (lnum_stop < 0)
7648 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649 if (argvars[3].v_type != VAR_UNKNOWN)
7650 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007651#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007652 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653 if (time_limit < 0)
7654 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02007656 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007657 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007658 }
7659
7660#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007661 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007662 profile_setlimit(time_limit, &tm);
7663#endif
7664
7665 /*
7666 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
7667 * Check to make sure only those flags are set.
7668 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
7669 * flags cannot be set. Check for that condition also.
7670 */
7671 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
7672 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007674 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007675 goto theend;
7676 }
7677
7678 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007679 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02007680 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007681 sia.sa_stop_lnum = (linenr_T)lnum_stop;
7682#ifdef FEAT_RELTIME
7683 sia.sa_tm = &tm;
7684#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007685
7686 // Repeat until {skip} returns FALSE.
7687 for (;;)
7688 {
7689 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007690 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007691 // finding the first match again means there is no match where {skip}
7692 // evaluates to zero.
7693 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
7694 subpatnum = FAIL;
7695
Bram Moolenaara9c01042020-06-07 14:50:50 +02007696 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007697 // didn't find it or no skip argument
7698 break;
7699 firstpos = pos;
7700
Bram Moolenaara9c01042020-06-07 14:50:50 +02007701 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007702 {
7703 int do_skip;
7704 int err;
7705 pos_T save_pos = curwin->w_cursor;
7706
7707 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02007708 err = FALSE;
7709 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02007710 curwin->w_cursor = save_pos;
7711 if (err)
7712 {
7713 // Evaluating {skip} caused an error, break here.
7714 subpatnum = FAIL;
7715 break;
7716 }
7717 if (!do_skip)
7718 break;
7719 }
7720 }
7721
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722 if (subpatnum != FAIL)
7723 {
7724 if (flags & SP_SUBPAT)
7725 retval = subpatnum;
7726 else
7727 retval = pos.lnum;
7728 if (flags & SP_SETPCMARK)
7729 setpcmark();
7730 curwin->w_cursor = pos;
7731 if (match_pos != NULL)
7732 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007733 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007734 match_pos->lnum = pos.lnum;
7735 match_pos->col = pos.col + 1;
7736 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007737 // "/$" will put the cursor after the end of the line, may need to
7738 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007739 check_cursor();
7740 }
7741
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007742 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007743 if (flags & SP_NOMOVE)
7744 curwin->w_cursor = save_cursor;
7745 else
7746 curwin->w_set_curswant = TRUE;
7747theend:
7748 p_ws = save_p_ws;
7749
7750 return retval;
7751}
7752
7753#ifdef FEAT_FLOAT
7754
7755/*
7756 * round() is not in C90, use ceil() or floor() instead.
7757 */
7758 float_T
7759vim_round(float_T f)
7760{
7761 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
7762}
7763
7764/*
7765 * "round({float})" function
7766 */
7767 static void
7768f_round(typval_T *argvars, typval_T *rettv)
7769{
7770 float_T f = 0.0;
7771
7772 rettv->v_type = VAR_FLOAT;
7773 if (get_float_arg(argvars, &f) == OK)
7774 rettv->vval.v_float = vim_round(f);
7775 else
7776 rettv->vval.v_float = 0.0;
7777}
7778#endif
7779
Bram Moolenaare99be0e2019-03-26 22:51:09 +01007780#ifdef FEAT_RUBY
7781/*
7782 * "rubyeval()" function
7783 */
7784 static void
7785f_rubyeval(typval_T *argvars, typval_T *rettv)
7786{
7787 char_u *str;
7788 char_u buf[NUMBUFLEN];
7789
7790 str = tv_get_string_buf(&argvars[0], buf);
7791 do_rubyeval(str, rettv);
7792}
7793#endif
7794
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795/*
7796 * "screenattr()" function
7797 */
7798 static void
7799f_screenattr(typval_T *argvars, typval_T *rettv)
7800{
7801 int row;
7802 int col;
7803 int c;
7804
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007805 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7806 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807 if (row < 0 || row >= screen_Rows
7808 || col < 0 || col >= screen_Columns)
7809 c = -1;
7810 else
7811 c = ScreenAttrs[LineOffset[row] + col];
7812 rettv->vval.v_number = c;
7813}
7814
7815/*
7816 * "screenchar()" function
7817 */
7818 static void
7819f_screenchar(typval_T *argvars, typval_T *rettv)
7820{
7821 int row;
7822 int col;
7823 int off;
7824 int c;
7825
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007826 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7827 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007828 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007829 c = -1;
7830 else
7831 {
7832 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007833 if (enc_utf8 && ScreenLinesUC[off] != 0)
7834 c = ScreenLinesUC[off];
7835 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007836 c = ScreenLines[off];
7837 }
7838 rettv->vval.v_number = c;
7839}
7840
7841/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007842 * "screenchars()" function
7843 */
7844 static void
7845f_screenchars(typval_T *argvars, typval_T *rettv)
7846{
7847 int row;
7848 int col;
7849 int off;
7850 int c;
7851 int i;
7852
7853 if (rettv_list_alloc(rettv) == FAIL)
7854 return;
7855 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7856 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7857 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7858 return;
7859
7860 off = LineOffset[row] + col;
7861 if (enc_utf8 && ScreenLinesUC[off] != 0)
7862 c = ScreenLinesUC[off];
7863 else
7864 c = ScreenLines[off];
7865 list_append_number(rettv->vval.v_list, (varnumber_T)c);
7866
7867 if (enc_utf8)
7868
7869 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7870 list_append_number(rettv->vval.v_list,
7871 (varnumber_T)ScreenLinesC[i][off]);
7872}
7873
7874/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875 * "screencol()" function
7876 *
7877 * First column is 1 to be consistent with virtcol().
7878 */
7879 static void
7880f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
7881{
7882 rettv->vval.v_number = screen_screencol() + 1;
7883}
7884
7885/*
7886 * "screenrow()" function
7887 */
7888 static void
7889f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
7890{
7891 rettv->vval.v_number = screen_screenrow() + 1;
7892}
7893
7894/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007895 * "screenstring()" function
7896 */
7897 static void
7898f_screenstring(typval_T *argvars, typval_T *rettv)
7899{
7900 int row;
7901 int col;
7902 int off;
7903 int c;
7904 int i;
7905 char_u buf[MB_MAXBYTES + 1];
7906 int buflen = 0;
7907
7908 rettv->vval.v_string = NULL;
7909 rettv->v_type = VAR_STRING;
7910
7911 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7912 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7913 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7914 return;
7915
7916 off = LineOffset[row] + col;
7917 if (enc_utf8 && ScreenLinesUC[off] != 0)
7918 c = ScreenLinesUC[off];
7919 else
7920 c = ScreenLines[off];
7921 buflen += mb_char2bytes(c, buf);
7922
Bram Moolenaarf1387282021-03-22 17:11:15 +01007923 if (enc_utf8 && ScreenLinesUC[off] != 0)
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007924 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7925 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
7926
7927 buf[buflen] = NUL;
7928 rettv->vval.v_string = vim_strsave(buf);
7929}
7930
7931/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007932 * "search()" function
7933 */
7934 static void
7935f_search(typval_T *argvars, typval_T *rettv)
7936{
7937 int flags = 0;
7938
7939 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
7940}
7941
7942/*
7943 * "searchdecl()" function
7944 */
7945 static void
7946f_searchdecl(typval_T *argvars, typval_T *rettv)
7947{
Bram Moolenaar30788d32020-09-05 21:35:16 +02007948 int locally = TRUE;
7949 int thisblock = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950 int error = FALSE;
7951 char_u *name;
7952
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007953 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007955 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007956 if (argvars[1].v_type != VAR_UNKNOWN)
7957 {
Bram Moolenaar30788d32020-09-05 21:35:16 +02007958 locally = !(int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007959 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar30788d32020-09-05 21:35:16 +02007960 thisblock = (int)tv_get_bool_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007961 }
7962 if (!error && name != NULL)
7963 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
7964 locally, thisblock, SEARCH_KEEP) == FAIL;
7965}
7966
7967/*
7968 * Used by searchpair() and searchpairpos()
7969 */
7970 static int
7971searchpair_cmn(typval_T *argvars, pos_T *match_pos)
7972{
7973 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01007974 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007975 int save_p_ws = p_ws;
7976 int dir;
7977 int flags = 0;
7978 char_u nbuf1[NUMBUFLEN];
7979 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007980 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007981 long lnum_stop = 0;
7982 long time_limit = 0;
7983
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007984 // Get the three pattern arguments: start, middle, end. Will result in an
7985 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007986 spat = tv_get_string_chk(&argvars[0]);
7987 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
7988 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007989 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007990 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007992 // Handle the optional fourth argument: flags
7993 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007994 if (dir == 0)
7995 goto theend;
7996
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007997 // Don't accept SP_END or SP_SUBPAT.
7998 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007999 if ((flags & (SP_END | SP_SUBPAT)) != 0
8000 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8001 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008002 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 goto theend;
8004 }
8005
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008006 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007 if (flags & SP_REPEAT)
8008 p_ws = FALSE;
8009
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008010 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011 if (argvars[3].v_type == VAR_UNKNOWN
8012 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01008013 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008014 else
8015 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02008016 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01008017 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02008018
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019 if (argvars[5].v_type != VAR_UNKNOWN)
8020 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008021 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008022 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02008023 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008024 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008025 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02008026 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008027#ifdef FEAT_RELTIME
8028 if (argvars[6].v_type != VAR_UNKNOWN)
8029 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008030 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008031 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02008032 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008033 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008034 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02008035 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008036 }
8037#endif
8038 }
8039 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008040
8041 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
8042 match_pos, lnum_stop, time_limit);
8043
8044theend:
8045 p_ws = save_p_ws;
8046
8047 return retval;
8048}
8049
8050/*
8051 * "searchpair()" function
8052 */
8053 static void
8054f_searchpair(typval_T *argvars, typval_T *rettv)
8055{
8056 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
8057}
8058
8059/*
8060 * "searchpairpos()" function
8061 */
8062 static void
8063f_searchpairpos(typval_T *argvars, typval_T *rettv)
8064{
8065 pos_T match_pos;
8066 int lnum = 0;
8067 int col = 0;
8068
8069 if (rettv_list_alloc(rettv) == FAIL)
8070 return;
8071
8072 if (searchpair_cmn(argvars, &match_pos) > 0)
8073 {
8074 lnum = match_pos.lnum;
8075 col = match_pos.col;
8076 }
8077
8078 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8079 list_append_number(rettv->vval.v_list, (varnumber_T)col);
8080}
8081
8082/*
8083 * Search for a start/middle/end thing.
8084 * Used by searchpair(), see its documentation for the details.
8085 * Returns 0 or -1 for no match,
8086 */
8087 long
8088do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008089 char_u *spat, // start pattern
8090 char_u *mpat, // middle pattern
8091 char_u *epat, // end pattern
8092 int dir, // BACKWARD or FORWARD
8093 typval_T *skip, // skip expression
8094 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008096 linenr_T lnum_stop, // stop at this line if not zero
8097 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008098{
8099 char_u *save_cpo;
8100 char_u *pat, *pat2 = NULL, *pat3 = NULL;
8101 long retval = 0;
8102 pos_T pos;
8103 pos_T firstpos;
8104 pos_T foundpos;
8105 pos_T save_cursor;
8106 pos_T save_pos;
8107 int n;
8108 int r;
8109 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01008110 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008111 int err;
8112 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02008113#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008114 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02008115#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008117 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118 save_cpo = p_cpo;
8119 p_cpo = empty_option;
8120
8121#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008122 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008123 profile_setlimit(time_limit, &tm);
8124#endif
8125
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008126 // Make two search patterns: start/end (pat2, for in nested pairs) and
8127 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02008128 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
8129 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 if (pat2 == NULL || pat3 == NULL)
8131 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01008132 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133 if (*mpat == NUL)
8134 STRCPY(pat3, pat2);
8135 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01008136 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137 spat, epat, mpat);
8138 if (flags & SP_START)
8139 options |= SEARCH_START;
8140
Bram Moolenaar48570482017-10-30 21:48:41 +01008141 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02008142 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01008143
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008144 save_cursor = curwin->w_cursor;
8145 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01008146 CLEAR_POS(&firstpos);
8147 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148 pat = pat3;
8149 for (;;)
8150 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02008151 searchit_arg_T sia;
8152
Bram Moolenaara80faa82020-04-12 19:37:17 +02008153 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02008154 sia.sa_stop_lnum = lnum_stop;
8155#ifdef FEAT_RELTIME
8156 sia.sa_tm = &tm;
8157#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01008158 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02008159 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01008160 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008161 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008162 break;
8163
8164 if (firstpos.lnum == 0)
8165 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01008166 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008168 // Found the same position again. Can happen with a pattern that
8169 // has "\zs" at the end and searching backwards. Advance one
8170 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008171 if (dir == BACKWARD)
8172 decl(&pos);
8173 else
8174 incl(&pos);
8175 }
8176 foundpos = pos;
8177
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008178 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 options &= ~SEARCH_START;
8180
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008181 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01008182 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008183 {
8184 save_pos = curwin->w_cursor;
8185 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01008186 err = FALSE;
8187 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 curwin->w_cursor = save_pos;
8189 if (err)
8190 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008191 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192 curwin->w_cursor = save_cursor;
8193 retval = -1;
8194 break;
8195 }
8196 if (r)
8197 continue;
8198 }
8199
8200 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
8201 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008202 // Found end when searching backwards or start when searching
8203 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008204 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008205 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008206 }
8207 else
8208 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008209 // Found end when searching forward or start when searching
8210 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008211 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008212 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 }
8214
8215 if (nest == 0)
8216 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008217 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008218 if (flags & SP_RETCOUNT)
8219 ++retval;
8220 else
8221 retval = pos.lnum;
8222 if (flags & SP_SETPCMARK)
8223 setpcmark();
8224 curwin->w_cursor = pos;
8225 if (!(flags & SP_REPEAT))
8226 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008227 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008228 }
8229 }
8230
8231 if (match_pos != NULL)
8232 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008233 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008234 match_pos->lnum = curwin->w_cursor.lnum;
8235 match_pos->col = curwin->w_cursor.col + 1;
8236 }
8237
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008238 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239 if ((flags & SP_NOMOVE) || retval == 0)
8240 curwin->w_cursor = save_cursor;
8241
8242theend:
8243 vim_free(pat2);
8244 vim_free(pat3);
8245 if (p_cpo == empty_option)
8246 p_cpo = save_cpo;
8247 else
Bram Moolenaare5a2dc82021-01-03 19:52:05 +01008248 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008249 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaare5a2dc82021-01-03 19:52:05 +01008250 // If it's still empty it was changed and restored, need to restore in
8251 // the complicated way.
8252 if (*p_cpo == NUL)
8253 set_option_value((char_u *)"cpo", 0L, save_cpo, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008254 free_string_option(save_cpo);
Bram Moolenaare5a2dc82021-01-03 19:52:05 +01008255 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008256
8257 return retval;
8258}
8259
8260/*
8261 * "searchpos()" function
8262 */
8263 static void
8264f_searchpos(typval_T *argvars, typval_T *rettv)
8265{
8266 pos_T match_pos;
8267 int lnum = 0;
8268 int col = 0;
8269 int n;
8270 int flags = 0;
8271
8272 if (rettv_list_alloc(rettv) == FAIL)
8273 return;
8274
8275 n = search_cmn(argvars, &match_pos, &flags);
8276 if (n > 0)
8277 {
8278 lnum = match_pos.lnum;
8279 col = match_pos.col;
8280 }
8281
8282 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
8283 list_append_number(rettv->vval.v_list, (varnumber_T)col);
8284 if (flags & SP_SUBPAT)
8285 list_append_number(rettv->vval.v_list, (varnumber_T)n);
8286}
8287
Bram Moolenaar6f02b002021-01-10 20:22:54 +01008288/*
8289 * Set the cursor or mark position.
8290 * If 'charpos' is TRUE, then use the column number as a character offet.
8291 * Otherwise use the column number as a byte offset.
8292 */
8293 static void
8294set_position(typval_T *argvars, typval_T *rettv, int charpos)
8295{
8296 pos_T pos;
8297 int fnum;
8298 char_u *name;
8299 colnr_T curswant = -1;
8300
8301 rettv->vval.v_number = -1;
8302
8303 name = tv_get_string_chk(argvars);
8304 if (name != NULL)
8305 {
8306 if (list2fpos(&argvars[1], &pos, &fnum, &curswant, charpos) == OK)
8307 {
8308 if (pos.col != MAXCOL && --pos.col < 0)
8309 pos.col = 0;
8310 if ((name[0] == '.' && name[1] == NUL))
8311 {
8312 // set cursor; "fnum" is ignored
8313 curwin->w_cursor = pos;
8314 if (curswant >= 0)
8315 {
8316 curwin->w_curswant = curswant - 1;
8317 curwin->w_set_curswant = FALSE;
8318 }
8319 check_cursor();
8320 rettv->vval.v_number = 0;
8321 }
8322 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
8323 {
8324 // set mark
8325 if (setmark_pos(name[1], &pos, fnum) == OK)
8326 rettv->vval.v_number = 0;
8327 }
8328 else
8329 emsg(_(e_invarg));
8330 }
8331 }
8332}
8333/*
8334 * "setcharpos()" function
8335 */
8336 static void
8337f_setcharpos(typval_T *argvars, typval_T *rettv)
8338{
8339 set_position(argvars, rettv, TRUE);
8340}
8341
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008343f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
8344{
8345 dict_T *d;
8346 dictitem_T *di;
8347 char_u *csearch;
8348
8349 if (argvars[0].v_type != VAR_DICT)
8350 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008351 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008352 return;
8353 }
8354
8355 if ((d = argvars[0].vval.v_dict) != NULL)
8356 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01008357 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008358 if (csearch != NULL)
8359 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008360 if (enc_utf8)
8361 {
8362 int pcc[MAX_MCO];
8363 int c = utfc_ptr2char(csearch, pcc);
8364
8365 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
8366 }
8367 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008368 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02008369 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008370 }
8371
8372 di = dict_find(d, (char_u *)"forward", -1);
8373 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008374 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008375 ? FORWARD : BACKWARD);
8376
8377 di = dict_find(d, (char_u *)"until", -1);
8378 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008379 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008380 }
8381}
8382
8383/*
Bram Moolenaar6f02b002021-01-10 20:22:54 +01008384 * "setcursorcharpos" function
8385 */
8386 static void
Bram Moolenaar3af15ab2021-01-17 16:16:23 +01008387f_setcursorcharpos(typval_T *argvars, typval_T *rettv)
Bram Moolenaar6f02b002021-01-10 20:22:54 +01008388{
8389 set_cursorpos(argvars, rettv, TRUE);
8390}
8391
8392/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02008393 * "setenv()" function
8394 */
8395 static void
8396f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
8397{
8398 char_u namebuf[NUMBUFLEN];
8399 char_u valbuf[NUMBUFLEN];
8400 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
8401
8402 if (argvars[1].v_type == VAR_SPECIAL
8403 && argvars[1].vval.v_number == VVAL_NULL)
8404 vim_unsetenv(name);
8405 else
8406 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
8407}
8408
8409/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008410 * "setfperm({fname}, {mode})" function
8411 */
8412 static void
8413f_setfperm(typval_T *argvars, typval_T *rettv)
8414{
8415 char_u *fname;
8416 char_u modebuf[NUMBUFLEN];
8417 char_u *mode_str;
8418 int i;
8419 int mask;
8420 int mode = 0;
8421
8422 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008423 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008424 if (fname == NULL)
8425 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008426 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008427 if (mode_str == NULL)
8428 return;
8429 if (STRLEN(mode_str) != 9)
8430 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008431 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008432 return;
8433 }
8434
8435 mask = 1;
8436 for (i = 8; i >= 0; --i)
8437 {
8438 if (mode_str[i] != '-')
8439 mode |= mask;
8440 mask = mask << 1;
8441 }
8442 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
8443}
8444
8445/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008446 * "setpos()" function
8447 */
8448 static void
8449f_setpos(typval_T *argvars, typval_T *rettv)
8450{
Bram Moolenaar6f02b002021-01-10 20:22:54 +01008451 set_position(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008452}
8453
8454/*
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008455 * Translate a register type string to the yank type and block length
8456 */
8457 static int
8458get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
8459{
8460 char_u *stropt = *pp;
8461 switch (*stropt)
8462 {
8463 case 'v': case 'c': // character-wise selection
8464 *yank_type = MCHAR;
8465 break;
8466 case 'V': case 'l': // line-wise selection
8467 *yank_type = MLINE;
8468 break;
8469 case 'b': case Ctrl_V: // block-wise selection
8470 *yank_type = MBLOCK;
8471 if (VIM_ISDIGIT(stropt[1]))
8472 {
8473 ++stropt;
8474 *block_len = getdigits(&stropt) - 1;
8475 --stropt;
8476 }
8477 break;
8478 default:
8479 return FAIL;
8480 }
8481 *pp = stropt;
8482 return OK;
8483}
8484
8485/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008486 * "setreg()" function
8487 */
8488 static void
8489f_setreg(typval_T *argvars, typval_T *rettv)
8490{
8491 int regname;
8492 char_u *strregname;
8493 char_u *stropt;
8494 char_u *strval;
8495 int append;
8496 char_u yank_type;
8497 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008498 typval_T *regcontents;
8499 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008500
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008501 pointreg = 0;
8502 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008503 block_len = -1;
8504 yank_type = MAUTO;
8505 append = FALSE;
8506
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008507 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008508 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008509
8510 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008511 return; // type error; errmsg already given
Bram Moolenaar418a29f2021-02-10 22:23:41 +01008512 if (in_vim9script() && STRLEN(strregname) > 1)
8513 {
8514 semsg(_(e_register_name_must_be_one_char_str), strregname);
8515 return;
8516 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008517 regname = *strregname;
8518 if (regname == 0 || regname == '@')
8519 regname = '"';
8520
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008521 if (argvars[1].v_type == VAR_DICT)
8522 {
8523 dict_T *d = argvars[1].vval.v_dict;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008524 dictitem_T *di;
8525
8526 if (d == NULL || d->dv_hashtab.ht_used == 0)
8527 {
8528 // Empty dict, clear the register (like setreg(0, []))
8529 char_u *lstval[2] = {NULL, NULL};
8530 write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
8531 return;
8532 }
8533
8534 di = dict_find(d, (char_u *)"regcontents", -1);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008535 if (di != NULL)
8536 regcontents = &di->di_tv;
8537
8538 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
8539 if (stropt != NULL)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008540 {
8541 int ret = get_yank_type(&stropt, &yank_type, &block_len);
8542
8543 if (ret == FAIL || *++stropt != NUL)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008544 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008545 semsg(_(e_invargval), "value");
8546 return;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008547 }
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008548 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008549
8550 if (regname == '"')
8551 {
8552 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
8553 if (stropt != NULL)
8554 {
8555 pointreg = *stropt;
8556 regname = pointreg;
8557 }
8558 }
Bram Moolenaar6a950582020-08-28 16:39:33 +02008559 else if (dict_get_bool(d, (char_u *)"isunnamed", -1) > 0)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008560 pointreg = regname;
8561 }
8562 else
8563 regcontents = &argvars[1];
8564
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008565 if (argvars[2].v_type != VAR_UNKNOWN)
8566 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008567 if (yank_type != MAUTO)
8568 {
8569 semsg(_(e_toomanyarg), "setreg");
8570 return;
8571 }
8572
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008573 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008574 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008575 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008576 for (; *stropt != NUL; ++stropt)
8577 switch (*stropt)
8578 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008579 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008580 append = TRUE;
8581 break;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02008582 default:
8583 get_yank_type(&stropt, &yank_type, &block_len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008584 }
8585 }
8586
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008587 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008588 {
8589 char_u **lstval;
8590 char_u **allocval;
8591 char_u buf[NUMBUFLEN];
8592 char_u **curval;
8593 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008594 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595 listitem_T *li;
8596 int len;
8597
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008598 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008599 len = ll == NULL ? 0 : ll->lv_len;
8600
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008601 // First half: use for pointers to result lines; second half: use for
8602 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008603 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008604 if (lstval == NULL)
8605 return;
8606 curval = lstval;
8607 allocval = lstval + len + 2;
8608 curallocval = allocval;
8609
Bram Moolenaar50985eb2020-01-27 22:09:39 +01008610 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008611 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02008612 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02008613 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008614 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01008615 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008616 if (strval == NULL)
8617 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01008618 if (strval == buf)
8619 {
8620 // Need to make a copy, next tv_get_string_buf_chk() will
8621 // overwrite the string.
8622 strval = vim_strsave(buf);
8623 if (strval == NULL)
8624 goto free_lstval;
8625 *curallocval++ = strval;
8626 }
8627 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008628 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008629 }
8630 *curval++ = NULL;
8631
8632 write_reg_contents_lst(regname, lstval, -1,
8633 append, yank_type, block_len);
8634free_lstval:
8635 while (curallocval > allocval)
8636 vim_free(*--curallocval);
8637 vim_free(lstval);
8638 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008639 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008640 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008641 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008642 if (strval == NULL)
8643 return;
8644 write_reg_contents_ex(regname, strval, -1,
8645 append, yank_type, block_len);
8646 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02008647 if (pointreg != 0)
8648 get_yank_register(pointreg, TRUE);
8649
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008650 rettv->vval.v_number = 0;
8651}
8652
8653/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008654 * "settagstack()" function
8655 */
8656 static void
8657f_settagstack(typval_T *argvars, typval_T *rettv)
8658{
8659 static char *e_invact2 = N_("E962: Invalid action: '%s'");
8660 win_T *wp;
8661 dict_T *d;
8662 int action = 'r';
8663
8664 rettv->vval.v_number = -1;
8665
8666 // first argument: window number or id
8667 wp = find_win_by_nr_or_id(&argvars[0]);
8668 if (wp == NULL)
8669 return;
8670
8671 // second argument: dict with items to set in the tag stack
8672 if (argvars[1].v_type != VAR_DICT)
8673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008674 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008675 return;
8676 }
8677 d = argvars[1].vval.v_dict;
8678 if (d == NULL)
8679 return;
8680
8681 // third argument: action - 'a' for append and 'r' for replace.
8682 // default is to replace the stack.
8683 if (argvars[2].v_type == VAR_UNKNOWN)
8684 action = 'r';
8685 else if (argvars[2].v_type == VAR_STRING)
8686 {
8687 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008688 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008689 if (actstr == NULL)
8690 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01008691 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
8692 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008693 action = *actstr;
8694 else
8695 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008696 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008697 return;
8698 }
8699 }
8700 else
8701 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008702 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008703 return;
8704 }
8705
8706 if (set_tagstack(wp, d, action) == OK)
8707 rettv->vval.v_number = 0;
8708}
8709
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008710#ifdef FEAT_CRYPT
8711/*
8712 * "sha256({string})" function
8713 */
8714 static void
8715f_sha256(typval_T *argvars, typval_T *rettv)
8716{
8717 char_u *p;
8718
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008719 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 rettv->vval.v_string = vim_strsave(
8721 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
8722 rettv->v_type = VAR_STRING;
8723}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008724#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008725
8726/*
8727 * "shellescape({string})" function
8728 */
8729 static void
8730f_shellescape(typval_T *argvars, typval_T *rettv)
8731{
Bram Moolenaar20615522017-06-05 18:46:26 +02008732 int do_special = non_zero_arg(&argvars[1]);
8733
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008734 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008735 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008736 rettv->v_type = VAR_STRING;
8737}
8738
8739/*
8740 * shiftwidth() function
8741 */
8742 static void
8743f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
8744{
Bram Moolenaarf9514162018-11-22 03:08:29 +01008745 rettv->vval.v_number = 0;
8746
8747 if (argvars[0].v_type != VAR_UNKNOWN)
8748 {
8749 long col;
8750
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008751 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01008752 if (col < 0)
8753 return; // type error; errmsg already given
8754#ifdef FEAT_VARTABS
8755 rettv->vval.v_number = get_sw_value_col(curbuf, col);
8756 return;
8757#endif
8758 }
8759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008760 rettv->vval.v_number = get_sw_value(curbuf);
8761}
8762
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008763#ifdef FEAT_FLOAT
8764/*
8765 * "sin()" function
8766 */
8767 static void
8768f_sin(typval_T *argvars, typval_T *rettv)
8769{
8770 float_T f = 0.0;
8771
8772 rettv->v_type = VAR_FLOAT;
8773 if (get_float_arg(argvars, &f) == OK)
8774 rettv->vval.v_float = sin(f);
8775 else
8776 rettv->vval.v_float = 0.0;
8777}
8778
8779/*
8780 * "sinh()" function
8781 */
8782 static void
8783f_sinh(typval_T *argvars, typval_T *rettv)
8784{
8785 float_T f = 0.0;
8786
8787 rettv->v_type = VAR_FLOAT;
8788 if (get_float_arg(argvars, &f) == OK)
8789 rettv->vval.v_float = sinh(f);
8790 else
8791 rettv->vval.v_float = 0.0;
8792}
8793#endif
8794
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008795/*
8796 * "soundfold({word})" function
8797 */
8798 static void
8799f_soundfold(typval_T *argvars, typval_T *rettv)
8800{
8801 char_u *s;
8802
8803 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008804 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008805#ifdef FEAT_SPELL
8806 rettv->vval.v_string = eval_soundfold(s);
8807#else
8808 rettv->vval.v_string = vim_strsave(s);
8809#endif
8810}
8811
8812/*
8813 * "spellbadword()" function
8814 */
8815 static void
8816f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
8817{
8818 char_u *word = (char_u *)"";
8819 hlf_T attr = HLF_COUNT;
8820 int len = 0;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008821#ifdef FEAT_SPELL
8822 int wo_spell_save = curwin->w_p_spell;
8823
8824 if (!curwin->w_p_spell)
8825 {
8826 did_set_spelllang(curwin);
8827 curwin->w_p_spell = TRUE;
8828 }
8829
8830 if (*curwin->w_s->b_p_spl == NUL)
8831 {
8832 emsg(_(e_no_spell));
8833 curwin->w_p_spell = wo_spell_save;
8834 return;
8835 }
8836#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008837
8838 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008839 {
8840#ifdef FEAT_SPELL
8841 curwin->w_p_spell = wo_spell_save;
8842#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008843 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008844 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008845
8846#ifdef FEAT_SPELL
8847 if (argvars[0].v_type == VAR_UNKNOWN)
8848 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008849 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008850 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
8851 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008852 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008853 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008854 curwin->w_set_curswant = TRUE;
8855 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008856 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008857 else if (*curbuf->b_s.b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008858 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008859 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008860 int capcol = -1;
8861
8862 if (str != NULL)
8863 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008864 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008865 while (*str != NUL)
8866 {
8867 len = spell_check(curwin, str, &attr, &capcol, FALSE);
8868 if (attr != HLF_COUNT)
8869 {
8870 word = str;
8871 break;
8872 }
8873 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02008874 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02008875 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008876 }
8877 }
8878 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008879 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008880#endif
8881
8882 list_append_string(rettv->vval.v_list, word, len);
8883 list_append_string(rettv->vval.v_list, (char_u *)(
8884 attr == HLF_SPB ? "bad" :
8885 attr == HLF_SPR ? "rare" :
8886 attr == HLF_SPL ? "local" :
8887 attr == HLF_SPC ? "caps" :
8888 ""), -1);
8889}
8890
8891/*
8892 * "spellsuggest()" function
8893 */
8894 static void
8895f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
8896{
8897#ifdef FEAT_SPELL
8898 char_u *str;
8899 int typeerr = FALSE;
8900 int maxcount;
8901 garray_T ga;
8902 int i;
8903 listitem_T *li;
8904 int need_capital = FALSE;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008905 int wo_spell_save = curwin->w_p_spell;
8906
8907 if (!curwin->w_p_spell)
8908 {
8909 did_set_spelllang(curwin);
8910 curwin->w_p_spell = TRUE;
8911 }
8912
8913 if (*curwin->w_s->b_p_spl == NUL)
8914 {
8915 emsg(_(e_no_spell));
8916 curwin->w_p_spell = wo_spell_save;
8917 return;
8918 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008919#endif
8920
8921 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008922 {
8923#ifdef FEAT_SPELL
8924 curwin->w_p_spell = wo_spell_save;
8925#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008926 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008927 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008928
8929#ifdef FEAT_SPELL
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008930 if (*curwin->w_s->b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008931 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008932 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008933 if (argvars[1].v_type != VAR_UNKNOWN)
8934 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008935 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008936 if (maxcount <= 0)
8937 return;
8938 if (argvars[2].v_type != VAR_UNKNOWN)
8939 {
Bram Moolenaar7c27f332020-09-05 22:45:55 +02008940 need_capital = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008941 if (typeerr)
8942 return;
8943 }
8944 }
8945 else
8946 maxcount = 25;
8947
8948 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
8949
8950 for (i = 0; i < ga.ga_len; ++i)
8951 {
8952 str = ((char_u **)ga.ga_data)[i];
8953
8954 li = listitem_alloc();
8955 if (li == NULL)
8956 vim_free(str);
8957 else
8958 {
8959 li->li_tv.v_type = VAR_STRING;
8960 li->li_tv.v_lock = 0;
8961 li->li_tv.vval.v_string = str;
8962 list_append(rettv->vval.v_list, li);
8963 }
8964 }
8965 ga_clear(&ga);
8966 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02008967 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008968#endif
8969}
8970
8971 static void
8972f_split(typval_T *argvars, typval_T *rettv)
8973{
8974 char_u *str;
8975 char_u *end;
8976 char_u *pat = NULL;
8977 regmatch_T regmatch;
8978 char_u patbuf[NUMBUFLEN];
8979 char_u *save_cpo;
8980 int match;
8981 colnr_T col = 0;
8982 int keepempty = FALSE;
8983 int typeerr = FALSE;
8984
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008985 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008986 save_cpo = p_cpo;
Bram Moolenaare5a2dc82021-01-03 19:52:05 +01008987 p_cpo = empty_option;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008988
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008989 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008990 if (argvars[1].v_type != VAR_UNKNOWN)
8991 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008992 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008993 if (pat == NULL)
8994 typeerr = TRUE;
8995 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar3986b942020-09-06 16:09:04 +02008996 keepempty = (int)tv_get_bool_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008997 }
8998 if (pat == NULL || *pat == NUL)
8999 pat = (char_u *)"[\\x01- ]\\+";
9000
9001 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02009002 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009003 if (typeerr)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02009004 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009005
9006 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
9007 if (regmatch.regprog != NULL)
9008 {
9009 regmatch.rm_ic = FALSE;
9010 while (*str != NUL || keepempty)
9011 {
9012 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009013 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009014 else
9015 match = vim_regexec_nl(&regmatch, str, col);
9016 if (match)
9017 end = regmatch.startp[0];
9018 else
9019 end = str + STRLEN(str);
9020 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
9021 && *str != NUL && match && end < regmatch.endp[0]))
9022 {
9023 if (list_append_string(rettv->vval.v_list, str,
9024 (int)(end - str)) == FAIL)
9025 break;
9026 }
9027 if (!match)
9028 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01009029 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009030 if (regmatch.endp[0] > str)
9031 col = 0;
9032 else
Bram Moolenaar13505972019-01-24 15:04:48 +01009033 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009034 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009035 str = regmatch.endp[0];
9036 }
9037
9038 vim_regfree(regmatch.regprog);
9039 }
9040
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02009041theend:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009042 p_cpo = save_cpo;
9043}
9044
9045#ifdef FEAT_FLOAT
9046/*
9047 * "sqrt()" function
9048 */
9049 static void
9050f_sqrt(typval_T *argvars, typval_T *rettv)
9051{
9052 float_T f = 0.0;
9053
9054 rettv->v_type = VAR_FLOAT;
9055 if (get_float_arg(argvars, &f) == OK)
9056 rettv->vval.v_float = sqrt(f);
9057 else
9058 rettv->vval.v_float = 0.0;
9059}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01009060#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009061
Bram Moolenaar0387cae2019-11-29 21:07:58 +01009062#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01009063/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009064 * "str2float()" function
9065 */
9066 static void
9067f_str2float(typval_T *argvars, typval_T *rettv)
9068{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009069 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01009070 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009071
Bram Moolenaar08243d22017-01-10 16:12:29 +01009072 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009073 p = skipwhite(p + 1);
9074 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01009075 if (isneg)
9076 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009077 rettv->v_type = VAR_FLOAT;
9078}
9079#endif
9080
9081/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02009082 * "str2list()" function
9083 */
9084 static void
9085f_str2list(typval_T *argvars, typval_T *rettv)
9086{
9087 char_u *p;
9088 int utf8 = FALSE;
9089
9090 if (rettv_list_alloc(rettv) == FAIL)
9091 return;
9092
9093 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaara48f7862020-09-05 20:16:57 +02009094 utf8 = (int)tv_get_bool_chk(&argvars[1], NULL);
Bram Moolenaar9d401282019-04-06 13:18:12 +02009095
9096 p = tv_get_string(&argvars[0]);
9097
9098 if (has_mbyte || utf8)
9099 {
9100 int (*ptr2len)(char_u *);
9101 int (*ptr2char)(char_u *);
9102
9103 if (utf8 || enc_utf8)
9104 {
9105 ptr2len = utf_ptr2len;
9106 ptr2char = utf_ptr2char;
9107 }
9108 else
9109 {
9110 ptr2len = mb_ptr2len;
9111 ptr2char = mb_ptr2char;
9112 }
9113
9114 for ( ; *p != NUL; p += (*ptr2len)(p))
9115 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
9116 }
9117 else
9118 for ( ; *p != NUL; ++p)
9119 list_append_number(rettv->vval.v_list, *p);
9120}
9121
9122/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009123 * "str2nr()" function
9124 */
9125 static void
9126f_str2nr(typval_T *argvars, typval_T *rettv)
9127{
9128 int base = 10;
9129 char_u *p;
9130 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02009131 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01009132 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009133
9134 if (argvars[1].v_type != VAR_UNKNOWN)
9135 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009136 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009137 if (base != 2 && base != 8 && base != 10 && base != 16)
9138 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009139 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009140 return;
9141 }
Bram Moolenaar3986b942020-09-06 16:09:04 +02009142 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2]))
Bram Moolenaar60a8de22019-09-15 14:33:22 +02009143 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009144 }
9145
Bram Moolenaarf2b26bc2021-01-30 23:05:11 +01009146 p = skipwhite(tv_get_string_strict(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01009147 isneg = (*p == '-');
9148 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009149 p = skipwhite(p + 1);
9150 switch (base)
9151 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02009152 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02009153 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02009154 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009155 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02009156 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
9157 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01009158 if (isneg)
9159 rettv->vval.v_number = -n;
9160 else
9161 rettv->vval.v_number = n;
9162
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009163}
9164
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009165/*
9166 * "strgetchar()" function
9167 */
9168 static void
9169f_strgetchar(typval_T *argvars, typval_T *rettv)
9170{
9171 char_u *str;
9172 int len;
9173 int error = FALSE;
9174 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01009175 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009176
9177 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009178 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009179 if (str == NULL)
9180 return;
9181 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009182 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009183 if (error)
9184 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009185
Bram Moolenaar13505972019-01-24 15:04:48 +01009186 while (charidx >= 0 && byteidx < len)
9187 {
9188 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009189 {
Bram Moolenaar13505972019-01-24 15:04:48 +01009190 rettv->vval.v_number = mb_ptr2char(str + byteidx);
9191 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009192 }
Bram Moolenaar13505972019-01-24 15:04:48 +01009193 --charidx;
9194 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009195 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009196}
9197
9198/*
9199 * "stridx()" function
9200 */
9201 static void
9202f_stridx(typval_T *argvars, typval_T *rettv)
9203{
9204 char_u buf[NUMBUFLEN];
9205 char_u *needle;
9206 char_u *haystack;
9207 char_u *save_haystack;
9208 char_u *pos;
9209 int start_idx;
9210
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009211 needle = tv_get_string_chk(&argvars[1]);
9212 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009213 rettv->vval.v_number = -1;
9214 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009215 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009216
9217 if (argvars[2].v_type != VAR_UNKNOWN)
9218 {
9219 int error = FALSE;
9220
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009221 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009222 if (error || start_idx >= (int)STRLEN(haystack))
9223 return;
9224 if (start_idx >= 0)
9225 haystack += start_idx;
9226 }
9227
9228 pos = (char_u *)strstr((char *)haystack, (char *)needle);
9229 if (pos != NULL)
9230 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
9231}
9232
9233/*
9234 * "string()" function
9235 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01009236 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009237f_string(typval_T *argvars, typval_T *rettv)
9238{
9239 char_u *tofree;
9240 char_u numbuf[NUMBUFLEN];
9241
9242 rettv->v_type = VAR_STRING;
9243 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
9244 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009245 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009246 if (rettv->vval.v_string != NULL && tofree == NULL)
9247 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
9248}
9249
9250/*
9251 * "strlen()" function
9252 */
9253 static void
9254f_strlen(typval_T *argvars, typval_T *rettv)
9255{
9256 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009257 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009258}
9259
Bram Moolenaar70ce8a12021-03-14 19:02:09 +01009260 static void
9261strchar_common(typval_T *argvars, typval_T *rettv, int skipcc)
9262{
9263 char_u *s = tv_get_string(&argvars[0]);
9264 varnumber_T len = 0;
9265 int (*func_mb_ptr2char_adv)(char_u **pp);
9266
9267 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
9268 while (*s != NUL)
9269 {
9270 func_mb_ptr2char_adv(&s);
9271 ++len;
9272 }
9273 rettv->vval.v_number = len;
9274}
9275
9276/*
9277 * "strcharlen()" function
9278 */
9279 static void
9280f_strcharlen(typval_T *argvars, typval_T *rettv)
9281{
9282 strchar_common(argvars, rettv, TRUE);
9283}
9284
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009285/*
9286 * "strchars()" function
9287 */
9288 static void
9289f_strchars(typval_T *argvars, typval_T *rettv)
9290{
Bram Moolenaar239f8d92021-01-17 13:21:20 +01009291 varnumber_T skipcc = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009292
9293 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaar239f8d92021-01-17 13:21:20 +01009294 skipcc = tv_get_bool(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009295 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarbade44e2020-09-26 22:39:24 +02009296 semsg(_(e_using_number_as_bool_nr), skipcc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009297 else
Bram Moolenaar70ce8a12021-03-14 19:02:09 +01009298 strchar_common(argvars, rettv, skipcc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009299}
9300
9301/*
9302 * "strdisplaywidth()" function
9303 */
9304 static void
9305f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
9306{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009307 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009308 int col = 0;
9309
9310 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009311 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009312
9313 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
9314}
9315
9316/*
9317 * "strwidth()" function
9318 */
9319 static void
9320f_strwidth(typval_T *argvars, typval_T *rettv)
9321{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009322 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009323
Bram Moolenaar13505972019-01-24 15:04:48 +01009324 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009325}
9326
9327/*
9328 * "strcharpart()" function
9329 */
9330 static void
9331f_strcharpart(typval_T *argvars, typval_T *rettv)
9332{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009333 char_u *p;
9334 int nchar;
9335 int nbyte = 0;
9336 int charlen;
Bram Moolenaar02b4d9b2021-03-14 19:46:45 +01009337 int skipcc = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009338 int len = 0;
9339 int slen;
9340 int error = FALSE;
9341
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009342 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009343 slen = (int)STRLEN(p);
9344
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009345 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009346 if (!error)
9347 {
Bram Moolenaar02b4d9b2021-03-14 19:46:45 +01009348 if (argvars[2].v_type != VAR_UNKNOWN
9349 && argvars[3].v_type != VAR_UNKNOWN)
9350 {
9351 skipcc = tv_get_bool(&argvars[3]);
9352 if (skipcc < 0 || skipcc > 1)
9353 {
9354 semsg(_(e_using_number_as_bool_nr), skipcc);
9355 return;
9356 }
9357 }
9358
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009359 if (nchar > 0)
9360 while (nchar > 0 && nbyte < slen)
9361 {
Bram Moolenaar02b4d9b2021-03-14 19:46:45 +01009362 if (skipcc)
9363 nbyte += mb_ptr2len(p + nbyte);
9364 else
9365 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009366 --nchar;
9367 }
9368 else
9369 nbyte = nchar;
9370 if (argvars[2].v_type != VAR_UNKNOWN)
9371 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009372 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009373 while (charlen > 0 && nbyte + len < slen)
9374 {
9375 int off = nbyte + len;
9376
9377 if (off < 0)
9378 len += 1;
9379 else
Bram Moolenaar02b4d9b2021-03-14 19:46:45 +01009380 {
9381 if (skipcc)
9382 len += mb_ptr2len(p + off);
9383 else
9384 len += MB_CPTR2LEN(p + off);
9385 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009386 --charlen;
9387 }
9388 }
9389 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009390 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009391 }
9392
9393 /*
9394 * Only return the overlap between the specified part and the actual
9395 * string.
9396 */
9397 if (nbyte < 0)
9398 {
9399 len += nbyte;
9400 nbyte = 0;
9401 }
9402 else if (nbyte > slen)
9403 nbyte = slen;
9404 if (len < 0)
9405 len = 0;
9406 else if (nbyte + len > slen)
9407 len = slen - nbyte;
9408
9409 rettv->v_type = VAR_STRING;
9410 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009411}
9412
9413/*
9414 * "strpart()" function
9415 */
9416 static void
9417f_strpart(typval_T *argvars, typval_T *rettv)
9418{
9419 char_u *p;
9420 int n;
9421 int len;
9422 int slen;
9423 int error = FALSE;
9424
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009425 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009426 slen = (int)STRLEN(p);
9427
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009428 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009429 if (error)
9430 len = 0;
9431 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009432 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009433 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009434 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009435
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02009436 // Only return the overlap between the specified part and the actual
9437 // string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009438 if (n < 0)
9439 {
9440 len += n;
9441 n = 0;
9442 }
9443 else if (n > slen)
9444 n = slen;
9445 if (len < 0)
9446 len = 0;
9447 else if (n + len > slen)
9448 len = slen - n;
9449
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02009450 if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN)
9451 {
9452 int off;
9453
9454 // length in characters
9455 for (off = n; off < slen && len > 0; --len)
9456 off += mb_ptr2len(p + off);
9457 len = off - n;
9458 }
9459
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009460 rettv->v_type = VAR_STRING;
9461 rettv->vval.v_string = vim_strnsave(p + n, len);
9462}
9463
9464/*
9465 * "strridx()" function
9466 */
9467 static void
9468f_strridx(typval_T *argvars, typval_T *rettv)
9469{
9470 char_u buf[NUMBUFLEN];
9471 char_u *needle;
9472 char_u *haystack;
9473 char_u *rest;
9474 char_u *lastmatch = NULL;
9475 int haystack_len, end_idx;
9476
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009477 needle = tv_get_string_chk(&argvars[1]);
9478 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009479
9480 rettv->vval.v_number = -1;
9481 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009482 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009483
9484 haystack_len = (int)STRLEN(haystack);
9485 if (argvars[2].v_type != VAR_UNKNOWN)
9486 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009487 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009488 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009489 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009490 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009491 }
9492 else
9493 end_idx = haystack_len;
9494
9495 if (*needle == NUL)
9496 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009497 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009498 lastmatch = haystack + end_idx;
9499 }
9500 else
9501 {
9502 for (rest = haystack; *rest != '\0'; ++rest)
9503 {
9504 rest = (char_u *)strstr((char *)rest, (char *)needle);
9505 if (rest == NULL || rest > haystack + end_idx)
9506 break;
9507 lastmatch = rest;
9508 }
9509 }
9510
9511 if (lastmatch == NULL)
9512 rettv->vval.v_number = -1;
9513 else
9514 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
9515}
9516
9517/*
9518 * "strtrans()" function
9519 */
9520 static void
9521f_strtrans(typval_T *argvars, typval_T *rettv)
9522{
9523 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009524 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009525}
9526
9527/*
9528 * "submatch()" function
9529 */
9530 static void
9531f_submatch(typval_T *argvars, typval_T *rettv)
9532{
9533 int error = FALSE;
9534 int no;
9535 int retList = 0;
9536
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009537 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009538 if (error)
9539 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02009540 if (no < 0 || no >= NSUBEXP)
9541 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009542 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01009543 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02009544 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009545 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaarad304702020-09-06 18:22:53 +02009546 retList = (int)tv_get_bool_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009547 if (error)
9548 return;
9549
9550 if (retList == 0)
9551 {
9552 rettv->v_type = VAR_STRING;
9553 rettv->vval.v_string = reg_submatch(no);
9554 }
9555 else
9556 {
9557 rettv->v_type = VAR_LIST;
9558 rettv->vval.v_list = reg_submatch_list(no);
9559 }
9560}
9561
9562/*
9563 * "substitute()" function
9564 */
9565 static void
9566f_substitute(typval_T *argvars, typval_T *rettv)
9567{
9568 char_u patbuf[NUMBUFLEN];
9569 char_u subbuf[NUMBUFLEN];
9570 char_u flagsbuf[NUMBUFLEN];
9571
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009572 char_u *str = tv_get_string_chk(&argvars[0]);
9573 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009574 char_u *sub = NULL;
9575 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009576 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009577
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009578 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
9579 expr = &argvars[2];
9580 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009581 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009582
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009583 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009584 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
9585 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009586 rettv->vval.v_string = NULL;
9587 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02009588 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009589}
9590
9591/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02009592 * "swapinfo(swap_filename)" function
9593 */
9594 static void
9595f_swapinfo(typval_T *argvars, typval_T *rettv)
9596{
9597 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009598 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02009599}
9600
9601/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02009602 * "swapname(expr)" function
9603 */
9604 static void
9605f_swapname(typval_T *argvars, typval_T *rettv)
9606{
9607 buf_T *buf;
9608
9609 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009610 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02009611 if (buf == NULL || buf->b_ml.ml_mfp == NULL
9612 || buf->b_ml.ml_mfp->mf_fname == NULL)
9613 rettv->vval.v_string = NULL;
9614 else
9615 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
9616}
9617
9618/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009619 * "synID(lnum, col, trans)" function
9620 */
9621 static void
9622f_synID(typval_T *argvars UNUSED, typval_T *rettv)
9623{
9624 int id = 0;
9625#ifdef FEAT_SYN_HL
9626 linenr_T lnum;
9627 colnr_T col;
9628 int trans;
9629 int transerr = FALSE;
9630
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009631 lnum = tv_get_lnum(argvars); // -1 on type error
9632 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaarfcb6d702020-09-05 21:41:56 +02009633 trans = (int)tv_get_bool_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009634
9635 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9636 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
9637 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
9638#endif
9639
9640 rettv->vval.v_number = id;
9641}
9642
9643/*
9644 * "synIDattr(id, what [, mode])" function
9645 */
9646 static void
9647f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
9648{
9649 char_u *p = NULL;
9650#ifdef FEAT_SYN_HL
9651 int id;
9652 char_u *what;
9653 char_u *mode;
9654 char_u modebuf[NUMBUFLEN];
9655 int modec;
9656
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009657 id = (int)tv_get_number(&argvars[0]);
9658 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009659 if (argvars[2].v_type != VAR_UNKNOWN)
9660 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009661 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009662 modec = TOLOWER_ASC(mode[0]);
9663 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009664 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009665 }
9666 else
9667 {
9668#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
9669 if (USE_24BIT)
9670 modec = 'g';
9671 else
9672#endif
9673 if (t_colors > 1)
9674 modec = 'c';
9675 else
9676 modec = 't';
9677 }
9678
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009679 switch (TOLOWER_ASC(what[0]))
9680 {
9681 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009682 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009683 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009684 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009685 p = highlight_has_attr(id, HL_BOLD, modec);
9686 break;
9687
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009688 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009689 p = highlight_color(id, what, modec);
9690 break;
9691
9692 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009693 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009694 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009695 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009696 p = highlight_has_attr(id, HL_ITALIC, modec);
9697 break;
9698
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009699 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02009700 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009701 break;
9702
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009703 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009704 p = highlight_has_attr(id, HL_INVERSE, modec);
9705 break;
9706
9707 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009708 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009709 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009710 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02009711 else if (TOLOWER_ASC(what[1]) == 't' &&
9712 TOLOWER_ASC(what[2]) == 'r')
9713 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009714 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009715 p = highlight_has_attr(id, HL_STANDOUT, modec);
9716 break;
9717
9718 case 'u':
Bram Moolenaar391c3622020-09-29 20:59:17 +02009719 if (TOLOWER_ASC(what[1]) == 'l') // ul
9720 p = highlight_color(id, what, modec);
9721 else if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009722 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009723 p = highlight_has_attr(id, HL_UNDERLINE, modec);
9724 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009725 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009726 p = highlight_has_attr(id, HL_UNDERCURL, modec);
9727 break;
9728 }
9729
9730 if (p != NULL)
9731 p = vim_strsave(p);
9732#endif
9733 rettv->v_type = VAR_STRING;
9734 rettv->vval.v_string = p;
9735}
9736
9737/*
9738 * "synIDtrans(id)" function
9739 */
9740 static void
9741f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
9742{
9743 int id;
9744
9745#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009746 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009747
9748 if (id > 0)
9749 id = syn_get_final_id(id);
9750 else
9751#endif
9752 id = 0;
9753
9754 rettv->vval.v_number = id;
9755}
9756
9757/*
9758 * "synconcealed(lnum, col)" function
9759 */
9760 static void
9761f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
9762{
9763#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9764 linenr_T lnum;
9765 colnr_T col;
9766 int syntax_flags = 0;
9767 int cchar;
9768 int matchid = 0;
9769 char_u str[NUMBUFLEN];
9770#endif
9771
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009772 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009773
9774#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009775 lnum = tv_get_lnum(argvars); // -1 on type error
9776 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009777
Bram Moolenaara80faa82020-04-12 19:37:17 +02009778 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009779
9780 if (rettv_list_alloc(rettv) != FAIL)
9781 {
9782 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9783 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9784 && curwin->w_p_cole > 0)
9785 {
9786 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
9787 syntax_flags = get_syntax_info(&matchid);
9788
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009789 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009790 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
9791 {
9792 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02009793 if (cchar == NUL && curwin->w_p_cole == 1)
Bram Moolenaareed9d462021-02-15 20:38:25 +01009794 cchar = (curwin->w_lcs_chars.conceal == NUL) ? ' '
9795 : curwin->w_lcs_chars.conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009796 if (cchar != NUL)
9797 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009798 if (has_mbyte)
9799 (*mb_char2bytes)(cchar, str);
9800 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009801 str[0] = cchar;
9802 }
9803 }
9804 }
9805
9806 list_append_number(rettv->vval.v_list,
9807 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009808 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009809 list_append_string(rettv->vval.v_list, str, -1);
9810 list_append_number(rettv->vval.v_list, matchid);
9811 }
9812#endif
9813}
9814
9815/*
9816 * "synstack(lnum, col)" function
9817 */
9818 static void
9819f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
9820{
9821#ifdef FEAT_SYN_HL
9822 linenr_T lnum;
9823 colnr_T col;
9824 int i;
9825 int id;
9826#endif
9827
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009828 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009829
9830#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009831 lnum = tv_get_lnum(argvars); // -1 on type error
9832 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009833
9834 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9835 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9836 && rettv_list_alloc(rettv) != FAIL)
9837 {
9838 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
9839 for (i = 0; ; ++i)
9840 {
9841 id = syn_get_stack_item(i);
9842 if (id < 0)
9843 break;
9844 if (list_append_number(rettv->vval.v_list, id) == FAIL)
9845 break;
9846 }
9847 }
9848#endif
9849}
9850
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009851/*
9852 * "tabpagebuflist()" function
9853 */
9854 static void
9855f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9856{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009857 tabpage_T *tp;
9858 win_T *wp = NULL;
9859
9860 if (argvars[0].v_type == VAR_UNKNOWN)
9861 wp = firstwin;
9862 else
9863 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009864 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009865 if (tp != NULL)
9866 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9867 }
9868 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
9869 {
9870 for (; wp != NULL; wp = wp->w_next)
9871 if (list_append_number(rettv->vval.v_list,
9872 wp->w_buffer->b_fnum) == FAIL)
9873 break;
9874 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009875}
9876
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009877/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009878 * "tagfiles()" function
9879 */
9880 static void
9881f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
9882{
9883 char_u *fname;
9884 tagname_T tn;
9885 int first;
9886
9887 if (rettv_list_alloc(rettv) == FAIL)
9888 return;
9889 fname = alloc(MAXPATHL);
9890 if (fname == NULL)
9891 return;
9892
9893 for (first = TRUE; ; first = FALSE)
9894 if (get_tagfname(&tn, first, fname) == FAIL
9895 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
9896 break;
9897 tagname_free(&tn);
9898 vim_free(fname);
9899}
9900
9901/*
9902 * "taglist()" function
9903 */
9904 static void
9905f_taglist(typval_T *argvars, typval_T *rettv)
9906{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009907 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009908 char_u *tag_pattern;
9909
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009910 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009911
9912 rettv->vval.v_number = FALSE;
9913 if (*tag_pattern == NUL)
9914 return;
9915
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009916 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009917 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009918 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009919 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009920}
9921
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009922#ifdef FEAT_FLOAT
9923/*
9924 * "tan()" function
9925 */
9926 static void
9927f_tan(typval_T *argvars, typval_T *rettv)
9928{
9929 float_T f = 0.0;
9930
9931 rettv->v_type = VAR_FLOAT;
9932 if (get_float_arg(argvars, &f) == OK)
9933 rettv->vval.v_float = tan(f);
9934 else
9935 rettv->vval.v_float = 0.0;
9936}
9937
9938/*
9939 * "tanh()" function
9940 */
9941 static void
9942f_tanh(typval_T *argvars, typval_T *rettv)
9943{
9944 float_T f = 0.0;
9945
9946 rettv->v_type = VAR_FLOAT;
9947 if (get_float_arg(argvars, &f) == OK)
9948 rettv->vval.v_float = tanh(f);
9949 else
9950 rettv->vval.v_float = 0.0;
9951}
9952#endif
9953
9954/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009955 * "tolower(string)" function
9956 */
9957 static void
9958f_tolower(typval_T *argvars, typval_T *rettv)
9959{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009960 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009961 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009962}
9963
9964/*
9965 * "toupper(string)" function
9966 */
9967 static void
9968f_toupper(typval_T *argvars, typval_T *rettv)
9969{
9970 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009971 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009972}
9973
9974/*
9975 * "tr(string, fromstr, tostr)" function
9976 */
9977 static void
9978f_tr(typval_T *argvars, typval_T *rettv)
9979{
9980 char_u *in_str;
9981 char_u *fromstr;
9982 char_u *tostr;
9983 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009984 int inlen;
9985 int fromlen;
9986 int tolen;
9987 int idx;
9988 char_u *cpstr;
9989 int cplen;
9990 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009991 char_u buf[NUMBUFLEN];
9992 char_u buf2[NUMBUFLEN];
9993 garray_T ga;
9994
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009995 in_str = tv_get_string(&argvars[0]);
9996 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
9997 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009998
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009999 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010000 rettv->v_type = VAR_STRING;
10001 rettv->vval.v_string = NULL;
10002 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010003 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010004 ga_init2(&ga, (int)sizeof(char), 80);
10005
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010006 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010007 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010008 if (STRLEN(fromstr) != STRLEN(tostr))
10009 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010010error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010011 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010012 ga_clear(&ga);
10013 return;
10014 }
10015
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010016 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010017 while (*in_str != NUL)
10018 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010019 if (has_mbyte)
10020 {
10021 inlen = (*mb_ptr2len)(in_str);
10022 cpstr = in_str;
10023 cplen = inlen;
10024 idx = 0;
10025 for (p = fromstr; *p != NUL; p += fromlen)
10026 {
10027 fromlen = (*mb_ptr2len)(p);
10028 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
10029 {
10030 for (p = tostr; *p != NUL; p += tolen)
10031 {
10032 tolen = (*mb_ptr2len)(p);
10033 if (idx-- == 0)
10034 {
10035 cplen = tolen;
10036 cpstr = p;
10037 break;
10038 }
10039 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010040 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010041 goto error;
10042 break;
10043 }
10044 ++idx;
10045 }
10046
10047 if (first && cpstr == in_str)
10048 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010049 // Check that fromstr and tostr have the same number of
10050 // (multi-byte) characters. Done only once when a character
10051 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010052 first = FALSE;
10053 for (p = tostr; *p != NUL; p += tolen)
10054 {
10055 tolen = (*mb_ptr2len)(p);
10056 --idx;
10057 }
10058 if (idx != 0)
10059 goto error;
10060 }
10061
10062 (void)ga_grow(&ga, cplen);
10063 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
10064 ga.ga_len += cplen;
10065
10066 in_str += inlen;
10067 }
10068 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010069 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010070 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010071 p = vim_strchr(fromstr, *in_str);
10072 if (p != NULL)
10073 ga_append(&ga, tostr[p - fromstr]);
10074 else
10075 ga_append(&ga, *in_str);
10076 ++in_str;
10077 }
10078 }
10079
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010080 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010081 (void)ga_grow(&ga, 1);
10082 ga_append(&ga, NUL);
10083
10084 rettv->vval.v_string = ga.ga_data;
10085}
10086
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010087/*
10088 * "trim({expr})" function
10089 */
10090 static void
10091f_trim(typval_T *argvars, typval_T *rettv)
10092{
10093 char_u buf1[NUMBUFLEN];
10094 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010095 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010096 char_u *mask = NULL;
10097 char_u *tail;
10098 char_u *prev;
10099 char_u *p;
10100 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010101 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010102
10103 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010104 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010105 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010106 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010107
10108 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010109 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010110 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010111
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010112 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010113 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010114 int error = 0;
10115
10116 // leading or trailing characters to trim
10117 dir = (int)tv_get_number_chk(&argvars[2], &error);
10118 if (error)
10119 return;
10120 if (dir < 0 || dir > 2)
10121 {
10122 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
10123 return;
10124 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010125 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010126 }
10127
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010128 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010129 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010130 // Trim leading characters
10131 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010132 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010133 c1 = PTR2CHAR(head);
10134 if (mask == NULL)
10135 {
10136 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010137 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +020010138 }
10139 else
10140 {
10141 for (p = mask; *p != NUL; MB_PTR_ADV(p))
10142 if (c1 == PTR2CHAR(p))
10143 break;
10144 if (*p == NUL)
10145 break;
10146 }
10147 MB_PTR_ADV(head);
10148 }
10149 }
10150
10151 tail = head + STRLEN(head);
10152 if (dir == 0 || dir == 2)
10153 {
10154 // Trim trailing characters
10155 for (; tail > head; tail = prev)
10156 {
10157 prev = tail;
10158 MB_PTR_BACK(head, prev);
10159 c1 = PTR2CHAR(prev);
10160 if (mask == NULL)
10161 {
10162 if (c1 > ' ' && c1 != 0xa0)
10163 break;
10164 }
10165 else
10166 {
10167 for (p = mask; *p != NUL; MB_PTR_ADV(p))
10168 if (c1 == PTR2CHAR(p))
10169 break;
10170 if (*p == NUL)
10171 break;
10172 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010173 }
10174 }
Bram Moolenaardf44a272020-06-07 20:49:05 +020010175 rettv->vval.v_string = vim_strnsave(head, tail - head);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010176}
10177
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010178#ifdef FEAT_FLOAT
10179/*
10180 * "trunc({float})" function
10181 */
10182 static void
10183f_trunc(typval_T *argvars, typval_T *rettv)
10184{
10185 float_T f = 0.0;
10186
10187 rettv->v_type = VAR_FLOAT;
10188 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010189 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010190 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
10191 else
10192 rettv->vval.v_float = 0.0;
10193}
10194#endif
10195
10196/*
10197 * "type(expr)" function
10198 */
10199 static void
10200f_type(typval_T *argvars, typval_T *rettv)
10201{
10202 int n = -1;
10203
10204 switch (argvars[0].v_type)
10205 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +010010206 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
10207 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010208 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +010010209 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
10210 case VAR_LIST: n = VAR_TYPE_LIST; break;
10211 case VAR_DICT: n = VAR_TYPE_DICT; break;
10212 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
10213 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
10214 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020010215 case VAR_JOB: n = VAR_TYPE_JOB; break;
10216 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010217 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010218 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +020010219 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010010220 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +010010221 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010222 n = -1;
10223 break;
10224 }
10225 rettv->vval.v_number = n;
10226}
10227
10228/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010229 * "virtcol(string)" function
10230 */
10231 static void
10232f_virtcol(typval_T *argvars, typval_T *rettv)
10233{
10234 colnr_T vcol = 0;
10235 pos_T *fp;
10236 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +010010237 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010238
Bram Moolenaar6f02b002021-01-10 20:22:54 +010010239 fp = var2fpos(&argvars[0], FALSE, &fnum, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010240 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
10241 && fnum == curbuf->b_fnum)
10242 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +010010243 // Limit the column to a valid value, getvvcol() doesn't check.
10244 if (fp->col < 0)
10245 fp->col = 0;
10246 else
10247 {
10248 len = (int)STRLEN(ml_get(fp->lnum));
10249 if (fp->col > len)
10250 fp->col = len;
10251 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010252 getvvcol(curwin, fp, NULL, NULL, &vcol);
10253 ++vcol;
10254 }
10255
10256 rettv->vval.v_number = vcol;
10257}
10258
10259/*
10260 * "visualmode()" function
10261 */
10262 static void
10263f_visualmode(typval_T *argvars, typval_T *rettv)
10264{
10265 char_u str[2];
10266
10267 rettv->v_type = VAR_STRING;
10268 str[0] = curbuf->b_visual_mode_eval;
10269 str[1] = NUL;
10270 rettv->vval.v_string = vim_strsave(str);
10271
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010272 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010273 if (non_zero_arg(&argvars[0]))
10274 curbuf->b_visual_mode_eval = NUL;
10275}
10276
10277/*
10278 * "wildmenumode()" function
10279 */
10280 static void
10281f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10282{
10283#ifdef FEAT_WILDMENU
10284 if (wild_menu_showing)
10285 rettv->vval.v_number = 1;
10286#endif
10287}
10288
10289/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +010010290 * "windowsversion()" function
10291 */
10292 static void
10293f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10294{
10295 rettv->v_type = VAR_STRING;
10296 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
10297}
10298
10299/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010300 * "wordcount()" function
10301 */
10302 static void
10303f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
10304{
10305 if (rettv_dict_alloc(rettv) == FAIL)
10306 return;
10307 cursor_pos_info(rettv->vval.v_dict);
10308}
10309
10310/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010311 * "xor(expr, expr)" function
10312 */
10313 static void
10314f_xor(typval_T *argvars, typval_T *rettv)
10315{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010316 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
10317 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010318}
10319
Bram Moolenaar5d18efe2019-12-01 21:11:22 +010010320#endif // FEAT_EVAL