blob: 771e393db671b8ae6b27a46bd694493e6b75f49f [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020023#ifdef FEAT_FLOAT
24static void f_abs(typval_T *argvars, typval_T *rettv);
25static void f_acos(typval_T *argvars, typval_T *rettv);
26#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028#ifdef FEAT_FLOAT
29static void f_asin(typval_T *argvars, typval_T *rettv);
30static void f_atan(typval_T *argvars, typval_T *rettv);
31static void f_atan2(typval_T *argvars, typval_T *rettv);
32#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010033#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020034static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010035static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010036# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010037static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010038# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020040static void f_byte2line(typval_T *argvars, typval_T *rettv);
41static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
42static void f_byteidx(typval_T *argvars, typval_T *rettv);
43static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
44static void f_call(typval_T *argvars, typval_T *rettv);
45#ifdef FEAT_FLOAT
46static void f_ceil(typval_T *argvars, typval_T *rettv);
47#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_changenr(typval_T *argvars, typval_T *rettv);
49static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_confirm(typval_T *argvars, typval_T *rettv);
52static void f_copy(typval_T *argvars, typval_T *rettv);
53#ifdef FEAT_FLOAT
54static void f_cos(typval_T *argvars, typval_T *rettv);
55static void f_cosh(typval_T *argvars, typval_T *rettv);
56#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010058#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020059static void f_debugbreak(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010063static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020065static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_escape(typval_T *argvars, typval_T *rettv);
67static void f_eval(typval_T *argvars, typval_T *rettv);
68static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_exists(typval_T *argvars, typval_T *rettv);
71#ifdef FEAT_FLOAT
72static void f_exp(typval_T *argvars, typval_T *rettv);
73#endif
74static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020075static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077#ifdef FEAT_FLOAT
78static void f_float2nr(typval_T *argvars, typval_T *rettv);
79static void f_floor(typval_T *argvars, typval_T *rettv);
80static void f_fmod(typval_T *argvars, typval_T *rettv);
81#endif
82static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020084static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_function(typval_T *argvars, typval_T *rettv);
86static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
87static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010088static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020090static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010092static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getpid(typval_T *argvars, typval_T *rettv);
94static void f_getcurpos(typval_T *argvars, typval_T *rettv);
95static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarbb861e22020-06-07 18:16:36 +020097static void f_getreginfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020098static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010099static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +0200100static void f_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
102static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_hlID(typval_T *argvars, typval_T *rettv);
104static void f_hlexists(typval_T *argvars, typval_T *rettv);
105static void f_hostname(typval_T *argvars, typval_T *rettv);
106static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_index(typval_T *argvars, typval_T *rettv);
108static void f_input(typval_T *argvars, typval_T *rettv);
109static void f_inputdialog(typval_T *argvars, typval_T *rettv);
110static void f_inputlist(typval_T *argvars, typval_T *rettv);
111static void f_inputrestore(typval_T *argvars, typval_T *rettv);
112static void f_inputsave(typval_T *argvars, typval_T *rettv);
113static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100114static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200115static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200116static void f_islocked(typval_T *argvars, typval_T *rettv);
117#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200118static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_isnan(typval_T *argvars, typval_T *rettv);
120#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
122static void f_len(typval_T *argvars, typval_T *rettv);
123static void f_libcall(typval_T *argvars, typval_T *rettv);
124static void f_libcallnr(typval_T *argvars, typval_T *rettv);
125static void f_line(typval_T *argvars, typval_T *rettv);
126static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127#ifdef FEAT_FLOAT
128static void f_log(typval_T *argvars, typval_T *rettv);
129static void f_log10(typval_T *argvars, typval_T *rettv);
130#endif
131#ifdef FEAT_LUA
132static void f_luaeval(typval_T *argvars, typval_T *rettv);
133#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200134static void f_maparg(typval_T *argvars, typval_T *rettv);
135static void f_mapcheck(typval_T *argvars, typval_T *rettv);
136static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_matchend(typval_T *argvars, typval_T *rettv);
138static void f_matchlist(typval_T *argvars, typval_T *rettv);
139static void f_matchstr(typval_T *argvars, typval_T *rettv);
140static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
141static void f_max(typval_T *argvars, typval_T *rettv);
142static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200143#ifdef FEAT_MZSCHEME
144static void f_mzeval(typval_T *argvars, typval_T *rettv);
145#endif
146static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
147static void f_nr2char(typval_T *argvars, typval_T *rettv);
148static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200149#ifdef FEAT_PERL
150static void f_perleval(typval_T *argvars, typval_T *rettv);
151#endif
152#ifdef FEAT_FLOAT
153static void f_pow(typval_T *argvars, typval_T *rettv);
154#endif
155static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
156static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200157static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200158static void f_pumvisible(typval_T *argvars, typval_T *rettv);
159#ifdef FEAT_PYTHON3
160static void f_py3eval(typval_T *argvars, typval_T *rettv);
161#endif
162#ifdef FEAT_PYTHON
163static void f_pyeval(typval_T *argvars, typval_T *rettv);
164#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100165#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
166static void f_pyxeval(typval_T *argvars, typval_T *rettv);
167#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100168static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100169static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200171static void f_reg_executing(typval_T *argvars, typval_T *rettv);
172static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_rename(typval_T *argvars, typval_T *rettv);
174static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175#ifdef FEAT_FLOAT
176static void f_round(typval_T *argvars, typval_T *rettv);
177#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100178#ifdef FEAT_RUBY
179static void f_rubyeval(typval_T *argvars, typval_T *rettv);
180#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200181static void f_screenattr(typval_T *argvars, typval_T *rettv);
182static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100183static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200184static void f_screencol(typval_T *argvars, typval_T *rettv);
185static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100186static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_search(typval_T *argvars, typval_T *rettv);
188static void f_searchdecl(typval_T *argvars, typval_T *rettv);
189static void f_searchpair(typval_T *argvars, typval_T *rettv);
190static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
191static void f_searchpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200193static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100197static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198#ifdef FEAT_CRYPT
199static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200200#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_shellescape(typval_T *argvars, typval_T *rettv);
202static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200203#ifdef FEAT_FLOAT
204static void f_sin(typval_T *argvars, typval_T *rettv);
205static void f_sinh(typval_T *argvars, typval_T *rettv);
206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_soundfold(typval_T *argvars, typval_T *rettv);
208static void f_spellbadword(typval_T *argvars, typval_T *rettv);
209static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
210static void f_split(typval_T *argvars, typval_T *rettv);
211#ifdef FEAT_FLOAT
212static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100213#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100214static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100215#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200216static void f_str2float(typval_T *argvars, typval_T *rettv);
217#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200218static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219static void f_str2nr(typval_T *argvars, typval_T *rettv);
220static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_strgetchar(typval_T *argvars, typval_T *rettv);
222static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200223static void f_strlen(typval_T *argvars, typval_T *rettv);
224static void f_strcharpart(typval_T *argvars, typval_T *rettv);
225static void f_strpart(typval_T *argvars, typval_T *rettv);
226static void f_strridx(typval_T *argvars, typval_T *rettv);
227static void f_strtrans(typval_T *argvars, typval_T *rettv);
228static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
229static void f_strwidth(typval_T *argvars, typval_T *rettv);
230static void f_submatch(typval_T *argvars, typval_T *rettv);
231static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200232static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200233static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_synID(typval_T *argvars, typval_T *rettv);
235static void f_synIDattr(typval_T *argvars, typval_T *rettv);
236static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
237static void f_synstack(typval_T *argvars, typval_T *rettv);
238static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200239static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_taglist(typval_T *argvars, typval_T *rettv);
241static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200242#ifdef FEAT_FLOAT
243static void f_tan(typval_T *argvars, typval_T *rettv);
244static void f_tanh(typval_T *argvars, typval_T *rettv);
245#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_tolower(typval_T *argvars, typval_T *rettv);
247static void f_toupper(typval_T *argvars, typval_T *rettv);
248static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100249static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200250#ifdef FEAT_FLOAT
251static void f_trunc(typval_T *argvars, typval_T *rettv);
252#endif
253static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200254static void f_virtcol(typval_T *argvars, typval_T *rettv);
255static void f_visualmode(typval_T *argvars, typval_T *rettv);
256static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100257static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200258static void f_wordcount(typval_T *argvars, typval_T *rettv);
259static void f_xor(typval_T *argvars, typval_T *rettv);
260
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100261
262 static type_T *
263ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
264{
265 return &t_void;
266}
267 static type_T *
268ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
269{
270 return &t_any;
271}
272 static type_T *
273ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
274{
275 return &t_number;
276}
277 static type_T *
278ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
279{
280 return &t_float;
281}
282 static type_T *
283ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
284{
285 return &t_string;
286}
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200287 static type_T *
288ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100289{
290 return &t_list_any;
291}
292 static type_T *
293ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
294{
295 return &t_list_number;
296}
297 static type_T *
298ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
299{
300 return &t_list_string;
301}
302 static type_T *
303ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
304{
305 return &t_list_dict_any;
306}
307 static type_T *
308ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
309{
310 return &t_dict_any;
311}
312 static type_T *
313ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
314{
315 return &t_dict_number;
316}
317 static type_T *
318ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
319{
320 return &t_dict_string;
321}
322 static type_T *
323ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
324{
325 return &t_blob;
326}
327 static type_T *
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200328ret_func_any(int argcount UNUSED, type_T **argtypes UNUSED)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100329{
Bram Moolenaare69f6d02020-04-01 22:11:01 +0200330 return &t_func_any;
331}
332 static type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100333ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
334{
335 return &t_channel;
336}
337 static type_T *
338ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
339{
340 return &t_job;
341}
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100342
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200343 static type_T *
344ret_first_arg(int argcount, type_T **argtypes)
345{
346 if (argcount > 0)
347 return argtypes[0];
348 return &t_void;
349}
350
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200351/*
352 * Used for getqflist(): returns list if there is no argument, dict if there is
353 * one.
354 */
355 static type_T *
356ret_list_or_dict_0(int argcount, type_T **argtypes UNUSED)
357{
358 if (argcount > 0)
359 return &t_dict_any;
360 return &t_list_dict_any;
361}
362
363/*
364 * Used for getloclist(): returns list if there is one argument, dict if there
365 * are two.
366 */
367 static type_T *
368ret_list_or_dict_1(int argcount, type_T **argtypes UNUSED)
369{
370 if (argcount > 1)
371 return &t_dict_any;
372 return &t_list_dict_any;
373}
374
Bram Moolenaar846178a2020-07-05 17:04:13 +0200375 static type_T *
376ret_argv(int argcount, type_T **argtypes UNUSED)
377{
378 // argv() returns list of strings
379 if (argcount == 0)
380 return &t_list_string;
381
382 // argv(0) returns a string, but argv(-1] returns a list
383 return &t_any;
384}
385
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200386 static type_T *
387ret_remove(int argcount UNUSED, type_T **argtypes)
388{
389 if (argtypes[0]->tt_type == VAR_LIST
390 || argtypes[0]->tt_type == VAR_DICT)
391 return argtypes[0]->tt_member;
392 if (argtypes[0]->tt_type == VAR_BLOB)
393 return &t_number;
394 return &t_any;
395}
396
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200397 static type_T *
398ret_getreg(int argcount, type_T **argtypes UNUSED)
399{
400 // Assume that if the third argument is passed it's non-zero
401 if (argcount == 3)
402 return &t_list_string;
403 return &t_string;
404}
405
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200406 static type_T *
407ret_maparg(int argcount, type_T **argtypes UNUSED)
408{
409 // Assume that if the fourth argument is passed it's non-zero
410 if (argcount == 4)
411 return &t_dict_any;
412 return &t_string;
413}
414
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100415static type_T *ret_f_function(int argcount, type_T **argtypes);
416
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200417/*
418 * Array with names and number of arguments of all internal functions
419 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
420 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200421typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200422{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200423 char *f_name; // function name
424 char f_min_argc; // minimal number of arguments
425 char f_max_argc; // maximal number of arguments
426 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100427 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
428 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200430 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200431} funcentry_T;
432
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200433// values for f_argtype; zero means it cannot be used as a method
434#define FEARG_1 1 // base is the first argument
435#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200436#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200437#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200438#define FEARG_LAST 9 // base is the last argument
439
Bram Moolenaar15c47602020-03-26 22:16:48 +0100440#ifdef FEAT_FLOAT
441# define FLOAT_FUNC(name) name
442#else
443# define FLOAT_FUNC(name) NULL
444#endif
445#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
446# define MATH_FUNC(name) name
447#else
448# define MATH_FUNC(name) NULL
449#endif
450#ifdef FEAT_TIMERS
451# define TIMER_FUNC(name) name
452#else
453# define TIMER_FUNC(name) NULL
454#endif
455#ifdef FEAT_JOB_CHANNEL
456# define JOB_FUNC(name) name
457#else
458# define JOB_FUNC(name) NULL
459#endif
460#ifdef FEAT_PROP_POPUP
461# define PROP_FUNC(name) name
462#else
463# define PROP_FUNC(name) NULL
464#endif
465#ifdef FEAT_SIGNS
466# define SIGN_FUNC(name) name
467#else
468# define SIGN_FUNC(name) NULL
469#endif
470#ifdef FEAT_SOUND
471# define SOUND_FUNC(name) name
472#else
473# define SOUND_FUNC(name) NULL
474#endif
475#ifdef FEAT_TERMINAL
476# define TERM_FUNC(name) name
477#else
478# define TERM_FUNC(name) NULL
479#endif
480
Bram Moolenaarac92e252019-08-03 21:58:38 +0200481static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200482{
Bram Moolenaar15c47602020-03-26 22:16:48 +0100483 {"abs", 1, 1, FEARG_1, ret_any, FLOAT_FUNC(f_abs)},
484 {"acos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_acos)},
Bram Moolenaarfce82b32020-07-05 16:07:21 +0200485 {"add", 2, 2, FEARG_1, ret_first_arg, f_add},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100486 {"and", 2, 2, FEARG_1, ret_number, f_and},
Bram Moolenaar389df252020-07-09 21:20:47 +0200487 {"append", 2, 2, FEARG_2, ret_number, f_append},
Bram Moolenaar92053ce2020-07-09 22:53:30 +0200488 {"appendbufline", 3, 3, FEARG_3, ret_number, f_appendbufline},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100489 {"argc", 0, 1, 0, ret_number, f_argc},
490 {"argidx", 0, 0, 0, ret_number, f_argidx},
491 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
Bram Moolenaar846178a2020-07-05 17:04:13 +0200492 {"argv", 0, 2, 0, ret_argv, f_argv},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100493 {"asin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_asin)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100494 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
495 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
Bram Moolenaarfb517ba2020-06-03 19:55:35 +0200496 {"assert_equalfile", 2, 3, FEARG_1, ret_number, f_assert_equalfile},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
Bram Moolenaar1d634542020-08-18 13:41:50 +0200498 {"assert_fails", 1, 4, FEARG_1, ret_number, f_assert_fails},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100499 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
500 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
501 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
502 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
503 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
504 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
505 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100506 {"atan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_atan)},
507 {"atan2", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_atan2)},
508 {"balloon_gettext", 0, 0, 0, ret_string,
Bram Moolenaar59716a22017-03-01 20:32:44 +0100509#ifdef FEAT_BEVAL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100510 f_balloon_gettext
511#else
512 NULL
Bram Moolenaar59716a22017-03-01 20:32:44 +0100513#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100514 },
515 {"balloon_show", 1, 1, FEARG_1, ret_void,
516#ifdef FEAT_BEVAL
517 f_balloon_show
518#else
519 NULL
520#endif
521 },
522 {"balloon_split", 1, 1, FEARG_1, ret_list_string,
523#if defined(FEAT_BEVAL_TERM)
524 f_balloon_split
525#else
526 NULL
527#endif
528 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100529 {"browse", 4, 4, 0, ret_string, f_browse},
530 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
531 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
532 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
533 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
534 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
535 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
536 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
537 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
538 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
539 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
540 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
541 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
542 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
543 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
544 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
545 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
546 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100547 {"ceil", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_ceil)},
548 {"ch_canread", 1, 1, FEARG_1, ret_number, JOB_FUNC(f_ch_canread)},
549 {"ch_close", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close)},
550 {"ch_close_in", 1, 1, FEARG_1, ret_void, JOB_FUNC(f_ch_close_in)},
551 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalexpr)},
552 {"ch_evalraw", 2, 3, FEARG_1, ret_any, JOB_FUNC(f_ch_evalraw)},
553 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, JOB_FUNC(f_ch_getbufnr)},
554 {"ch_getjob", 1, 1, FEARG_1, ret_job, JOB_FUNC(f_ch_getjob)},
555 {"ch_info", 1, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_ch_info)},
556 {"ch_log", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_log)},
557 {"ch_logfile", 1, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_logfile)},
558 {"ch_open", 1, 2, FEARG_1, ret_channel, JOB_FUNC(f_ch_open)},
559 {"ch_read", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_read)},
560 {"ch_readblob", 1, 2, FEARG_1, ret_blob, JOB_FUNC(f_ch_readblob)},
561 {"ch_readraw", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_readraw)},
562 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendexpr)},
563 {"ch_sendraw", 2, 3, FEARG_1, ret_void, JOB_FUNC(f_ch_sendraw)},
564 {"ch_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_ch_setoptions)},
565 {"ch_status", 1, 2, FEARG_1, ret_string, JOB_FUNC(f_ch_status)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100566 {"changenr", 0, 0, 0, ret_number, f_changenr},
567 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
Bram Moolenaar4e4473c2020-08-28 22:24:57 +0200568 {"charclass", 1, 1, FEARG_1, ret_number, f_charclass},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100569 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
570 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
571 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
572 {"col", 1, 1, FEARG_1, ret_number, f_col},
573 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
574 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
575 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
576 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
577 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
Bram Moolenaara66ba012020-07-05 18:41:08 +0200578 {"copy", 1, 1, FEARG_1, ret_first_arg, f_copy},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100579 {"cos", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cos)},
580 {"cosh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_cosh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100581 {"count", 2, 4, FEARG_1, ret_number, f_count},
582 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
583 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100584 {"debugbreak", 1, 1, FEARG_1, ret_number,
Bram Moolenaar4f974752019-02-17 17:44:42 +0100585#ifdef MSWIN
Bram Moolenaar15c47602020-03-26 22:16:48 +0100586 f_debugbreak
587#else
588 NULL
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200589#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100590 },
Bram Moolenaara66ba012020-07-05 18:41:08 +0200591 {"deepcopy", 1, 2, FEARG_1, ret_first_arg, f_deepcopy},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100592 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
593 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
594 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
595 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
596 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
597 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
598 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
599 {"environ", 0, 0, 0, ret_dict_string, f_environ},
600 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
601 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
602 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
603 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
604 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
605 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
606 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100607 {"exp", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_exp)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100608 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
609 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
Bram Moolenaarb3c019c2020-07-05 20:08:39 +0200610 {"extend", 2, 3, FEARG_1, ret_first_arg, f_extend},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100611 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
612 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
613 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
614 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
Bram Moolenaar0d94ad62020-07-05 20:16:41 +0200615 {"filter", 2, 2, FEARG_1, ret_first_arg, f_filter},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100616 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
617 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar077a1e62020-06-08 20:50:43 +0200618 {"flatten", 1, 2, FEARG_1, ret_list_any, f_flatten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100619 {"float2nr", 1, 1, FEARG_1, ret_number, FLOAT_FUNC(f_float2nr)},
620 {"floor", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_floor)},
621 {"fmod", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_fmod)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100622 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
623 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
624 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
625 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
626 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
627 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
628 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
629 {"foreground", 0, 0, 0, ret_void, f_foreground},
Bram Moolenaard77a8522020-04-03 21:59:57 +0200630 {"funcref", 1, 3, FEARG_1, ret_func_any, f_funcref},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100631 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
632 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
633 {"get", 2, 3, FEARG_1, ret_any, f_get},
Bram Moolenaar6434fc52020-07-18 22:24:22 +0200634 {"getbufinfo", 0, 1, FEARG_1, ret_list_dict_any, f_getbufinfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100635 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
636 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
637 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
638 {"getchar", 0, 1, 0, ret_number, f_getchar},
639 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
640 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
641 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
642 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
643 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
644 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
645 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
646 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
647 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
648 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
649 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
650 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
651 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
652 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
653 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
654 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
655 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
656 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200657 {"getloclist", 1, 2, 0, ret_list_or_dict_1, f_getloclist},
Bram Moolenaarf17e7ea2020-06-01 14:14:44 +0200658 {"getmarklist", 0, 1, FEARG_1, ret_list_dict_any, f_getmarklist},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100659 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
660 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
661 {"getpid", 0, 0, 0, ret_number, f_getpid},
662 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
Bram Moolenaarf151ad12020-06-30 13:38:01 +0200663 {"getqflist", 0, 1, 0, ret_list_or_dict_0, f_getqflist},
Bram Moolenaar3d945cc2020-08-06 21:26:59 +0200664 {"getreg", 0, 3, FEARG_1, ret_getreg, f_getreg},
Bram Moolenaarbb861e22020-06-07 18:16:36 +0200665 {"getreginfo", 0, 1, FEARG_1, ret_dict_any, f_getreginfo},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100666 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
667 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
668 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
669 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
670 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +0200671 {"gettext", 1, 1, FEARG_1, ret_string, f_gettext},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100672 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
673 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
674 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
675 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
676 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
677 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
678 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
679 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100680 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100681 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
682 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
683 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
684 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
685 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
686 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
687 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
688 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
689 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
690 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
691 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
692 {"hostname", 0, 0, 0, ret_string, f_hostname},
693 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
694 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
695 {"index", 2, 4, FEARG_1, ret_number, f_index},
696 {"input", 1, 3, FEARG_1, ret_string, f_input},
697 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
698 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
699 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
700 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
701 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
Bram Moolenaar252e88a2020-07-05 20:47:18 +0200702 {"insert", 2, 3, FEARG_1, ret_first_arg, f_insert},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100703 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
704 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
705 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100706 {"isinf", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isinf)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100707 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100708 {"isnan", 1, 1, FEARG_1, ret_number, MATH_FUNC(f_isnan)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100709 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100710 {"job_getchannel", 1, 1, FEARG_1, ret_channel, JOB_FUNC(f_job_getchannel)},
711 {"job_info", 0, 1, FEARG_1, ret_dict_any, JOB_FUNC(f_job_info)},
712 {"job_setoptions", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_job_setoptions)},
713 {"job_start", 1, 2, FEARG_1, ret_job, JOB_FUNC(f_job_start)},
714 {"job_status", 1, 1, FEARG_1, ret_string, JOB_FUNC(f_job_status)},
715 {"job_stop", 1, 2, FEARG_1, ret_number, JOB_FUNC(f_job_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100716 {"join", 1, 2, FEARG_1, ret_string, f_join},
717 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
718 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
719 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
720 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
Bram Moolenaar32f335f2020-08-14 18:56:45 +0200721 {"keys", 1, 1, FEARG_1, ret_list_string, f_keys},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100722 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
723 {"len", 1, 1, FEARG_1, ret_number, f_len},
724 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
725 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
726 {"line", 1, 2, FEARG_1, ret_number, f_line},
727 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
728 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
729 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
730 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
731 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
732 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
733 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100734 {"log", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log)},
735 {"log10", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_log10)},
736 {"luaeval", 1, 2, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200737#ifdef FEAT_LUA
Bram Moolenaar15c47602020-03-26 22:16:48 +0100738 f_luaeval
739#else
740 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200741#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100742 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100743 {"map", 2, 2, FEARG_1, ret_any, f_map},
Bram Moolenaar4a6d1b62020-08-08 17:55:49 +0200744 {"maparg", 1, 4, FEARG_1, ret_maparg, f_maparg},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100745 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
Bram Moolenaar4c9243f2020-05-22 13:10:44 +0200746 {"mapset", 3, 3, FEARG_1, ret_void, f_mapset},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100747 {"match", 2, 4, FEARG_1, ret_any, f_match},
748 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
749 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
750 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
751 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
752 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
753 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
754 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
755 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
756 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100757 {"menu_info", 1, 2, FEARG_1, ret_dict_any,
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100758#ifdef FEAT_MENU
Bram Moolenaar15c47602020-03-26 22:16:48 +0100759 f_menu_info
760#else
761 NULL
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100762#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100763 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100764 {"min", 1, 1, FEARG_1, ret_any, f_min},
765 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
766 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100767 {"mzeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200768#ifdef FEAT_MZSCHEME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100769 f_mzeval
770#else
771 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100773 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100774 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
775 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
776 {"or", 2, 2, FEARG_1, ret_number, f_or},
777 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100778 {"perleval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779#ifdef FEAT_PERL
Bram Moolenaar15c47602020-03-26 22:16:48 +0100780 f_perleval
781#else
782 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200783#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100784 },
785 {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)},
786 {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)},
Bram Moolenaar03a9f842020-05-13 13:40:16 +0200787 {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100788 {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)},
789 {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)},
790 {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)},
791 {"popup_filter_menu", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_menu)},
792 {"popup_filter_yesno", 2, 2, 0, ret_number, PROP_FUNC(f_popup_filter_yesno)},
793 {"popup_findinfo", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findinfo)},
794 {"popup_findpreview", 0, 0, 0, ret_number, PROP_FUNC(f_popup_findpreview)},
795 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)},
796 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)},
797 {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)},
Bram Moolenaaref6b9792020-05-13 16:34:15 +0200798 {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100799 {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)},
800 {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)},
801 {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)},
802 {"popup_notification", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_notification)},
803 {"popup_setoptions", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_setoptions)},
804 {"popup_settext", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_settext)},
805 {"popup_show", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_show)},
806 {"pow", 2, 2, FEARG_1, ret_float, FLOAT_FUNC(f_pow)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100807 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
808 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100809 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setcallback)},
810 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, JOB_FUNC(f_prompt_setinterrupt)},
811 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, JOB_FUNC(f_prompt_setprompt)},
812 {"prop_add", 3, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_add)},
813 {"prop_clear", 1, 3, FEARG_1, ret_void, PROP_FUNC(f_prop_clear)},
814 {"prop_find", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_find)},
815 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, PROP_FUNC(f_prop_list)},
816 {"prop_remove", 1, 3, FEARG_1, ret_number, PROP_FUNC(f_prop_remove)},
817 {"prop_type_add", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_add)},
818 {"prop_type_change", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_change)},
819 {"prop_type_delete", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_prop_type_delete)},
820 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, PROP_FUNC(f_prop_type_get)},
821 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, PROP_FUNC(f_prop_type_list)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100822 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
823 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100824 {"py3eval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825#ifdef FEAT_PYTHON3
Bram Moolenaar15c47602020-03-26 22:16:48 +0100826 f_py3eval
827#else
828 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200829#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100830 },
831 {"pyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200832#ifdef FEAT_PYTHON
Bram Moolenaar15c47602020-03-26 22:16:48 +0100833 f_pyeval
834#else
835 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100837 },
838 {"pyxeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100839#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar15c47602020-03-26 22:16:48 +0100840 f_pyxeval
841#else
842 NULL
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100843#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100844 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100845 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
846 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
Bram Moolenaar84cf6bd2020-06-16 20:03:43 +0200847 {"readdir", 1, 3, FEARG_1, ret_list_string, f_readdir},
848 {"readdirex", 1, 3, FEARG_1, ret_list_dict_any, f_readdirex},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100849 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
Bram Moolenaar85629982020-06-01 18:39:20 +0200850 {"reduce", 2, 3, FEARG_1, ret_any, f_reduce},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100851 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
852 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
853 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100854 {"reltimefloat", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_reltimefloat)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100855 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
856 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
857 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
858 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
859 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
860 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
Bram Moolenaar9978d472020-07-05 16:01:56 +0200861 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
Bram Moolenaarad7c2492020-07-05 20:55:29 +0200862 {"remove", 2, 3, FEARG_1, ret_remove, f_remove},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100863 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
Bram Moolenaar9978d472020-07-05 16:01:56 +0200864 {"repeat", 2, 2, FEARG_1, ret_first_arg, f_repeat},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100865 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
Bram Moolenaar67627352020-07-05 21:10:24 +0200866 {"reverse", 1, 1, FEARG_1, ret_first_arg, f_reverse},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100867 {"round", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_round)},
868 {"rubyeval", 1, 1, FEARG_1, ret_any,
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100869#ifdef FEAT_RUBY
Bram Moolenaar15c47602020-03-26 22:16:48 +0100870 f_rubyeval
871#else
872 NULL
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100873#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100874 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100875 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
876 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
877 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
878 {"screencol", 0, 0, 0, ret_number, f_screencol},
879 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
880 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
881 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200882 {"search", 1, 5, FEARG_1, ret_number, f_search},
Bram Moolenaare8f5ec02020-06-01 17:28:35 +0200883 {"searchcount", 0, 1, FEARG_1, ret_dict_any, f_searchcount},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100884 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
885 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
886 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
Bram Moolenaaradc17a52020-06-06 18:37:51 +0200887 {"searchpos", 1, 5, FEARG_1, ret_list_number, f_searchpos},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100888 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
889 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
890 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
891 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
Bram Moolenaar08aac3c2020-08-28 21:04:24 +0200892 {"setcellwidths", 1, 1, FEARG_1, ret_void, f_setcellwidths},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100893 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
894 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
895 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
896 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
897 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
898 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
899 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
900 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
901 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
902 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
903 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
904 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
905 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
906 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100907 {"sha256", 1, 1, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200908#ifdef FEAT_CRYPT
Bram Moolenaar15c47602020-03-26 22:16:48 +0100909 f_sha256
910#else
911 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200912#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100913 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100914 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
915 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100916 {"sign_define", 1, 2, FEARG_1, ret_any, SIGN_FUNC(f_sign_define)},
917 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getdefined)},
918 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, SIGN_FUNC(f_sign_getplaced)},
919 {"sign_jump", 3, 3, FEARG_1, ret_number, SIGN_FUNC(f_sign_jump)},
920 {"sign_place", 4, 5, FEARG_1, ret_number, SIGN_FUNC(f_sign_place)},
921 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_placelist)},
922 {"sign_undefine", 0, 1, FEARG_1, ret_number, SIGN_FUNC(f_sign_undefine)},
923 {"sign_unplace", 1, 2, FEARG_1, ret_number, SIGN_FUNC(f_sign_unplace)},
924 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, SIGN_FUNC(f_sign_unplacelist)},
Bram Moolenaar7035fd92020-04-08 20:03:52 +0200925 {"simplify", 1, 1, FEARG_1, ret_string, f_simplify},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100926 {"sin", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sin)},
927 {"sinh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sinh)},
Bram Moolenaar865af6b2020-06-18 18:45:49 +0200928 {"sort", 1, 3, FEARG_1, ret_first_arg, f_sort},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100929 {"sound_clear", 0, 0, 0, ret_void, SOUND_FUNC(f_sound_clear)},
930 {"sound_playevent", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playevent)},
931 {"sound_playfile", 1, 2, FEARG_1, ret_number, SOUND_FUNC(f_sound_playfile)},
932 {"sound_stop", 1, 1, FEARG_1, ret_void, SOUND_FUNC(f_sound_stop)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100933 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
934 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
935 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
936 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100937 {"sqrt", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_sqrt)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100938 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
939 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100940 {"str2float", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_str2float)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100941 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
942 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
943 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
944 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
945 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100946 {"strftime", 1, 2, FEARG_1, ret_string,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200947#ifdef HAVE_STRFTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100948 f_strftime
949#else
950 NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100952 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100953 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
954 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
955 {"string", 1, 1, FEARG_1, ret_string, f_string},
956 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
Bram Moolenaar6c53fca2020-08-23 17:34:46 +0200957 {"strpart", 2, 4, FEARG_1, ret_string, f_strpart},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100958 {"strptime", 2, 2, FEARG_1, ret_number,
Bram Moolenaar10455d42019-11-21 15:36:18 +0100959#ifdef HAVE_STRPTIME
Bram Moolenaar15c47602020-03-26 22:16:48 +0100960 f_strptime
961#else
962 NULL
Bram Moolenaar10455d42019-11-21 15:36:18 +0100963#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100964 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100965 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
966 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
967 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
968 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
969 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
970 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
971 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
972 {"synID", 3, 3, 0, ret_number, f_synID},
973 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
974 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
975 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
976 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
977 {"system", 1, 2, FEARG_1, ret_string, f_system},
978 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
979 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
980 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
981 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
982 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
983 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100984 {"tan", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tan)},
985 {"tanh", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_tanh)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100986 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaar15c47602020-03-26 22:16:48 +0100987 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, TERM_FUNC(f_term_dumpdiff)},
988 {"term_dumpload", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_dumpload)},
989 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, TERM_FUNC(f_term_dumpwrite)},
990 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getaltscreen)},
991 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +0100992#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +0100993 f_term_getansicolors
994#else
995 NULL
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200996#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +0100997 },
998 {"term_getattr", 2, 2, FEARG_1, ret_number, TERM_FUNC(f_term_getattr)},
999 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, TERM_FUNC(f_term_getcursor)},
1000 {"term_getjob", 1, 1, FEARG_1, ret_job, TERM_FUNC(f_term_getjob)},
1001 {"term_getline", 2, 2, FEARG_1, ret_string, TERM_FUNC(f_term_getline)},
1002 {"term_getscrolled", 1, 1, FEARG_1, ret_number, TERM_FUNC(f_term_getscrolled)},
1003 {"term_getsize", 1, 1, FEARG_1, ret_list_number, TERM_FUNC(f_term_getsize)},
1004 {"term_getstatus", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_getstatus)},
1005 {"term_gettitle", 1, 1, FEARG_1, ret_string, TERM_FUNC(f_term_gettitle)},
1006 {"term_gettty", 1, 2, FEARG_1, ret_string, TERM_FUNC(f_term_gettty)},
1007 {"term_list", 0, 0, 0, ret_list_number, TERM_FUNC(f_term_list)},
1008 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, TERM_FUNC(f_term_scrape)},
1009 {"term_sendkeys", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_sendkeys)},
1010 {"term_setansicolors", 2, 2, FEARG_1, ret_void,
Bram Moolenaarbd5e6222020-03-26 23:13:34 +01001011#if defined(FEAT_TERMINAL) && (defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS))
Bram Moolenaar15c47602020-03-26 22:16:48 +01001012 f_term_setansicolors
1013#else
1014 NULL
1015#endif
1016 },
1017 {"term_setapi", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setapi)},
1018 {"term_setkill", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setkill)},
1019 {"term_setrestore", 2, 2, FEARG_1, ret_void, TERM_FUNC(f_term_setrestore)},
1020 {"term_setsize", 3, 3, FEARG_1, ret_void, TERM_FUNC(f_term_setsize)},
1021 {"term_start", 1, 2, FEARG_1, ret_number, TERM_FUNC(f_term_start)},
1022 {"term_wait", 1, 2, FEARG_1, ret_void, TERM_FUNC(f_term_wait)},
Bram Moolenaar0c0eddd2020-06-13 15:47:25 +02001023 {"terminalprops", 0, 0, 0, ret_dict_string, f_terminalprops},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001024 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
1025 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
1026 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
1027 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
1028 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
1029 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
1030 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
1031 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001032 {"test_null_channel", 0, 0, 0, ret_channel, JOB_FUNC(f_test_null_channel)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001033 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaare69f6d02020-04-01 22:11:01 +02001034 {"test_null_function", 0, 0, 0, ret_func_any, f_test_null_function},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001035 {"test_null_job", 0, 0, 0, ret_job, JOB_FUNC(f_test_null_job)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001036 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
Bram Moolenaard77a8522020-04-03 21:59:57 +02001037 {"test_null_partial", 0, 0, 0, ret_func_any, f_test_null_partial},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001038 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
1039 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
1040 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
1041 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001042 {"test_scrollbar", 3, 3, FEARG_2, ret_void,
Bram Moolenaarab186732018-09-14 21:27:06 +02001043#ifdef FEAT_GUI
Bram Moolenaar15c47602020-03-26 22:16:48 +01001044 f_test_scrollbar
1045#else
1046 NULL
Bram Moolenaarab186732018-09-14 21:27:06 +02001047#endif
Bram Moolenaar15c47602020-03-26 22:16:48 +01001048 },
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001049 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
1050 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
1051 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
1052 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
Bram Moolenaar418f1df2020-08-12 21:34:49 +02001053 {"test_void", 0, 0, 0, ret_void, f_test_void},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001054 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, TIMER_FUNC(f_timer_info)},
1055 {"timer_pause", 2, 2, FEARG_1, ret_void, TIMER_FUNC(f_timer_pause)},
1056 {"timer_start", 2, 3, FEARG_1, ret_number, TIMER_FUNC(f_timer_start)},
1057 {"timer_stop", 1, 1, FEARG_1, ret_void, TIMER_FUNC(f_timer_stop)},
1058 {"timer_stopall", 0, 0, 0, ret_void, TIMER_FUNC(f_timer_stopall)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001059 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
1060 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
1061 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
Bram Moolenaar2245ae12020-05-31 22:20:36 +02001062 {"trim", 1, 3, FEARG_1, ret_string, f_trim},
Bram Moolenaar15c47602020-03-26 22:16:48 +01001063 {"trunc", 1, 1, FEARG_1, ret_float, FLOAT_FUNC(f_trunc)},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001064 {"type", 1, 1, FEARG_1, ret_number, f_type},
1065 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
1066 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
1067 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
1068 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
1069 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
1070 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
1071 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
1072 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
1073 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
1074 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
1075 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
1076 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
1077 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
1078 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
1079 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
1080 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
1081 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
1082 {"wincol", 0, 0, 0, ret_number, f_wincol},
1083 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
1084 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
1085 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
1086 {"winline", 0, 0, 0, ret_number, f_winline},
1087 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
1088 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
1089 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
1090 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
1091 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
1092 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
1093 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
1094 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +02001095};
1096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001097/*
1098 * Function given to ExpandGeneric() to obtain the list of internal
1099 * or user defined function names.
1100 */
1101 char_u *
1102get_function_name(expand_T *xp, int idx)
1103{
1104 static int intidx = -1;
1105 char_u *name;
1106
1107 if (idx == 0)
1108 intidx = -1;
1109 if (intidx < 0)
1110 {
1111 name = get_user_func_name(xp, idx);
1112 if (name != NULL)
1113 return name;
1114 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001115 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001116 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001117 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001118 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001119 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001120 STRCAT(IObuff, ")");
1121 return IObuff;
1122 }
1123
1124 return NULL;
1125}
1126
1127/*
1128 * Function given to ExpandGeneric() to obtain the list of internal or
1129 * user defined variable or function names.
1130 */
1131 char_u *
1132get_expr_name(expand_T *xp, int idx)
1133{
1134 static int intidx = -1;
1135 char_u *name;
1136
1137 if (idx == 0)
1138 intidx = -1;
1139 if (intidx < 0)
1140 {
1141 name = get_function_name(xp, idx);
1142 if (name != NULL)
1143 return name;
1144 }
1145 return get_user_var_name(xp, ++intidx);
1146}
1147
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001148/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001149 * Find internal function "name" in table "global_functions".
Bram Moolenaar15c47602020-03-26 22:16:48 +01001150 * Return index, or -1 if not found or "implemented" is TRUE and the function
1151 * is not implemented.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001152 */
Bram Moolenaar15c47602020-03-26 22:16:48 +01001153 static int
1154find_internal_func_opt(char_u *name, int implemented)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001155{
1156 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001157 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001158 int cmp;
1159 int x;
1160
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001161 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001162
1163 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001164 while (first <= last)
1165 {
1166 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001167 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001168 if (cmp < 0)
1169 last = x - 1;
1170 else if (cmp > 0)
1171 first = x + 1;
Bram Moolenaar15c47602020-03-26 22:16:48 +01001172 else if (implemented && global_functions[x].f_func == NULL)
1173 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001174 else
1175 return x;
1176 }
1177 return -1;
1178}
1179
Bram Moolenaar15c47602020-03-26 22:16:48 +01001180/*
1181 * Find internal function "name" in table "global_functions".
1182 * Return index, or -1 if not found or the function is not implemented.
1183 */
1184 int
1185find_internal_func(char_u *name)
1186{
1187 return find_internal_func_opt(name, TRUE);
1188}
1189
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001190 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001191has_internal_func(char_u *name)
1192{
Bram Moolenaar15c47602020-03-26 22:16:48 +01001193 return find_internal_func_opt(name, TRUE) >= 0;
1194}
1195
1196 static int
1197has_internal_func_name(char_u *name)
1198{
1199 return find_internal_func_opt(name, FALSE) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001200}
1201
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001202 char *
1203internal_func_name(int idx)
1204{
1205 return global_functions[idx].f_name;
1206}
1207
1208 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001209internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001210{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001211 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001212}
1213
1214/*
1215 * Check the argument count to use for internal function "idx".
Bram Moolenaar389df252020-07-09 21:20:47 +02001216 * Returns -1 for failure, 0 if no method base accepted, 1 if method base is
1217 * first argument, 2 if method base is second argument, etc. 9 if method base
1218 * is last argument.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001219 */
1220 int
1221check_internal_func(int idx, int argcount)
1222{
1223 int res;
1224 char *name;
1225
1226 if (argcount < global_functions[idx].f_min_argc)
1227 res = FCERR_TOOFEW;
1228 else if (argcount > global_functions[idx].f_max_argc)
1229 res = FCERR_TOOMANY;
1230 else
Bram Moolenaar389df252020-07-09 21:20:47 +02001231 return global_functions[idx].f_argtype;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001232
1233 name = internal_func_name(idx);
1234 if (res == FCERR_TOOMANY)
1235 semsg(_(e_toomanyarg), name);
1236 else
1237 semsg(_(e_toofewarg), name);
Bram Moolenaar389df252020-07-09 21:20:47 +02001238 return -1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001239}
1240
Bram Moolenaarac92e252019-08-03 21:58:38 +02001241 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242call_internal_func(
1243 char_u *name,
1244 int argcount,
1245 typval_T *argvars,
1246 typval_T *rettv)
1247{
1248 int i;
1249
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001250 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001251 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001252 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001253 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001254 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001255 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001256 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001257 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001258 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001259 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001260}
1261
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001262 void
1263call_internal_func_by_idx(
1264 int idx,
1265 typval_T *argvars,
1266 typval_T *rettv)
1267{
1268 global_functions[idx].f_func(argvars, rettv);
1269}
1270
Bram Moolenaarac92e252019-08-03 21:58:38 +02001271/*
1272 * Invoke a method for base->method().
1273 */
1274 int
1275call_internal_method(
1276 char_u *name,
1277 int argcount,
1278 typval_T *argvars,
1279 typval_T *rettv,
1280 typval_T *basetv)
1281{
1282 int i;
1283 int fi;
1284 typval_T argv[MAX_FUNC_ARGS + 1];
1285
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001286 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001287 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001288 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001289 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001290 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001291 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001292 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001293 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001294 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001295
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001296 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001297 {
1298 // base value goes last
1299 for (i = 0; i < argcount; ++i)
1300 argv[i] = argvars[i];
1301 argv[argcount] = *basetv;
1302 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001303 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001304 {
1305 // base value goes second
1306 argv[0] = argvars[0];
1307 argv[1] = *basetv;
1308 for (i = 1; i < argcount; ++i)
1309 argv[i + 1] = argvars[i];
1310 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001311 else if (global_functions[fi].f_argtype == FEARG_3)
1312 {
1313 // base value goes third
1314 argv[0] = argvars[0];
1315 argv[1] = argvars[1];
1316 argv[2] = *basetv;
1317 for (i = 2; i < argcount; ++i)
1318 argv[i + 1] = argvars[i];
1319 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001320 else if (global_functions[fi].f_argtype == FEARG_4)
1321 {
1322 // base value goes fourth
1323 argv[0] = argvars[0];
1324 argv[1] = argvars[1];
1325 argv[2] = argvars[2];
1326 argv[3] = *basetv;
1327 for (i = 3; i < argcount; ++i)
1328 argv[i + 1] = argvars[i];
1329 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001330 else
1331 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001332 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001333 argv[0] = *basetv;
1334 for (i = 0; i < argcount; ++i)
1335 argv[i + 1] = argvars[i];
1336 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001337 argv[argcount + 1].v_type = VAR_UNKNOWN;
1338
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001339 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001340 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001341}
1342
1343/*
1344 * Return TRUE for a non-zero Number and a non-empty String.
1345 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001346 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347non_zero_arg(typval_T *argvars)
1348{
1349 return ((argvars[0].v_type == VAR_NUMBER
1350 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001351 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001352 && argvars[0].vval.v_number == VVAL_TRUE)
1353 || (argvars[0].v_type == VAR_STRING
1354 && argvars[0].vval.v_string != NULL
1355 && *argvars[0].vval.v_string != NUL));
1356}
1357
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001359/*
1360 * Get the float value of "argvars[0]" into "f".
1361 * Returns FAIL when the argument is not a Number or Float.
1362 */
1363 static int
1364get_float_arg(typval_T *argvars, float_T *f)
1365{
1366 if (argvars[0].v_type == VAR_FLOAT)
1367 {
1368 *f = argvars[0].vval.v_float;
1369 return OK;
1370 }
1371 if (argvars[0].v_type == VAR_NUMBER)
1372 {
1373 *f = (float_T)argvars[0].vval.v_number;
1374 return OK;
1375 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001376 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001377 return FAIL;
1378}
1379
1380/*
1381 * "abs(expr)" function
1382 */
1383 static void
1384f_abs(typval_T *argvars, typval_T *rettv)
1385{
1386 if (argvars[0].v_type == VAR_FLOAT)
1387 {
1388 rettv->v_type = VAR_FLOAT;
1389 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1390 }
1391 else
1392 {
1393 varnumber_T n;
1394 int error = FALSE;
1395
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001396 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001397 if (error)
1398 rettv->vval.v_number = -1;
1399 else if (n > 0)
1400 rettv->vval.v_number = n;
1401 else
1402 rettv->vval.v_number = -n;
1403 }
1404}
1405
1406/*
1407 * "acos()" function
1408 */
1409 static void
1410f_acos(typval_T *argvars, typval_T *rettv)
1411{
1412 float_T f = 0.0;
1413
1414 rettv->v_type = VAR_FLOAT;
1415 if (get_float_arg(argvars, &f) == OK)
1416 rettv->vval.v_float = acos(f);
1417 else
1418 rettv->vval.v_float = 0.0;
1419}
1420#endif
1421
1422/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001423 * "and(expr, expr)" function
1424 */
1425 static void
1426f_and(typval_T *argvars, typval_T *rettv)
1427{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001428 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1429 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001430}
1431
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001432#ifdef FEAT_FLOAT
1433/*
1434 * "asin()" function
1435 */
1436 static void
1437f_asin(typval_T *argvars, typval_T *rettv)
1438{
1439 float_T f = 0.0;
1440
1441 rettv->v_type = VAR_FLOAT;
1442 if (get_float_arg(argvars, &f) == OK)
1443 rettv->vval.v_float = asin(f);
1444 else
1445 rettv->vval.v_float = 0.0;
1446}
1447
1448/*
1449 * "atan()" function
1450 */
1451 static void
1452f_atan(typval_T *argvars, typval_T *rettv)
1453{
1454 float_T f = 0.0;
1455
1456 rettv->v_type = VAR_FLOAT;
1457 if (get_float_arg(argvars, &f) == OK)
1458 rettv->vval.v_float = atan(f);
1459 else
1460 rettv->vval.v_float = 0.0;
1461}
1462
1463/*
1464 * "atan2()" function
1465 */
1466 static void
1467f_atan2(typval_T *argvars, typval_T *rettv)
1468{
1469 float_T fx = 0.0, fy = 0.0;
1470
1471 rettv->v_type = VAR_FLOAT;
1472 if (get_float_arg(argvars, &fx) == OK
1473 && get_float_arg(&argvars[1], &fy) == OK)
1474 rettv->vval.v_float = atan2(fx, fy);
1475 else
1476 rettv->vval.v_float = 0.0;
1477}
1478#endif
1479
1480/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001481 * "balloon_show()" function
1482 */
1483#ifdef FEAT_BEVAL
1484 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001485f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1486{
1487 rettv->v_type = VAR_STRING;
1488 if (balloonEval != NULL)
1489 {
1490 if (balloonEval->msg == NULL)
1491 rettv->vval.v_string = NULL;
1492 else
1493 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1494 }
1495}
1496
1497 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001498f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1499{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001500 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001501 {
1502 if (argvars[0].v_type == VAR_LIST
1503# ifdef FEAT_GUI
1504 && !gui.in_use
1505# endif
1506 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001507 {
1508 list_T *l = argvars[0].vval.v_list;
1509
1510 // empty list removes the balloon
1511 post_balloon(balloonEval, NULL,
1512 l == NULL || l->lv_len == 0 ? NULL : l);
1513 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001514 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001515 {
1516 char_u *mesg = tv_get_string_chk(&argvars[0]);
1517
1518 if (mesg != NULL)
1519 // empty string removes the balloon
1520 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1521 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001522 }
1523}
1524
Bram Moolenaar669a8282017-11-19 20:13:05 +01001525# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001526 static void
1527f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1528{
1529 if (rettv_list_alloc(rettv) == OK)
1530 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001531 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001532
1533 if (msg != NULL)
1534 {
1535 pumitem_T *array;
1536 int size = split_message(msg, &array);
1537 int i;
1538
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001539 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001540 for (i = 1; i < size - 1; ++i)
1541 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001542 while (size > 0)
1543 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001544 vim_free(array);
1545 }
1546 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001547}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001548# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001549#endif
1550
1551/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001552 * Get the buffer from "arg" and give an error and return NULL if it is not
1553 * valid.
1554 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001555 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001556get_buf_arg(typval_T *arg)
1557{
1558 buf_T *buf;
1559
1560 ++emsg_off;
1561 buf = tv_get_buf(arg, FALSE);
1562 --emsg_off;
1563 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001564 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001565 return buf;
1566}
1567
1568/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001569 * "byte2line(byte)" function
1570 */
1571 static void
1572f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1573{
1574#ifndef FEAT_BYTEOFF
1575 rettv->vval.v_number = -1;
1576#else
1577 long boff = 0;
1578
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001579 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580 if (boff < 0)
1581 rettv->vval.v_number = -1;
1582 else
1583 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1584 (linenr_T)0, &boff);
1585#endif
1586}
1587
1588 static void
1589byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1590{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001591 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001592 char_u *str;
1593 varnumber_T idx;
1594
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001595 str = tv_get_string_chk(&argvars[0]);
1596 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597 rettv->vval.v_number = -1;
1598 if (str == NULL || idx < 0)
1599 return;
1600
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601 t = str;
1602 for ( ; idx > 0; idx--)
1603 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001604 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001605 return;
1606 if (enc_utf8 && comp)
1607 t += utf_ptr2len(t);
1608 else
1609 t += (*mb_ptr2len)(t);
1610 }
1611 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001612}
1613
1614/*
1615 * "byteidx()" function
1616 */
1617 static void
1618f_byteidx(typval_T *argvars, typval_T *rettv)
1619{
1620 byteidx(argvars, rettv, FALSE);
1621}
1622
1623/*
1624 * "byteidxcomp()" function
1625 */
1626 static void
1627f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1628{
1629 byteidx(argvars, rettv, TRUE);
1630}
1631
1632/*
1633 * "call(func, arglist [, dict])" function
1634 */
1635 static void
1636f_call(typval_T *argvars, typval_T *rettv)
1637{
1638 char_u *func;
1639 partial_T *partial = NULL;
1640 dict_T *selfdict = NULL;
1641
1642 if (argvars[1].v_type != VAR_LIST)
1643 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001644 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001645 return;
1646 }
1647 if (argvars[1].vval.v_list == NULL)
1648 return;
1649
1650 if (argvars[0].v_type == VAR_FUNC)
1651 func = argvars[0].vval.v_string;
1652 else if (argvars[0].v_type == VAR_PARTIAL)
1653 {
1654 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001655 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001656 }
1657 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001658 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001659 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001660 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661
1662 if (argvars[2].v_type != VAR_UNKNOWN)
1663 {
1664 if (argvars[2].v_type != VAR_DICT)
1665 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001666 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667 return;
1668 }
1669 selfdict = argvars[2].vval.v_dict;
1670 }
1671
1672 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1673}
1674
1675#ifdef FEAT_FLOAT
1676/*
1677 * "ceil({float})" function
1678 */
1679 static void
1680f_ceil(typval_T *argvars, typval_T *rettv)
1681{
1682 float_T f = 0.0;
1683
1684 rettv->v_type = VAR_FLOAT;
1685 if (get_float_arg(argvars, &f) == OK)
1686 rettv->vval.v_float = ceil(f);
1687 else
1688 rettv->vval.v_float = 0.0;
1689}
1690#endif
1691
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692/*
1693 * "changenr()" function
1694 */
1695 static void
1696f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1697{
1698 rettv->vval.v_number = curbuf->b_u_seq_cur;
1699}
1700
1701/*
1702 * "char2nr(string)" function
1703 */
1704 static void
1705f_char2nr(typval_T *argvars, typval_T *rettv)
1706{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001707 if (has_mbyte)
1708 {
1709 int utf8 = 0;
1710
1711 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001712 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001713
1714 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001715 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001717 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001718 }
1719 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001720 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001721}
1722
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001723 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001724get_optional_window(typval_T *argvars, int idx)
1725{
1726 win_T *win = curwin;
1727
1728 if (argvars[idx].v_type != VAR_UNKNOWN)
1729 {
1730 win = find_win_by_nr_or_id(&argvars[idx]);
1731 if (win == NULL)
1732 {
1733 emsg(_(e_invalwindow));
1734 return NULL;
1735 }
1736 }
1737 return win;
1738}
1739
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001740/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001741 * "col(string)" function
1742 */
1743 static void
1744f_col(typval_T *argvars, typval_T *rettv)
1745{
1746 colnr_T col = 0;
1747 pos_T *fp;
1748 int fnum = curbuf->b_fnum;
1749
1750 fp = var2fpos(&argvars[0], FALSE, &fnum);
1751 if (fp != NULL && fnum == curbuf->b_fnum)
1752 {
1753 if (fp->col == MAXCOL)
1754 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001755 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001756 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1757 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1758 else
1759 col = MAXCOL;
1760 }
1761 else
1762 {
1763 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001764 // col(".") when the cursor is on the NUL at the end of the line
1765 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001766 if (virtual_active() && fp == &curwin->w_cursor)
1767 {
1768 char_u *p = ml_get_cursor();
1769
1770 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1771 curwin->w_virtcol - curwin->w_cursor.coladd))
1772 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773 int l;
1774
1775 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1776 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001777 }
1778 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001779 }
1780 }
1781 rettv->vval.v_number = col;
1782}
1783
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001784/*
1785 * "confirm(message, buttons[, default [, type]])" function
1786 */
1787 static void
1788f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1789{
1790#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1791 char_u *message;
1792 char_u *buttons = NULL;
1793 char_u buf[NUMBUFLEN];
1794 char_u buf2[NUMBUFLEN];
1795 int def = 1;
1796 int type = VIM_GENERIC;
1797 char_u *typestr;
1798 int error = FALSE;
1799
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001800 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001801 if (message == NULL)
1802 error = TRUE;
1803 if (argvars[1].v_type != VAR_UNKNOWN)
1804 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001805 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001806 if (buttons == NULL)
1807 error = TRUE;
1808 if (argvars[2].v_type != VAR_UNKNOWN)
1809 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001810 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001811 if (argvars[3].v_type != VAR_UNKNOWN)
1812 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001813 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001814 if (typestr == NULL)
1815 error = TRUE;
1816 else
1817 {
1818 switch (TOUPPER_ASC(*typestr))
1819 {
1820 case 'E': type = VIM_ERROR; break;
1821 case 'Q': type = VIM_QUESTION; break;
1822 case 'I': type = VIM_INFO; break;
1823 case 'W': type = VIM_WARNING; break;
1824 case 'G': type = VIM_GENERIC; break;
1825 }
1826 }
1827 }
1828 }
1829 }
1830
1831 if (buttons == NULL || *buttons == NUL)
1832 buttons = (char_u *)_("&Ok");
1833
1834 if (!error)
1835 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1836 def, NULL, FALSE);
1837#endif
1838}
1839
1840/*
1841 * "copy()" function
1842 */
1843 static void
1844f_copy(typval_T *argvars, typval_T *rettv)
1845{
1846 item_copy(&argvars[0], rettv, FALSE, 0);
1847}
1848
1849#ifdef FEAT_FLOAT
1850/*
1851 * "cos()" function
1852 */
1853 static void
1854f_cos(typval_T *argvars, typval_T *rettv)
1855{
1856 float_T f = 0.0;
1857
1858 rettv->v_type = VAR_FLOAT;
1859 if (get_float_arg(argvars, &f) == OK)
1860 rettv->vval.v_float = cos(f);
1861 else
1862 rettv->vval.v_float = 0.0;
1863}
1864
1865/*
1866 * "cosh()" function
1867 */
1868 static void
1869f_cosh(typval_T *argvars, typval_T *rettv)
1870{
1871 float_T f = 0.0;
1872
1873 rettv->v_type = VAR_FLOAT;
1874 if (get_float_arg(argvars, &f) == OK)
1875 rettv->vval.v_float = cosh(f);
1876 else
1877 rettv->vval.v_float = 0.0;
1878}
1879#endif
1880
1881/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001882 * "cursor(lnum, col)" function, or
1883 * "cursor(list)"
1884 *
1885 * Moves the cursor to the specified line and column.
1886 * Returns 0 when the position could be set, -1 otherwise.
1887 */
1888 static void
1889f_cursor(typval_T *argvars, typval_T *rettv)
1890{
1891 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001892 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001893 int set_curswant = TRUE;
1894
1895 rettv->vval.v_number = -1;
1896 if (argvars[1].v_type == VAR_UNKNOWN)
1897 {
1898 pos_T pos;
1899 colnr_T curswant = -1;
1900
1901 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1902 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001903 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001904 return;
1905 }
1906 line = pos.lnum;
1907 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001909 if (curswant >= 0)
1910 {
1911 curwin->w_curswant = curswant - 1;
1912 set_curswant = FALSE;
1913 }
1914 }
1915 else
1916 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001917 line = tv_get_lnum(argvars);
1918 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001919 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001920 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001921 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001922 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001923 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001924 if (line > 0)
1925 curwin->w_cursor.lnum = line;
1926 if (col > 0)
1927 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001929
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001930 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001931 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001932 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001933 if (has_mbyte)
1934 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001935
1936 curwin->w_set_curswant = set_curswant;
1937 rettv->vval.v_number = 0;
1938}
1939
Bram Moolenaar4f974752019-02-17 17:44:42 +01001940#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001941/*
1942 * "debugbreak()" function
1943 */
1944 static void
1945f_debugbreak(typval_T *argvars, typval_T *rettv)
1946{
1947 int pid;
1948
1949 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001950 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001951 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001952 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001953 else
1954 {
1955 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1956
1957 if (hProcess != NULL)
1958 {
1959 DebugBreakProcess(hProcess);
1960 CloseHandle(hProcess);
1961 rettv->vval.v_number = OK;
1962 }
1963 }
1964}
1965#endif
1966
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001967/*
1968 * "deepcopy()" function
1969 */
1970 static void
1971f_deepcopy(typval_T *argvars, typval_T *rettv)
1972{
1973 int noref = 0;
1974 int copyID;
1975
1976 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001977 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001979 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 else
1981 {
1982 copyID = get_copyID();
1983 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1984 }
1985}
1986
1987/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988 * "did_filetype()" function
1989 */
1990 static void
1991f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1992{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001993 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001994}
1995
1996/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001997 * "echoraw({expr})" function
1998 */
1999 static void
2000f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
2001{
2002 char_u *str = tv_get_string_chk(&argvars[0]);
2003
2004 if (str != NULL && *str != NUL)
2005 {
2006 out_str(str);
2007 out_flush();
2008 }
2009}
2010
2011/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 * "empty({expr})" function
2013 */
2014 static void
2015f_empty(typval_T *argvars, typval_T *rettv)
2016{
2017 int n = FALSE;
2018
2019 switch (argvars[0].v_type)
2020 {
2021 case VAR_STRING:
2022 case VAR_FUNC:
2023 n = argvars[0].vval.v_string == NULL
2024 || *argvars[0].vval.v_string == NUL;
2025 break;
2026 case VAR_PARTIAL:
2027 n = FALSE;
2028 break;
2029 case VAR_NUMBER:
2030 n = argvars[0].vval.v_number == 0;
2031 break;
2032 case VAR_FLOAT:
2033#ifdef FEAT_FLOAT
2034 n = argvars[0].vval.v_float == 0.0;
2035 break;
2036#endif
2037 case VAR_LIST:
2038 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002039 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002040 break;
2041 case VAR_DICT:
2042 n = argvars[0].vval.v_dict == NULL
2043 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2044 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01002045 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002046 case VAR_SPECIAL:
2047 n = argvars[0].vval.v_number != VVAL_TRUE;
2048 break;
2049
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002050 case VAR_BLOB:
2051 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002052 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2053 break;
2054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002055 case VAR_JOB:
2056#ifdef FEAT_JOB_CHANNEL
2057 n = argvars[0].vval.v_job == NULL
2058 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2059 break;
2060#endif
2061 case VAR_CHANNEL:
2062#ifdef FEAT_JOB_CHANNEL
2063 n = argvars[0].vval.v_channel == NULL
2064 || !channel_is_open(argvars[0].vval.v_channel);
2065 break;
2066#endif
2067 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02002068 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002069 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01002070 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002071 n = TRUE;
2072 break;
2073 }
2074
2075 rettv->vval.v_number = n;
2076}
2077
2078/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002079 * "environ()" function
2080 */
2081 static void
2082f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2083{
2084#if !defined(AMIGA)
2085 int i = 0;
2086 char_u *entry, *value;
2087# ifdef MSWIN
2088 extern wchar_t **_wenviron;
2089# else
2090 extern char **environ;
2091# endif
2092
2093 if (rettv_dict_alloc(rettv) != OK)
2094 return;
2095
2096# ifdef MSWIN
2097 if (*_wenviron == NULL)
2098 return;
2099# else
2100 if (*environ == NULL)
2101 return;
2102# endif
2103
2104 for (i = 0; ; ++i)
2105 {
2106# ifdef MSWIN
2107 short_u *p;
2108
2109 if ((p = (short_u *)_wenviron[i]) == NULL)
2110 return;
2111 entry = utf16_to_enc(p, NULL);
2112# else
2113 if ((entry = (char_u *)environ[i]) == NULL)
2114 return;
2115 entry = vim_strsave(entry);
2116# endif
2117 if (entry == NULL) // out of memory
2118 return;
2119 if ((value = vim_strchr(entry, '=')) == NULL)
2120 {
2121 vim_free(entry);
2122 continue;
2123 }
2124 *value++ = NUL;
2125 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2126 vim_free(entry);
2127 }
2128#endif
2129}
2130
2131/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002132 * "escape({string}, {chars})" function
2133 */
2134 static void
2135f_escape(typval_T *argvars, typval_T *rettv)
2136{
2137 char_u buf[NUMBUFLEN];
2138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002139 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2140 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002141 rettv->v_type = VAR_STRING;
2142}
2143
2144/*
2145 * "eval()" function
2146 */
2147 static void
2148f_eval(typval_T *argvars, typval_T *rettv)
2149{
2150 char_u *s, *p;
2151
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002152 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 if (s != NULL)
2154 s = skipwhite(s);
2155
2156 p = s;
Bram Moolenaar5409f5d2020-06-24 18:37:35 +02002157 if (s == NULL || eval1(&s, rettv, &EVALARG_EVALUATE) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 {
2159 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002160 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161 need_clr_eos = FALSE;
2162 rettv->v_type = VAR_NUMBER;
2163 rettv->vval.v_number = 0;
2164 }
2165 else if (*s != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02002166 semsg(_(e_trailing_arg), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167}
2168
2169/*
2170 * "eventhandler()" function
2171 */
2172 static void
2173f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2174{
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002175 rettv->vval.v_number = vgetc_busy || input_busy;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176}
2177
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178static garray_T redir_execute_ga;
2179
2180/*
2181 * Append "value[value_len]" to the execute() output.
2182 */
2183 void
2184execute_redir_str(char_u *value, int value_len)
2185{
2186 int len;
2187
2188 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002189 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002190 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002191 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 if (ga_grow(&redir_execute_ga, len) == OK)
2193 {
2194 mch_memmove((char *)redir_execute_ga.ga_data
2195 + redir_execute_ga.ga_len, value, len);
2196 redir_execute_ga.ga_len += len;
2197 }
2198}
2199
2200/*
2201 * Get next line from a list.
2202 * Called by do_cmdline() to get the next line.
2203 * Returns allocated string, or NULL for end of function.
2204 */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002205 static char_u *
2206get_list_line(
2207 int c UNUSED,
2208 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002209 int indent UNUSED,
Bram Moolenaar66250c92020-08-20 15:02:42 +02002210 getline_opt_T options UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211{
2212 listitem_T **p = (listitem_T **)cookie;
2213 listitem_T *item = *p;
2214 char_u buf[NUMBUFLEN];
2215 char_u *s;
2216
2217 if (item == NULL)
2218 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002219 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002220 *p = item->li_next;
2221 return s == NULL ? NULL : vim_strsave(s);
2222}
2223
2224/*
2225 * "execute()" function
2226 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002227 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002228execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002229{
2230 char_u *cmd = NULL;
2231 list_T *list = NULL;
2232 int save_msg_silent = msg_silent;
2233 int save_emsg_silent = emsg_silent;
2234 int save_emsg_noredir = emsg_noredir;
2235 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002236 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002237 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002238 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002239 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002240
2241 rettv->vval.v_string = NULL;
2242 rettv->v_type = VAR_STRING;
2243
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002244 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002245 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002246 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002247 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002248 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002249 return;
2250 ++list->lv_refcount;
2251 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002252 else if (argvars[arg_off].v_type == VAR_JOB
2253 || argvars[arg_off].v_type == VAR_CHANNEL)
2254 {
2255 emsg(_(e_inval_string));
2256 return;
2257 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002258 else
2259 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002260 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002261 if (cmd == NULL)
2262 return;
2263 }
2264
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002265 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 {
2267 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002268 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269
2270 if (s == NULL)
2271 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002272 if (*s == NUL)
2273 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002274 if (STRNCMP(s, "silent", 6) == 0)
2275 ++msg_silent;
2276 if (STRCMP(s, "silent!") == 0)
2277 {
2278 emsg_silent = TRUE;
2279 emsg_noredir = TRUE;
2280 }
2281 }
2282 else
2283 ++msg_silent;
2284
2285 if (redir_execute)
2286 save_ga = redir_execute_ga;
2287 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2288 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002289 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002290 if (!echo_output)
2291 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292
2293 if (cmd != NULL)
2294 do_cmdline_cmd(cmd);
2295 else
2296 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002297 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002298
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002299 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002300 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 do_cmdline(NULL, get_list_line, (void *)&item,
2302 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2303 --list->lv_refcount;
2304 }
2305
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002306 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002307 if (ga_grow(&redir_execute_ga, 1) == OK)
2308 {
2309 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2310 rettv->vval.v_string = redir_execute_ga.ga_data;
2311 }
2312 else
2313 {
2314 ga_clear(&redir_execute_ga);
2315 rettv->vval.v_string = NULL;
2316 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002317 msg_silent = save_msg_silent;
2318 emsg_silent = save_emsg_silent;
2319 emsg_noredir = save_emsg_noredir;
2320
2321 redir_execute = save_redir_execute;
2322 if (redir_execute)
2323 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002324 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002325
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002326 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002327 if (echo_output)
2328 // When not working silently: put it in column zero. A following
2329 // "echon" will overwrite the message, unavoidably.
2330 msg_col = 0;
2331 else
2332 // When working silently: Put it back where it was, since nothing
2333 // should have been written.
2334 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002335}
2336
2337/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002338 * "execute()" function
2339 */
2340 static void
2341f_execute(typval_T *argvars, typval_T *rettv)
2342{
2343 execute_common(argvars, rettv, 0);
2344}
2345
2346/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 * "exists()" function
2348 */
2349 static void
2350f_exists(typval_T *argvars, typval_T *rettv)
2351{
2352 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002354
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002355 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002356 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002357 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002358 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 if (mch_getenv(p + 1) != NULL)
2360 n = TRUE;
2361 else
2362 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002363 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 p = expand_env_save(p);
2365 if (p != NULL && *p != '$')
2366 n = TRUE;
2367 vim_free(p);
2368 }
2369 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002370 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002371 {
Bram Moolenaar9a78e6d2020-07-01 18:29:55 +02002372 n = (eval_option(&p, NULL, TRUE) == OK);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002373 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002374 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002375 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002376 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002377 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002378 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002379 }
Bram Moolenaar15c47602020-03-26 22:16:48 +01002380 else if (*p == '?') // internal function only
2381 {
2382 n = has_internal_func_name(p + 1);
2383 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002384 else if (*p == ':')
2385 {
2386 n = cmd_exists(p + 1);
2387 }
2388 else if (*p == '#')
2389 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002390 if (p[1] == '#')
2391 n = autocmd_supported(p + 2);
2392 else
2393 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002394 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002395 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002396 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002397 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002398 }
2399
2400 rettv->vval.v_number = n;
2401}
2402
2403#ifdef FEAT_FLOAT
2404/*
2405 * "exp()" function
2406 */
2407 static void
2408f_exp(typval_T *argvars, typval_T *rettv)
2409{
2410 float_T f = 0.0;
2411
2412 rettv->v_type = VAR_FLOAT;
2413 if (get_float_arg(argvars, &f) == OK)
2414 rettv->vval.v_float = exp(f);
2415 else
2416 rettv->vval.v_float = 0.0;
2417}
2418#endif
2419
2420/*
2421 * "expand()" function
2422 */
2423 static void
2424f_expand(typval_T *argvars, typval_T *rettv)
2425{
2426 char_u *s;
2427 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002428 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002429 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2430 expand_T xpc;
2431 int error = FALSE;
2432 char_u *result;
2433
2434 rettv->v_type = VAR_STRING;
2435 if (argvars[1].v_type != VAR_UNKNOWN
2436 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002437 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002438 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002439 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002441 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 if (*s == '%' || *s == '#' || *s == '<')
2443 {
2444 ++emsg_off;
2445 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2446 --emsg_off;
2447 if (rettv->v_type == VAR_LIST)
2448 {
2449 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2450 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002451 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 }
2453 else
2454 rettv->vval.v_string = result;
2455 }
2456 else
2457 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002458 // When the optional second argument is non-zero, don't remove matches
2459 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002461 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002462 options |= WILD_KEEP_ALL;
2463 if (!error)
2464 {
2465 ExpandInit(&xpc);
2466 xpc.xp_context = EXPAND_FILES;
2467 if (p_wic)
2468 options += WILD_ICASE;
2469 if (rettv->v_type == VAR_STRING)
2470 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2471 options, WILD_ALL);
2472 else if (rettv_list_alloc(rettv) != FAIL)
2473 {
2474 int i;
2475
2476 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2477 for (i = 0; i < xpc.xp_numfiles; i++)
2478 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2479 ExpandCleanup(&xpc);
2480 }
2481 }
2482 else
2483 rettv->vval.v_string = NULL;
2484 }
2485}
2486
2487/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002488 * "expandcmd()" function
2489 * Expand all the special characters in a command string.
2490 */
2491 static void
2492f_expandcmd(typval_T *argvars, typval_T *rettv)
2493{
2494 exarg_T eap;
2495 char_u *cmdstr;
2496 char *errormsg = NULL;
2497
2498 rettv->v_type = VAR_STRING;
2499 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2500
2501 memset(&eap, 0, sizeof(eap));
2502 eap.cmd = cmdstr;
2503 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002504 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002505 eap.usefilter = FALSE;
2506 eap.nextcmd = NULL;
2507 eap.cmdidx = CMD_USER;
2508
2509 expand_filename(&eap, &cmdstr, &errormsg);
2510 if (errormsg != NULL && *errormsg != NUL)
2511 emsg(errormsg);
2512
2513 rettv->vval.v_string = cmdstr;
2514}
2515
2516/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517 * "feedkeys()" function
2518 */
2519 static void
2520f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2521{
2522 int remap = TRUE;
2523 int insert = FALSE;
2524 char_u *keys, *flags;
2525 char_u nbuf[NUMBUFLEN];
2526 int typed = FALSE;
2527 int execute = FALSE;
2528 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002529 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002530 char_u *keys_esc;
2531
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002532 // This is not allowed in the sandbox. If the commands would still be
2533 // executed in the sandbox it would be OK, but it probably happens later,
2534 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002535 if (check_secure())
2536 return;
2537
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002538 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002539
2540 if (argvars[1].v_type != VAR_UNKNOWN)
2541 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002542 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 for ( ; *flags != NUL; ++flags)
2544 {
2545 switch (*flags)
2546 {
2547 case 'n': remap = FALSE; break;
2548 case 'm': remap = TRUE; break;
2549 case 't': typed = TRUE; break;
2550 case 'i': insert = TRUE; break;
2551 case 'x': execute = TRUE; break;
2552 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002553 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 }
2555 }
2556 }
2557
2558 if (*keys != NUL || execute)
2559 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002560 // Need to escape K_SPECIAL and CSI before putting the string in the
2561 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002562 keys_esc = vim_strsave_escape_csi(keys);
2563 if (keys_esc != NULL)
2564 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002565 if (lowlevel)
2566 {
2567#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002568 int idx;
2569 int len = (int)STRLEN(keys);
2570
2571 for (idx = 0; idx < len; ++idx)
2572 {
2573 // if a CTRL-C was typed, set got_int, similar to what
2574 // happens in fill_input_buf()
2575 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2576 got_int = TRUE;
2577 add_to_input_buf(keys + idx, 1);
2578 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002579#else
2580 emsg(_("E980: lowlevel input not supported"));
2581#endif
2582 }
2583 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002584 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002585 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002586 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002587 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002588#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002589 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002590#endif
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002591 || input_busy)
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002592 typebuf_was_filled = TRUE;
2593 }
2594 vim_free(keys_esc);
2595
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002596 if (execute)
2597 {
2598 int save_msg_scroll = msg_scroll;
2599
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002600 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601 msg_scroll = FALSE;
2602
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002603 if (!dangerous)
2604 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002605 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002606 if (!dangerous)
2607 --ex_normal_busy;
2608
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609 msg_scroll |= save_msg_scroll;
2610 }
2611 }
2612 }
2613}
2614
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002615#ifdef FEAT_FLOAT
2616/*
2617 * "float2nr({float})" function
2618 */
2619 static void
2620f_float2nr(typval_T *argvars, typval_T *rettv)
2621{
2622 float_T f = 0.0;
2623
2624 if (get_float_arg(argvars, &f) == OK)
2625 {
Bram Moolenaar37184272020-05-23 19:30:05 +02002626 if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002627 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar37184272020-05-23 19:30:05 +02002628 else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002629 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002630 else
2631 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632 }
2633}
2634
2635/*
2636 * "floor({float})" function
2637 */
2638 static void
2639f_floor(typval_T *argvars, typval_T *rettv)
2640{
2641 float_T f = 0.0;
2642
2643 rettv->v_type = VAR_FLOAT;
2644 if (get_float_arg(argvars, &f) == OK)
2645 rettv->vval.v_float = floor(f);
2646 else
2647 rettv->vval.v_float = 0.0;
2648}
2649
2650/*
2651 * "fmod()" function
2652 */
2653 static void
2654f_fmod(typval_T *argvars, typval_T *rettv)
2655{
2656 float_T fx = 0.0, fy = 0.0;
2657
2658 rettv->v_type = VAR_FLOAT;
2659 if (get_float_arg(argvars, &fx) == OK
2660 && get_float_arg(&argvars[1], &fy) == OK)
2661 rettv->vval.v_float = fmod(fx, fy);
2662 else
2663 rettv->vval.v_float = 0.0;
2664}
2665#endif
2666
2667/*
2668 * "fnameescape({string})" function
2669 */
2670 static void
2671f_fnameescape(typval_T *argvars, typval_T *rettv)
2672{
2673 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002674 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675 rettv->v_type = VAR_STRING;
2676}
2677
2678/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002679 * "foreground()" function
2680 */
2681 static void
2682f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2683{
2684#ifdef FEAT_GUI
2685 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002686 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002687 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002688 return;
2689 }
2690#endif
2691#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002692 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693#endif
2694}
2695
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002696 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002697common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002698{
2699 char_u *s;
2700 char_u *name;
2701 int use_string = FALSE;
2702 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002703 char_u *trans_name = NULL;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002704 int is_global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705
2706 if (argvars[0].v_type == VAR_FUNC)
2707 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002708 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709 s = argvars[0].vval.v_string;
2710 }
2711 else if (argvars[0].v_type == VAR_PARTIAL
2712 && argvars[0].vval.v_partial != NULL)
2713 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002714 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002715 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002716 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002717 }
2718 else
2719 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002720 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002721 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002722 use_string = TRUE;
2723 }
2724
Bram Moolenaar843b8842016-08-21 14:36:15 +02002725 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002726 {
2727 name = s;
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002728 trans_name = trans_function_name(&name, &is_global, FALSE,
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002729 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2730 if (*name != NUL)
2731 s = NULL;
2732 }
2733
Bram Moolenaar843b8842016-08-21 14:36:15 +02002734 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2735 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002736 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002737 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002738 else if (trans_name != NULL && (is_funcref
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002739 ? find_func(trans_name, is_global, NULL) == NULL
2740 : !translated_function_exists(trans_name, is_global)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002741 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002742 else
2743 {
2744 int dict_idx = 0;
2745 int arg_idx = 0;
2746 list_T *list = NULL;
2747
2748 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2749 {
2750 char sid_buf[25];
2751 int off = *s == 's' ? 2 : 5;
2752
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002753 // Expand s: and <SID> into <SNR>nr_, so that the function can
2754 // also be called from another script. Using trans_function_name()
2755 // would also work, but some plugins depend on the name being
2756 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002757 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002758 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002759 if (name != NULL)
2760 {
2761 STRCPY(name, sid_buf);
2762 STRCAT(name, s + off);
2763 }
2764 }
2765 else
2766 name = vim_strsave(s);
2767
2768 if (argvars[1].v_type != VAR_UNKNOWN)
2769 {
2770 if (argvars[2].v_type != VAR_UNKNOWN)
2771 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002772 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002773 arg_idx = 1;
2774 dict_idx = 2;
2775 }
2776 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002777 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 dict_idx = 1;
2779 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002780 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002781 arg_idx = 1;
2782 if (dict_idx > 0)
2783 {
2784 if (argvars[dict_idx].v_type != VAR_DICT)
2785 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002786 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002788 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002789 }
2790 if (argvars[dict_idx].vval.v_dict == NULL)
2791 dict_idx = 0;
2792 }
2793 if (arg_idx > 0)
2794 {
2795 if (argvars[arg_idx].v_type != VAR_LIST)
2796 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002797 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002798 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002799 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002800 }
2801 list = argvars[arg_idx].vval.v_list;
2802 if (list == NULL || list->lv_len == 0)
2803 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002804 else if (list->lv_len > MAX_FUNC_ARGS)
2805 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002806 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002807 vim_free(name);
2808 goto theend;
2809 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002810 }
2811 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002812 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002813 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002814 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002815
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002816 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817 if (pt == NULL)
2818 vim_free(name);
2819 else
2820 {
2821 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2822 {
2823 listitem_T *li;
2824 int i = 0;
2825 int arg_len = 0;
2826 int lv_len = 0;
2827
2828 if (arg_pt != NULL)
2829 arg_len = arg_pt->pt_argc;
2830 if (list != NULL)
2831 lv_len = list->lv_len;
2832 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002833 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002834 if (pt->pt_argv == NULL)
2835 {
2836 vim_free(pt);
2837 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002838 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002839 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002840 for (i = 0; i < arg_len; i++)
2841 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2842 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002843 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002844 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002845 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002846 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002847 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848 }
2849
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002850 // For "function(dict.func, [], dict)" and "func" is a partial
2851 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002852 if (dict_idx > 0)
2853 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002854 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2856 ++pt->pt_dict->dv_refcount;
2857 }
2858 else if (arg_pt != NULL)
2859 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002860 // If the dict was bound automatically the result is also
2861 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002862 pt->pt_dict = arg_pt->pt_dict;
2863 pt->pt_auto = arg_pt->pt_auto;
2864 if (pt->pt_dict != NULL)
2865 ++pt->pt_dict->dv_refcount;
2866 }
2867
2868 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002869 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2870 {
2871 pt->pt_func = arg_pt->pt_func;
2872 func_ptr_ref(pt->pt_func);
2873 vim_free(name);
2874 }
2875 else if (is_funcref)
2876 {
Bram Moolenaar4c17ad92020-04-27 22:47:51 +02002877 pt->pt_func = find_func(trans_name, is_global, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002878 func_ptr_ref(pt->pt_func);
2879 vim_free(name);
2880 }
2881 else
2882 {
2883 pt->pt_name = name;
2884 func_ref(name);
2885 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002886 }
2887 rettv->v_type = VAR_PARTIAL;
2888 rettv->vval.v_partial = pt;
2889 }
2890 else
2891 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002892 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002893 rettv->v_type = VAR_FUNC;
2894 rettv->vval.v_string = name;
2895 func_ref(name);
2896 }
2897 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002898theend:
2899 vim_free(trans_name);
2900}
2901
2902/*
2903 * "funcref()" function
2904 */
2905 static void
2906f_funcref(typval_T *argvars, typval_T *rettv)
2907{
2908 common_function(argvars, rettv, TRUE);
2909}
2910
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002911 static type_T *
Bram Moolenaardfc33a62020-04-29 22:30:13 +02002912ret_f_function(int argcount, type_T **argtypes)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002913{
2914 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2915 return &t_func_any;
Bram Moolenaard77a8522020-04-03 21:59:57 +02002916 return &t_func_void;
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002917}
2918
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002919/*
2920 * "function()" function
2921 */
2922 static void
2923f_function(typval_T *argvars, typval_T *rettv)
2924{
2925 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926}
2927
2928/*
2929 * "garbagecollect()" function
2930 */
2931 static void
2932f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2933{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002934 // This is postponed until we are back at the toplevel, because we may be
2935 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002936 want_garbage_collect = TRUE;
2937
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002938 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002939 garbage_collect_at_exit = TRUE;
2940}
2941
2942/*
2943 * "get()" function
2944 */
2945 static void
2946f_get(typval_T *argvars, typval_T *rettv)
2947{
2948 listitem_T *li;
2949 list_T *l;
2950 dictitem_T *di;
2951 dict_T *d;
2952 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002953 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002954
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002955 if (argvars[0].v_type == VAR_BLOB)
2956 {
2957 int error = FALSE;
2958 int idx = tv_get_number_chk(&argvars[1], &error);
2959
2960 if (!error)
2961 {
2962 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002963 if (idx < 0)
2964 idx = blob_len(argvars[0].vval.v_blob) + idx;
2965 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2966 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002967 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002968 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002969 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002970 tv = rettv;
2971 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002972 }
2973 }
2974 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975 {
2976 if ((l = argvars[0].vval.v_list) != NULL)
2977 {
2978 int error = FALSE;
2979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002980 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002981 if (!error && li != NULL)
2982 tv = &li->li_tv;
2983 }
2984 }
2985 else if (argvars[0].v_type == VAR_DICT)
2986 {
2987 if ((d = argvars[0].vval.v_dict) != NULL)
2988 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002989 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002990 if (di != NULL)
2991 tv = &di->di_tv;
2992 }
2993 }
2994 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2995 {
2996 partial_T *pt;
2997 partial_T fref_pt;
2998
2999 if (argvars[0].v_type == VAR_PARTIAL)
3000 pt = argvars[0].vval.v_partial;
3001 else
3002 {
Bram Moolenaara80faa82020-04-12 19:37:17 +02003003 CLEAR_FIELD(fref_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003004 fref_pt.pt_name = argvars[0].vval.v_string;
3005 pt = &fref_pt;
3006 }
3007
3008 if (pt != NULL)
3009 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003010 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003011 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003012
3013 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3014 {
3015 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003016 n = partial_name(pt);
3017 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003018 rettv->vval.v_string = NULL;
3019 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003020 {
3021 rettv->vval.v_string = vim_strsave(n);
3022 if (rettv->v_type == VAR_FUNC)
3023 func_ref(rettv->vval.v_string);
3024 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003025 }
3026 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003027 {
3028 what_is_dict = TRUE;
3029 if (pt->pt_dict != NULL)
3030 rettv_dict_set(rettv, pt->pt_dict);
3031 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003032 else if (STRCMP(what, "args") == 0)
3033 {
3034 rettv->v_type = VAR_LIST;
3035 if (rettv_list_alloc(rettv) == OK)
3036 {
3037 int i;
3038
3039 for (i = 0; i < pt->pt_argc; ++i)
3040 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3041 }
3042 }
3043 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003044 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003045
3046 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3047 // third argument
3048 if (!what_is_dict)
3049 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003050 }
3051 }
3052 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003053 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003054
3055 if (tv == NULL)
3056 {
3057 if (argvars[2].v_type != VAR_UNKNOWN)
3058 copy_tv(&argvars[2], rettv);
3059 }
3060 else
3061 copy_tv(tv, rettv);
3062}
3063
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003064/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003065 * "getchangelist()" function
3066 */
3067 static void
3068f_getchangelist(typval_T *argvars, typval_T *rettv)
3069{
3070#ifdef FEAT_JUMPLIST
3071 buf_T *buf;
3072 int i;
3073 list_T *l;
3074 dict_T *d;
3075#endif
3076
3077 if (rettv_list_alloc(rettv) != OK)
3078 return;
3079
3080#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003081 if (argvars[0].v_type == VAR_UNKNOWN)
3082 buf = curbuf;
3083 else
Bram Moolenaara5d38412020-09-02 21:02:35 +02003084 buf = tv_get_buf_from_arg(&argvars[0]);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003085 if (buf == NULL)
3086 return;
3087
3088 l = list_alloc();
3089 if (l == NULL)
3090 return;
3091
3092 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3093 return;
3094 /*
3095 * The current window change list index tracks only the position in the
3096 * current buffer change list. For other buffers, use the change list
3097 * length as the current index.
3098 */
3099 list_append_number(rettv->vval.v_list,
3100 (varnumber_T)((buf == curwin->w_buffer)
3101 ? curwin->w_changelistidx : buf->b_changelistlen));
3102
3103 for (i = 0; i < buf->b_changelistlen; ++i)
3104 {
3105 if (buf->b_changelist[i].lnum == 0)
3106 continue;
3107 if ((d = dict_alloc()) == NULL)
3108 return;
3109 if (list_append_dict(l, d) == FAIL)
3110 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003111 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3112 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003113 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003114 }
3115#endif
3116}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003117
3118/*
3119 * "getcharsearch()" function
3120 */
3121 static void
3122f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3123{
3124 if (rettv_dict_alloc(rettv) != FAIL)
3125 {
3126 dict_T *dict = rettv->vval.v_dict;
3127
Bram Moolenaare0be1672018-07-08 16:50:37 +02003128 dict_add_string(dict, "char", last_csearch());
3129 dict_add_number(dict, "forward", last_csearch_forward());
3130 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003131 }
3132}
3133
3134/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003135 * "getenv()" function
3136 */
3137 static void
3138f_getenv(typval_T *argvars, typval_T *rettv)
3139{
3140 int mustfree = FALSE;
3141 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3142
3143 if (p == NULL)
3144 {
3145 rettv->v_type = VAR_SPECIAL;
3146 rettv->vval.v_number = VVAL_NULL;
3147 return;
3148 }
3149 if (!mustfree)
3150 p = vim_strsave(p);
3151 rettv->vval.v_string = p;
3152 rettv->v_type = VAR_STRING;
3153}
3154
3155/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003156 * "getfontname()" function
3157 */
3158 static void
3159f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3160{
3161 rettv->v_type = VAR_STRING;
3162 rettv->vval.v_string = NULL;
3163#ifdef FEAT_GUI
3164 if (gui.in_use)
3165 {
3166 GuiFont font;
3167 char_u *name = NULL;
3168
3169 if (argvars[0].v_type == VAR_UNKNOWN)
3170 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003171 // Get the "Normal" font. Either the name saved by
3172 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003173 font = gui.norm_font;
3174 name = hl_get_font_name();
3175 }
3176 else
3177 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003178 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003179 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003180 return;
3181 font = gui_mch_get_font(name, FALSE);
3182 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003183 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003184 }
3185 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3186 if (argvars[0].v_type != VAR_UNKNOWN)
3187 gui_mch_free_font(font);
3188 }
3189#endif
3190}
3191
3192/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003193 * "getjumplist()" function
3194 */
3195 static void
3196f_getjumplist(typval_T *argvars, typval_T *rettv)
3197{
3198#ifdef FEAT_JUMPLIST
3199 win_T *wp;
3200 int i;
3201 list_T *l;
3202 dict_T *d;
3203#endif
3204
3205 if (rettv_list_alloc(rettv) != OK)
3206 return;
3207
3208#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003209 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003210 if (wp == NULL)
3211 return;
3212
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003213 cleanup_jumplist(wp, TRUE);
3214
Bram Moolenaar4f505882018-02-10 21:06:32 +01003215 l = list_alloc();
3216 if (l == NULL)
3217 return;
3218
3219 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3220 return;
3221 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3222
3223 for (i = 0; i < wp->w_jumplistlen; ++i)
3224 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003225 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3226 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003227 if ((d = dict_alloc()) == NULL)
3228 return;
3229 if (list_append_dict(l, d) == FAIL)
3230 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003231 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3232 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003233 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003234 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003235 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003236 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003237 }
3238#endif
3239}
3240
3241/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003242 * "getpid()" function
3243 */
3244 static void
3245f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3246{
3247 rettv->vval.v_number = mch_get_pid();
3248}
3249
3250 static void
3251getpos_both(
3252 typval_T *argvars,
3253 typval_T *rettv,
3254 int getcurpos)
3255{
3256 pos_T *fp;
3257 list_T *l;
3258 int fnum = -1;
3259
3260 if (rettv_list_alloc(rettv) == OK)
3261 {
3262 l = rettv->vval.v_list;
3263 if (getcurpos)
3264 fp = &curwin->w_cursor;
3265 else
3266 fp = var2fpos(&argvars[0], TRUE, &fnum);
3267 if (fnum != -1)
3268 list_append_number(l, (varnumber_T)fnum);
3269 else
3270 list_append_number(l, (varnumber_T)0);
3271 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3272 : (varnumber_T)0);
3273 list_append_number(l, (fp != NULL)
3274 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3275 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003276 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003277 (varnumber_T)0);
3278 if (getcurpos)
3279 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003280 int save_set_curswant = curwin->w_set_curswant;
3281 colnr_T save_curswant = curwin->w_curswant;
3282 colnr_T save_virtcol = curwin->w_virtcol;
3283
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003284 update_curswant();
3285 list_append_number(l, curwin->w_curswant == MAXCOL ?
3286 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003287
3288 // Do not change "curswant", as it is unexpected that a get
3289 // function has a side effect.
3290 if (save_set_curswant)
3291 {
3292 curwin->w_set_curswant = save_set_curswant;
3293 curwin->w_curswant = save_curswant;
3294 curwin->w_virtcol = save_virtcol;
3295 curwin->w_valid &= ~VALID_VIRTCOL;
3296 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 }
3298 }
3299 else
3300 rettv->vval.v_number = FALSE;
3301}
3302
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003303/*
3304 * "getcurpos()" function
3305 */
3306 static void
3307f_getcurpos(typval_T *argvars, typval_T *rettv)
3308{
3309 getpos_both(argvars, rettv, TRUE);
3310}
3311
3312/*
3313 * "getpos(string)" function
3314 */
3315 static void
3316f_getpos(typval_T *argvars, typval_T *rettv)
3317{
3318 getpos_both(argvars, rettv, FALSE);
3319}
3320
3321/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003322 * "getreg()" function
3323 */
3324 static void
3325f_getreg(typval_T *argvars, typval_T *rettv)
3326{
3327 char_u *strregname;
3328 int regname;
3329 int arg2 = FALSE;
3330 int return_list = FALSE;
3331 int error = FALSE;
3332
3333 if (argvars[0].v_type != VAR_UNKNOWN)
3334 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003335 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003336 error = strregname == NULL;
3337 if (argvars[1].v_type != VAR_UNKNOWN)
3338 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003339 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003340 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003341 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342 }
3343 }
3344 else
3345 strregname = get_vim_var_str(VV_REG);
3346
3347 if (error)
3348 return;
3349
3350 regname = (strregname == NULL ? '"' : *strregname);
3351 if (regname == 0)
3352 regname = '"';
3353
3354 if (return_list)
3355 {
3356 rettv->v_type = VAR_LIST;
3357 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3358 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3359 if (rettv->vval.v_list == NULL)
3360 (void)rettv_list_alloc(rettv);
3361 else
3362 ++rettv->vval.v_list->lv_refcount;
3363 }
3364 else
3365 {
3366 rettv->v_type = VAR_STRING;
3367 rettv->vval.v_string = get_reg_contents(regname,
3368 arg2 ? GREG_EXPR_SRC : 0);
3369 }
3370}
3371
3372/*
3373 * "getregtype()" function
3374 */
3375 static void
3376f_getregtype(typval_T *argvars, typval_T *rettv)
3377{
3378 char_u *strregname;
3379 int regname;
3380 char_u buf[NUMBUFLEN + 2];
3381 long reglen = 0;
3382
3383 if (argvars[0].v_type != VAR_UNKNOWN)
3384 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003385 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003386 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003387 {
3388 rettv->v_type = VAR_STRING;
3389 rettv->vval.v_string = NULL;
3390 return;
3391 }
3392 }
3393 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003394 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 strregname = get_vim_var_str(VV_REG);
3396
3397 regname = (strregname == NULL ? '"' : *strregname);
3398 if (regname == 0)
3399 regname = '"';
3400
3401 buf[0] = NUL;
3402 buf[1] = NUL;
3403 switch (get_reg_type(regname, &reglen))
3404 {
3405 case MLINE: buf[0] = 'V'; break;
3406 case MCHAR: buf[0] = 'v'; break;
3407 case MBLOCK:
3408 buf[0] = Ctrl_V;
3409 sprintf((char *)buf + 1, "%ld", reglen + 1);
3410 break;
3411 }
3412 rettv->v_type = VAR_STRING;
3413 rettv->vval.v_string = vim_strsave(buf);
3414}
3415
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003416/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003417 * "gettagstack()" function
3418 */
3419 static void
3420f_gettagstack(typval_T *argvars, typval_T *rettv)
3421{
3422 win_T *wp = curwin; // default is current window
3423
3424 if (rettv_dict_alloc(rettv) != OK)
3425 return;
3426
3427 if (argvars[0].v_type != VAR_UNKNOWN)
3428 {
3429 wp = find_win_by_nr_or_id(&argvars[0]);
3430 if (wp == NULL)
3431 return;
3432 }
3433
3434 get_tagstack(wp, rettv->vval.v_dict);
3435}
3436
Bram Moolenaar0b39c3f2020-08-30 15:52:10 +02003437/*
3438 * "gettext()" function
3439 */
3440 static void
3441f_gettext(typval_T *argvars, typval_T *rettv)
3442{
3443 if (argvars[0].v_type != VAR_STRING
3444 || argvars[0].vval.v_string == NULL
3445 || *argvars[0].vval.v_string == NUL)
3446 {
3447 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
3448 }
3449 else
3450 {
3451 rettv->v_type = VAR_STRING;
3452 rettv->vval.v_string = vim_strsave(
3453 (char_u *)_(argvars[0].vval.v_string));
3454 }
3455}
3456
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003457// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003458#include "version.h"
3459
3460/*
3461 * "has()" function
3462 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003463 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003464f_has(typval_T *argvars, typval_T *rettv)
3465{
3466 int i;
3467 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003468 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003469 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003470 typedef struct {
3471 char *name;
3472 short present;
3473 } has_item_T;
3474 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003476 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003477#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003478 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003479#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003480 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003481#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003482 },
3483 {"arp",
3484#if defined(AMIGA) && defined(FEAT_ARP)
3485 1
3486#else
3487 0
3488#endif
3489 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003490 {"haiku",
3491#ifdef __HAIKU__
3492 1
3493#else
3494 0
3495#endif
3496 },
3497 {"bsd",
3498#if defined(BSD) && !defined(MACOS_X)
3499 1
3500#else
3501 0
3502#endif
3503 },
3504 {"hpux",
3505#ifdef hpux
3506 1
3507#else
3508 0
3509#endif
3510 },
3511 {"linux",
3512#ifdef __linux__
3513 1
3514#else
3515 0
3516#endif
3517 },
3518 {"mac", // Mac OS X (and, once, Mac OS Classic)
3519#ifdef MACOS_X
3520 1
3521#else
3522 0
3523#endif
3524 },
3525 {"osx", // Mac OS X
3526#ifdef MACOS_X
3527 1
3528#else
3529 0
3530#endif
3531 },
3532 {"macunix", // Mac OS X, with the darwin feature
3533#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3534 1
3535#else
3536 0
3537#endif
3538 },
3539 {"osxdarwin", // synonym for macunix
3540#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3541 1
3542#else
3543 0
3544#endif
3545 },
3546 {"qnx",
3547#ifdef __QNX__
3548 1
3549#else
3550 0
3551#endif
3552 },
3553 {"sun",
3554#ifdef SUN_SYSTEM
3555 1
3556#else
3557 0
3558#endif
3559 },
3560 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003562 1
3563#else
3564 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003566 },
3567 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003569 1
3570#else
3571 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003573 },
3574 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003575#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003576 1
3577#else
3578 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003579#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003580 },
3581 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003582#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003583 1
3584#else
3585 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003586#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003587 },
3588 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003589#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003590 1
3591#else
3592 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003593#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003594 },
3595 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003596#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003597 1
3598#else
3599 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003601 },
3602 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003604 1
3605#else
3606 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003608 },
3609 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003610#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003611 1
3612#else
3613 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003614#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003615 },
3616 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003617#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003618 1
3619#else
3620 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003621#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003622 },
3623 {"autocmd", 1},
3624 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003625#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003626 1
3627#else
3628 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003629#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003630 },
3631 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003632#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003633 1
3634#else
3635 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003636#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003637 },
3638 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003639#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003640 1
3641#else
3642 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003644 },
3645 {"balloon_multiline",
3646#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3647 // MS-Windows requires runtime check, see below
3648 1
3649#else
3650 0
3651#endif
3652 },
3653 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003654#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003655 1
3656#else
3657 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003658#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003659 },
3660 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003662 1
3663#else
3664 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003665#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003666 },
3667 {"all_builtin_terms",
3668#if defined(ALL_BUILTIN_TCAPS)
3669 1
3670#else
3671 0
3672#endif
3673 },
3674 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003675#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003676 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003678 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003679#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003680 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003682 },
3683 {"byte_offset",
3684#ifdef FEAT_BYTEOFF
3685 1
3686#else
3687 0
3688#endif
3689 },
3690 {"channel",
3691#ifdef FEAT_JOB_CHANNEL
3692 1
3693#else
3694 0
3695#endif
3696 },
3697 {"cindent",
3698#ifdef FEAT_CINDENT
3699 1
3700#else
3701 0
3702#endif
3703 },
3704 {"clientserver",
3705#ifdef FEAT_CLIENTSERVER
3706 1
3707#else
3708 0
3709#endif
3710 },
3711 {"clipboard",
3712#ifdef FEAT_CLIPBOARD
3713 1
3714#else
3715 0
3716#endif
3717 },
3718 {"cmdline_compl", 1},
3719 {"cmdline_hist", 1},
3720 {"comments", 1},
3721 {"conceal",
3722#ifdef FEAT_CONCEAL
3723 1
3724#else
3725 0
3726#endif
3727 },
3728 {"cryptv",
3729#ifdef FEAT_CRYPT
3730 1
3731#else
3732 0
3733#endif
3734 },
3735 {"crypt-blowfish",
3736#ifdef FEAT_CRYPT
3737 1
3738#else
3739 0
3740#endif
3741 },
3742 {"crypt-blowfish2",
3743#ifdef FEAT_CRYPT
3744 1
3745#else
3746 0
3747#endif
3748 },
3749 {"cscope",
3750#ifdef FEAT_CSCOPE
3751 1
3752#else
3753 0
3754#endif
3755 },
3756 {"cursorbind", 1},
3757 {"cursorshape",
3758#ifdef CURSOR_SHAPE
3759 1
3760#else
3761 0
3762#endif
3763 },
3764 {"debug",
3765#ifdef DEBUG
3766 1
3767#else
3768 0
3769#endif
3770 },
3771 {"dialog_con",
3772#ifdef FEAT_CON_DIALOG
3773 1
3774#else
3775 0
3776#endif
3777 },
3778 {"dialog_gui",
3779#ifdef FEAT_GUI_DIALOG
3780 1
3781#else
3782 0
3783#endif
3784 },
3785 {"diff",
3786#ifdef FEAT_DIFF
3787 1
3788#else
3789 0
3790#endif
3791 },
3792 {"digraphs",
3793#ifdef FEAT_DIGRAPHS
3794 1
3795#else
3796 0
3797#endif
3798 },
3799 {"directx",
3800#ifdef FEAT_DIRECTX
3801 1
3802#else
3803 0
3804#endif
3805 },
3806 {"dnd",
3807#ifdef FEAT_DND
3808 1
3809#else
3810 0
3811#endif
3812 },
3813 {"emacs_tags",
3814#ifdef FEAT_EMACS_TAGS
3815 1
3816#else
3817 0
3818#endif
3819 },
3820 {"eval", 1}, // always present, of course!
3821 {"ex_extra", 1}, // graduated feature
3822 {"extra_search",
3823#ifdef FEAT_SEARCH_EXTRA
3824 1
3825#else
3826 0
3827#endif
3828 },
3829 {"file_in_path",
3830#ifdef FEAT_SEARCHPATH
3831 1
3832#else
3833 0
3834#endif
3835 },
3836 {"filterpipe",
3837#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3838 1
3839#else
3840 0
3841#endif
3842 },
3843 {"find_in_path",
3844#ifdef FEAT_FIND_ID
3845 1
3846#else
3847 0
3848#endif
3849 },
3850 {"float",
3851#ifdef FEAT_FLOAT
3852 1
3853#else
3854 0
3855#endif
3856 },
3857 {"folding",
3858#ifdef FEAT_FOLDING
3859 1
3860#else
3861 0
3862#endif
3863 },
3864 {"footer",
3865#ifdef FEAT_FOOTER
3866 1
3867#else
3868 0
3869#endif
3870 },
3871 {"fork",
3872#if !defined(USE_SYSTEM) && defined(UNIX)
3873 1
3874#else
3875 0
3876#endif
3877 },
3878 {"gettext",
3879#ifdef FEAT_GETTEXT
3880 1
3881#else
3882 0
3883#endif
3884 },
3885 {"gui",
3886#ifdef FEAT_GUI
3887 1
3888#else
3889 0
3890#endif
3891 },
3892 {"gui_neXtaw",
3893#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3894 1
3895#else
3896 0
3897#endif
3898 },
3899 {"gui_athena",
3900#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3901 1
3902#else
3903 0
3904#endif
3905 },
3906 {"gui_gtk",
3907#ifdef FEAT_GUI_GTK
3908 1
3909#else
3910 0
3911#endif
3912 },
3913 {"gui_gtk2",
3914#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3915 1
3916#else
3917 0
3918#endif
3919 },
3920 {"gui_gtk3",
3921#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3922 1
3923#else
3924 0
3925#endif
3926 },
3927 {"gui_gnome",
3928#ifdef FEAT_GUI_GNOME
3929 1
3930#else
3931 0
3932#endif
3933 },
3934 {"gui_haiku",
3935#ifdef FEAT_GUI_HAIKU
3936 1
3937#else
3938 0
3939#endif
3940 },
Bram Moolenaar097148e2020-08-11 21:58:20 +02003941 {"gui_mac", 0},
Bram Moolenaar79296512020-03-22 16:17:14 +01003942 {"gui_motif",
3943#ifdef FEAT_GUI_MOTIF
3944 1
3945#else
3946 0
3947#endif
3948 },
3949 {"gui_photon",
3950#ifdef FEAT_GUI_PHOTON
3951 1
3952#else
3953 0
3954#endif
3955 },
3956 {"gui_win32",
3957#ifdef FEAT_GUI_MSWIN
3958 1
3959#else
3960 0
3961#endif
3962 },
3963 {"iconv",
3964#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3965 1
3966#else
3967 0
3968#endif
3969 },
3970 {"insert_expand", 1},
Bram Moolenaarbfe13cc2020-04-12 17:53:12 +02003971 {"ipv6",
3972#ifdef FEAT_IPV6
3973 1
3974#else
3975 0
3976#endif
3977 },
Bram Moolenaar79296512020-03-22 16:17:14 +01003978 {"job",
3979#ifdef FEAT_JOB_CHANNEL
3980 1
3981#else
3982 0
3983#endif
3984 },
3985 {"jumplist",
3986#ifdef FEAT_JUMPLIST
3987 1
3988#else
3989 0
3990#endif
3991 },
3992 {"keymap",
3993#ifdef FEAT_KEYMAP
3994 1
3995#else
3996 0
3997#endif
3998 },
3999 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
4000 {"langmap",
4001#ifdef FEAT_LANGMAP
4002 1
4003#else
4004 0
4005#endif
4006 },
4007 {"libcall",
4008#ifdef FEAT_LIBCALL
4009 1
4010#else
4011 0
4012#endif
4013 },
4014 {"linebreak",
4015#ifdef FEAT_LINEBREAK
4016 1
4017#else
4018 0
4019#endif
4020 },
4021 {"lispindent",
4022#ifdef FEAT_LISP
4023 1
4024#else
4025 0
4026#endif
4027 },
4028 {"listcmds", 1},
4029 {"localmap", 1},
4030 {"lua",
4031#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
4032 1
4033#else
4034 0
4035#endif
4036 },
4037 {"menu",
4038#ifdef FEAT_MENU
4039 1
4040#else
4041 0
4042#endif
4043 },
4044 {"mksession",
4045#ifdef FEAT_SESSION
4046 1
4047#else
4048 0
4049#endif
4050 },
4051 {"modify_fname", 1},
4052 {"mouse", 1},
4053 {"mouseshape",
4054#ifdef FEAT_MOUSESHAPE
4055 1
4056#else
4057 0
4058#endif
4059 },
4060 {"mouse_dec",
4061#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
4062 1
4063#else
4064 0
4065#endif
4066 },
4067 {"mouse_gpm",
4068#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
4069 1
4070#else
4071 0
4072#endif
4073 },
4074 {"mouse_jsbterm",
4075#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
4076 1
4077#else
4078 0
4079#endif
4080 },
4081 {"mouse_netterm",
4082#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
4083 1
4084#else
4085 0
4086#endif
4087 },
4088 {"mouse_pterm",
4089#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
4090 1
4091#else
4092 0
4093#endif
4094 },
4095 {"mouse_sgr",
4096#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4097 1
4098#else
4099 0
4100#endif
4101 },
4102 {"mouse_sysmouse",
4103#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4104 1
4105#else
4106 0
4107#endif
4108 },
4109 {"mouse_urxvt",
4110#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4111 1
4112#else
4113 0
4114#endif
4115 },
4116 {"mouse_xterm",
4117#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4118 1
4119#else
4120 0
4121#endif
4122 },
4123 {"multi_byte", 1},
4124 {"multi_byte_ime",
4125#ifdef FEAT_MBYTE_IME
4126 1
4127#else
4128 0
4129#endif
4130 },
4131 {"multi_lang",
4132#ifdef FEAT_MULTI_LANG
4133 1
4134#else
4135 0
4136#endif
4137 },
4138 {"mzscheme",
4139#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4140 1
4141#else
4142 0
4143#endif
4144 },
4145 {"num64", 1},
4146 {"ole",
4147#ifdef FEAT_OLE
4148 1
4149#else
4150 0
4151#endif
4152 },
4153 {"packages",
4154#ifdef FEAT_EVAL
4155 1
4156#else
4157 0
4158#endif
4159 },
4160 {"path_extra",
4161#ifdef FEAT_PATH_EXTRA
4162 1
4163#else
4164 0
4165#endif
4166 },
4167 {"perl",
4168#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4169 1
4170#else
4171 0
4172#endif
4173 },
4174 {"persistent_undo",
4175#ifdef FEAT_PERSISTENT_UNDO
4176 1
4177#else
4178 0
4179#endif
4180 },
4181 {"python_compiled",
4182#if defined(FEAT_PYTHON)
4183 1
4184#else
4185 0
4186#endif
4187 },
4188 {"python_dynamic",
4189#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4190 1
4191#else
4192 0
4193#endif
4194 },
4195 {"python",
4196#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4197 1
4198#else
4199 0
4200#endif
4201 },
4202 {"pythonx",
4203#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4204 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4205 1
4206#else
4207 0
4208#endif
4209 },
4210 {"python3_compiled",
4211#if defined(FEAT_PYTHON3)
4212 1
4213#else
4214 0
4215#endif
4216 },
4217 {"python3_dynamic",
4218#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4219 1
4220#else
4221 0
4222#endif
4223 },
4224 {"python3",
4225#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4226 1
4227#else
4228 0
4229#endif
4230 },
4231 {"popupwin",
4232#ifdef FEAT_PROP_POPUP
4233 1
4234#else
4235 0
4236#endif
4237 },
4238 {"postscript",
4239#ifdef FEAT_POSTSCRIPT
4240 1
4241#else
4242 0
4243#endif
4244 },
4245 {"printer",
4246#ifdef FEAT_PRINTER
4247 1
4248#else
4249 0
4250#endif
4251 },
4252 {"profile",
4253#ifdef FEAT_PROFILE
4254 1
4255#else
4256 0
4257#endif
4258 },
4259 {"reltime",
4260#ifdef FEAT_RELTIME
4261 1
4262#else
4263 0
4264#endif
4265 },
4266 {"quickfix",
4267#ifdef FEAT_QUICKFIX
4268 1
4269#else
4270 0
4271#endif
4272 },
4273 {"rightleft",
4274#ifdef FEAT_RIGHTLEFT
4275 1
4276#else
4277 0
4278#endif
4279 },
4280 {"ruby",
4281#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4282 1
4283#else
4284 0
4285#endif
4286 },
4287 {"scrollbind", 1},
4288 {"showcmd",
4289#ifdef FEAT_CMDL_INFO
4290 1
4291#else
4292 0
4293#endif
4294 },
4295 {"cmdline_info",
4296#ifdef FEAT_CMDL_INFO
4297 1
4298#else
4299 0
4300#endif
4301 },
4302 {"signs",
4303#ifdef FEAT_SIGNS
4304 1
4305#else
4306 0
4307#endif
4308 },
4309 {"smartindent",
4310#ifdef FEAT_SMARTINDENT
4311 1
4312#else
4313 0
4314#endif
4315 },
4316 {"startuptime",
4317#ifdef STARTUPTIME
4318 1
4319#else
4320 0
4321#endif
4322 },
4323 {"statusline",
4324#ifdef FEAT_STL_OPT
4325 1
4326#else
4327 0
4328#endif
4329 },
4330 {"netbeans_intg",
4331#ifdef FEAT_NETBEANS_INTG
4332 1
4333#else
4334 0
4335#endif
4336 },
4337 {"sound",
4338#ifdef FEAT_SOUND
4339 1
4340#else
4341 0
4342#endif
4343 },
4344 {"spell",
4345#ifdef FEAT_SPELL
4346 1
4347#else
4348 0
4349#endif
4350 },
4351 {"syntax",
4352#ifdef FEAT_SYN_HL
4353 1
4354#else
4355 0
4356#endif
4357 },
4358 {"system",
4359#if defined(USE_SYSTEM) || !defined(UNIX)
4360 1
4361#else
4362 0
4363#endif
4364 },
4365 {"tag_binary",
4366#ifdef FEAT_TAG_BINS
4367 1
4368#else
4369 0
4370#endif
4371 },
4372 {"tcl",
4373#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4374 1
4375#else
4376 0
4377#endif
4378 },
4379 {"termguicolors",
4380#ifdef FEAT_TERMGUICOLORS
4381 1
4382#else
4383 0
4384#endif
4385 },
4386 {"terminal",
4387#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4388 1
4389#else
4390 0
4391#endif
4392 },
4393 {"terminfo",
4394#ifdef TERMINFO
4395 1
4396#else
4397 0
4398#endif
4399 },
4400 {"termresponse",
4401#ifdef FEAT_TERMRESPONSE
4402 1
4403#else
4404 0
4405#endif
4406 },
4407 {"textobjects",
4408#ifdef FEAT_TEXTOBJ
4409 1
4410#else
4411 0
4412#endif
4413 },
4414 {"textprop",
4415#ifdef FEAT_PROP_POPUP
4416 1
4417#else
4418 0
4419#endif
4420 },
4421 {"tgetent",
4422#ifdef HAVE_TGETENT
4423 1
4424#else
4425 0
4426#endif
4427 },
4428 {"timers",
4429#ifdef FEAT_TIMERS
4430 1
4431#else
4432 0
4433#endif
4434 },
4435 {"title",
4436#ifdef FEAT_TITLE
4437 1
4438#else
4439 0
4440#endif
4441 },
4442 {"toolbar",
4443#ifdef FEAT_TOOLBAR
4444 1
4445#else
4446 0
4447#endif
4448 },
4449 {"unnamedplus",
4450#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4451 1
4452#else
4453 0
4454#endif
4455 },
4456 {"user-commands", 1}, // was accidentally included in 5.4
4457 {"user_commands", 1},
4458 {"vartabs",
4459#ifdef FEAT_VARTABS
4460 1
4461#else
4462 0
4463#endif
4464 },
4465 {"vertsplit", 1},
4466 {"viminfo",
4467#ifdef FEAT_VIMINFO
4468 1
4469#else
4470 0
4471#endif
4472 },
4473 {"vimscript-1", 1},
4474 {"vimscript-2", 1},
4475 {"vimscript-3", 1},
4476 {"vimscript-4", 1},
4477 {"virtualedit", 1},
4478 {"visual", 1},
4479 {"visualextra", 1},
4480 {"vreplace", 1},
4481 {"vtp",
4482#ifdef FEAT_VTP
4483 1
4484#else
4485 0
4486#endif
4487 },
4488 {"wildignore",
4489#ifdef FEAT_WILDIGN
4490 1
4491#else
4492 0
4493#endif
4494 },
4495 {"wildmenu",
4496#ifdef FEAT_WILDMENU
4497 1
4498#else
4499 0
4500#endif
4501 },
4502 {"windows", 1},
4503 {"winaltkeys",
4504#ifdef FEAT_WAK
4505 1
4506#else
4507 0
4508#endif
4509 },
4510 {"writebackup",
4511#ifdef FEAT_WRITEBACKUP
4512 1
4513#else
4514 0
4515#endif
4516 },
4517 {"xim",
4518#ifdef FEAT_XIM
4519 1
4520#else
4521 0
4522#endif
4523 },
4524 {"xfontset",
4525#ifdef FEAT_XFONTSET
4526 1
4527#else
4528 0
4529#endif
4530 },
4531 {"xpm",
4532#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4533 1
4534#else
4535 0
4536#endif
4537 },
4538 {"xpm_w32", // for backward compatibility
4539#ifdef FEAT_XPM_W32
4540 1
4541#else
4542 0
4543#endif
4544 },
4545 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004546#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004547 1
4548#else
4549 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004550#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004551 },
4552 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004553#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004554 1
4555#else
4556 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004557#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004558 },
4559 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004561 1
4562#else
4563 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004564#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004565 },
4566 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004567#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004568 1
4569#else
4570 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004571#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004572 },
4573 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004574#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004575 1
4576#else
4577 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004578#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004579 },
4580 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004581 };
4582
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004583 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004584 for (i = 0; has_list[i].name != NULL; ++i)
4585 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004586 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004587 x = TRUE;
4588 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004589 break;
4590 }
4591
Bram Moolenaar79296512020-03-22 16:17:14 +01004592 // features also in has_list[] but sometimes enabled at runtime
4593 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004595 if (0)
Bram Moolenaar86b9a3e2020-04-07 19:57:29 +02004596 {
4597 // intentionally empty
4598 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01004599#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004600 else if (STRICMP(name, "balloon_multiline") == 0)
4601 n = multiline_balloon_available();
4602#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004603#ifdef VIMDLL
4604 else if (STRICMP(name, "filterpipe") == 0)
4605 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004606#endif
4607#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4608 else if (STRICMP(name, "iconv") == 0)
4609 n = iconv_enabled(FALSE);
4610#endif
4611#ifdef DYNAMIC_LUA
4612 else if (STRICMP(name, "lua") == 0)
4613 n = lua_enabled(FALSE);
4614#endif
4615#ifdef DYNAMIC_MZSCHEME
4616 else if (STRICMP(name, "mzscheme") == 0)
4617 n = mzscheme_enabled(FALSE);
4618#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004619#ifdef DYNAMIC_PERL
4620 else if (STRICMP(name, "perl") == 0)
4621 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004623#ifdef DYNAMIC_PYTHON
4624 else if (STRICMP(name, "python") == 0)
4625 n = python_enabled(FALSE);
4626#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004627#ifdef DYNAMIC_PYTHON3
4628 else if (STRICMP(name, "python3") == 0)
4629 n = python3_enabled(FALSE);
4630#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004631#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4632 else if (STRICMP(name, "pythonx") == 0)
4633 {
4634# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4635 if (p_pyx == 0)
4636 n = python3_enabled(FALSE) || python_enabled(FALSE);
4637 else if (p_pyx == 3)
4638 n = python3_enabled(FALSE);
4639 else if (p_pyx == 2)
4640 n = python_enabled(FALSE);
4641# elif defined(DYNAMIC_PYTHON)
4642 n = python_enabled(FALSE);
4643# elif defined(DYNAMIC_PYTHON3)
4644 n = python3_enabled(FALSE);
4645# endif
4646 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004647#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004648#ifdef DYNAMIC_RUBY
4649 else if (STRICMP(name, "ruby") == 0)
4650 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004651#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004652#ifdef DYNAMIC_TCL
4653 else if (STRICMP(name, "tcl") == 0)
4654 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004655#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004656#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004657 else if (STRICMP(name, "terminal") == 0)
4658 n = terminal_enabled();
4659#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004660 }
4661
Bram Moolenaar79296512020-03-22 16:17:14 +01004662 // features not in has_list[]
4663 if (x == FALSE)
4664 {
4665 if (STRNICMP(name, "patch", 5) == 0)
4666 {
4667 x = TRUE;
4668 if (name[5] == '-'
4669 && STRLEN(name) >= 11
4670 && vim_isdigit(name[6])
4671 && vim_isdigit(name[8])
4672 && vim_isdigit(name[10]))
4673 {
4674 int major = atoi((char *)name + 6);
4675 int minor = atoi((char *)name + 8);
4676
4677 // Expect "patch-9.9.01234".
4678 n = (major < VIM_VERSION_MAJOR
4679 || (major == VIM_VERSION_MAJOR
4680 && (minor < VIM_VERSION_MINOR
4681 || (minor == VIM_VERSION_MINOR
4682 && has_patch(atoi((char *)name + 10))))));
4683 }
4684 else
4685 n = has_patch(atoi((char *)name + 5));
4686 }
4687 else if (STRICMP(name, "vim_starting") == 0)
4688 {
4689 x = TRUE;
4690 n = (starting != 0);
4691 }
4692 else if (STRICMP(name, "ttyin") == 0)
4693 {
4694 x = TRUE;
4695 n = mch_input_isatty();
4696 }
4697 else if (STRICMP(name, "ttyout") == 0)
4698 {
4699 x = TRUE;
4700 n = stdout_isatty;
4701 }
4702 else if (STRICMP(name, "multi_byte_encoding") == 0)
4703 {
4704 x = TRUE;
4705 n = has_mbyte;
4706 }
4707 else if (STRICMP(name, "gui_running") == 0)
4708 {
4709 x = TRUE;
4710#ifdef FEAT_GUI
4711 n = (gui.in_use || gui.starting);
4712#endif
4713 }
4714 else if (STRICMP(name, "browse") == 0)
4715 {
4716 x = TRUE;
4717#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4718 n = gui.in_use; // gui_mch_browse() works when GUI is running
4719#endif
4720 }
4721 else if (STRICMP(name, "syntax_items") == 0)
4722 {
4723 x = TRUE;
4724#ifdef FEAT_SYN_HL
4725 n = syntax_present(curwin);
4726#endif
4727 }
4728 else if (STRICMP(name, "vcon") == 0)
4729 {
4730 x = TRUE;
4731#ifdef FEAT_VTP
4732 n = is_term_win32() && has_vtp_working();
4733#endif
4734 }
4735 else if (STRICMP(name, "netbeans_enabled") == 0)
4736 {
4737 x = TRUE;
4738#ifdef FEAT_NETBEANS_INTG
4739 n = netbeans_active();
4740#endif
4741 }
4742 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4743 {
4744 x = TRUE;
4745#ifdef FEAT_MOUSE_GPM
4746 n = gpm_enabled();
4747#endif
4748 }
4749 else if (STRICMP(name, "conpty") == 0)
4750 {
4751 x = TRUE;
4752#if defined(FEAT_TERMINAL) && defined(MSWIN)
4753 n = use_conpty();
4754#endif
4755 }
4756 else if (STRICMP(name, "clipboard_working") == 0)
4757 {
4758 x = TRUE;
4759#ifdef FEAT_CLIPBOARD
4760 n = clip_star.available;
4761#endif
4762 }
4763 }
4764
4765 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4766 // return whether feature could ever be enabled
4767 rettv->vval.v_number = x;
4768 else
4769 // return whether feature is enabled
4770 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004771}
4772
4773/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004774 * "haslocaldir()" function
4775 */
4776 static void
4777f_haslocaldir(typval_T *argvars, typval_T *rettv)
4778{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004779 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004780 win_T *wp = NULL;
4781
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004782 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4783
4784 // Check for window-local and tab-local directories
4785 if (wp != NULL && wp->w_localdir != NULL)
4786 rettv->vval.v_number = 1;
4787 else if (tp != NULL && tp->tp_localdir != NULL)
4788 rettv->vval.v_number = 2;
4789 else
4790 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004791}
4792
4793/*
4794 * "hasmapto()" function
4795 */
4796 static void
4797f_hasmapto(typval_T *argvars, typval_T *rettv)
4798{
4799 char_u *name;
4800 char_u *mode;
4801 char_u buf[NUMBUFLEN];
4802 int abbr = FALSE;
4803
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004804 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004805 if (argvars[1].v_type == VAR_UNKNOWN)
4806 mode = (char_u *)"nvo";
4807 else
4808 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004809 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004810 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004811 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004812 }
4813
4814 if (map_to_exists(name, mode, abbr))
4815 rettv->vval.v_number = TRUE;
4816 else
4817 rettv->vval.v_number = FALSE;
4818}
4819
4820/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004821 * "highlightID(name)" function
4822 */
4823 static void
4824f_hlID(typval_T *argvars, typval_T *rettv)
4825{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004826 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004827}
4828
4829/*
4830 * "highlight_exists()" function
4831 */
4832 static void
4833f_hlexists(typval_T *argvars, typval_T *rettv)
4834{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004835 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004836}
4837
4838/*
4839 * "hostname()" function
4840 */
4841 static void
4842f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4843{
4844 char_u hostname[256];
4845
4846 mch_get_host_name(hostname, 256);
4847 rettv->v_type = VAR_STRING;
4848 rettv->vval.v_string = vim_strsave(hostname);
4849}
4850
4851/*
4852 * iconv() function
4853 */
4854 static void
4855f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4856{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004857 char_u buf1[NUMBUFLEN];
4858 char_u buf2[NUMBUFLEN];
4859 char_u *from, *to, *str;
4860 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861
4862 rettv->v_type = VAR_STRING;
4863 rettv->vval.v_string = NULL;
4864
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004865 str = tv_get_string(&argvars[0]);
4866 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4867 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004868 vimconv.vc_type = CONV_NONE;
4869 convert_setup(&vimconv, from, to);
4870
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004871 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004872 if (vimconv.vc_type == CONV_NONE)
4873 rettv->vval.v_string = vim_strsave(str);
4874 else
4875 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4876
4877 convert_setup(&vimconv, NULL, NULL);
4878 vim_free(from);
4879 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004880}
4881
4882/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004883 * "index()" function
4884 */
4885 static void
4886f_index(typval_T *argvars, typval_T *rettv)
4887{
4888 list_T *l;
4889 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004890 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004891 long idx = 0;
4892 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004893 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894
4895 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004896 if (argvars[0].v_type == VAR_BLOB)
4897 {
4898 typval_T tv;
4899 int start = 0;
4900
4901 if (argvars[2].v_type != VAR_UNKNOWN)
4902 {
4903 start = tv_get_number_chk(&argvars[2], &error);
4904 if (error)
4905 return;
4906 }
4907 b = argvars[0].vval.v_blob;
4908 if (b == NULL)
4909 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004910 if (start < 0)
4911 {
4912 start = blob_len(b) + start;
4913 if (start < 0)
4914 start = 0;
4915 }
4916
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004917 for (idx = start; idx < blob_len(b); ++idx)
4918 {
4919 tv.v_type = VAR_NUMBER;
4920 tv.vval.v_number = blob_get(b, idx);
4921 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4922 {
4923 rettv->vval.v_number = idx;
4924 return;
4925 }
4926 }
4927 return;
4928 }
4929 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004931 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004932 return;
4933 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004934
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935 l = argvars[0].vval.v_list;
4936 if (l != NULL)
4937 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02004938 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004939 item = l->lv_first;
4940 if (argvars[2].v_type != VAR_UNKNOWN)
4941 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004942 // Start at specified item. Use the cached index that list_find()
4943 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004944 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004945 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004947 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004948 if (error)
4949 item = NULL;
4950 }
4951
4952 for ( ; item != NULL; item = item->li_next, ++idx)
4953 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4954 {
4955 rettv->vval.v_number = idx;
4956 break;
4957 }
4958 }
4959}
4960
4961static int inputsecret_flag = 0;
4962
4963/*
4964 * "input()" function
4965 * Also handles inputsecret() when inputsecret is set.
4966 */
4967 static void
4968f_input(typval_T *argvars, typval_T *rettv)
4969{
4970 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4971}
4972
4973/*
4974 * "inputdialog()" function
4975 */
4976 static void
4977f_inputdialog(typval_T *argvars, typval_T *rettv)
4978{
4979#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004980 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004981 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4982 {
4983 char_u *message;
4984 char_u buf[NUMBUFLEN];
4985 char_u *defstr = (char_u *)"";
4986
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004987 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004988 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004989 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004990 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4991 else
4992 IObuff[0] = NUL;
4993 if (message != NULL && defstr != NULL
4994 && do_dialog(VIM_QUESTION, NULL, message,
4995 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4996 rettv->vval.v_string = vim_strsave(IObuff);
4997 else
4998 {
4999 if (message != NULL && defstr != NULL
5000 && argvars[1].v_type != VAR_UNKNOWN
5001 && argvars[2].v_type != VAR_UNKNOWN)
5002 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005003 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005004 else
5005 rettv->vval.v_string = NULL;
5006 }
5007 rettv->v_type = VAR_STRING;
5008 }
5009 else
5010#endif
5011 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5012}
5013
5014/*
5015 * "inputlist()" function
5016 */
5017 static void
5018f_inputlist(typval_T *argvars, typval_T *rettv)
5019{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005020 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005021 listitem_T *li;
5022 int selected;
5023 int mouse_used;
5024
5025#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005026 // While starting up, there is no place to enter text. When running tests
5027 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02005028 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005029 return;
5030#endif
5031 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5032 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005033 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034 return;
5035 }
5036
5037 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005038 msg_row = Rows - 1; // for when 'cmdheight' > 1
5039 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005040 msg_scroll = TRUE;
5041 msg_clr_eos();
5042
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005043 l = argvars[0].vval.v_list;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005044 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02005045 FOR_ALL_LIST_ITEMS(l, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005046 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005047 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005048 msg_putchar('\n');
5049 }
5050
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005051 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005052 selected = prompt_for_number(&mouse_used);
5053 if (mouse_used)
5054 selected -= lines_left;
5055
5056 rettv->vval.v_number = selected;
5057}
5058
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005059static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5060
5061/*
5062 * "inputrestore()" function
5063 */
5064 static void
5065f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5066{
5067 if (ga_userinput.ga_len > 0)
5068 {
5069 --ga_userinput.ga_len;
5070 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5071 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005072 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005073 }
5074 else if (p_verbose > 1)
5075 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005076 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005077 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005078 }
5079}
5080
5081/*
5082 * "inputsave()" function
5083 */
5084 static void
5085f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5086{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005087 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005088 if (ga_grow(&ga_userinput, 1) == OK)
5089 {
5090 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5091 + ga_userinput.ga_len);
5092 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005093 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094 }
5095 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005096 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097}
5098
5099/*
5100 * "inputsecret()" function
5101 */
5102 static void
5103f_inputsecret(typval_T *argvars, typval_T *rettv)
5104{
5105 ++cmdline_star;
5106 ++inputsecret_flag;
5107 f_input(argvars, rettv);
5108 --cmdline_star;
5109 --inputsecret_flag;
5110}
5111
5112/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005113 * "interrupt()" function
5114 */
5115 static void
5116f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5117{
5118 got_int = TRUE;
5119}
5120
5121/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005122 * "invert(expr)" function
5123 */
5124 static void
5125f_invert(typval_T *argvars, typval_T *rettv)
5126{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005127 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005128}
5129
5130/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005131 * "islocked()" function
5132 */
5133 static void
5134f_islocked(typval_T *argvars, typval_T *rettv)
5135{
5136 lval_T lv;
5137 char_u *end;
5138 dictitem_T *di;
5139
5140 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005141 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005142 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005143 if (end != NULL && lv.ll_name != NULL)
5144 {
5145 if (*end != NUL)
Bram Moolenaar2d06bfd2020-07-23 17:16:18 +02005146 semsg(_(e_trailing_arg), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005147 else
5148 {
5149 if (lv.ll_tv == NULL)
5150 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005151 di = find_var(lv.ll_name, NULL, TRUE);
5152 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005153 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005154 // Consider a variable locked when:
5155 // 1. the variable itself is locked
5156 // 2. the value of the variable is locked.
5157 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005158 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5159 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005160 }
5161 }
5162 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005163 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005164 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005165 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005166 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005167 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005168 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5169 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005170 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5172 }
5173 }
5174
5175 clear_lval(&lv);
5176}
5177
5178#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5179/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005180 * "isinf()" function
5181 */
5182 static void
5183f_isinf(typval_T *argvars, typval_T *rettv)
5184{
5185 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5186 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5187}
5188
5189/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005190 * "isnan()" function
5191 */
5192 static void
5193f_isnan(typval_T *argvars, typval_T *rettv)
5194{
5195 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5196 && isnan(argvars[0].vval.v_float);
5197}
5198#endif
5199
5200/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 * "last_buffer_nr()" function.
5202 */
5203 static void
5204f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5205{
5206 int n = 0;
5207 buf_T *buf;
5208
Bram Moolenaar29323592016-07-24 22:04:11 +02005209 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005210 if (n < buf->b_fnum)
5211 n = buf->b_fnum;
5212
5213 rettv->vval.v_number = n;
5214}
5215
5216/*
5217 * "len()" function
5218 */
5219 static void
5220f_len(typval_T *argvars, typval_T *rettv)
5221{
5222 switch (argvars[0].v_type)
5223 {
5224 case VAR_STRING:
5225 case VAR_NUMBER:
5226 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005227 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005228 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005229 case VAR_BLOB:
5230 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5231 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005232 case VAR_LIST:
5233 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5234 break;
5235 case VAR_DICT:
5236 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5237 break;
5238 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02005239 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005240 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005241 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242 case VAR_SPECIAL:
5243 case VAR_FLOAT:
5244 case VAR_FUNC:
5245 case VAR_PARTIAL:
5246 case VAR_JOB:
5247 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005248 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005249 break;
5250 }
5251}
5252
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005253 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005254libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005255{
5256#ifdef FEAT_LIBCALL
5257 char_u *string_in;
5258 char_u **string_result;
5259 int nr_result;
5260#endif
5261
5262 rettv->v_type = type;
5263 if (type != VAR_NUMBER)
5264 rettv->vval.v_string = NULL;
5265
5266 if (check_restricted() || check_secure())
5267 return;
5268
5269#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005270 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005271 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5272 {
5273 string_in = NULL;
5274 if (argvars[2].v_type == VAR_STRING)
5275 string_in = argvars[2].vval.v_string;
5276 if (type == VAR_NUMBER)
5277 string_result = NULL;
5278 else
5279 string_result = &rettv->vval.v_string;
5280 if (mch_libcall(argvars[0].vval.v_string,
5281 argvars[1].vval.v_string,
5282 string_in,
5283 argvars[2].vval.v_number,
5284 string_result,
5285 &nr_result) == OK
5286 && type == VAR_NUMBER)
5287 rettv->vval.v_number = nr_result;
5288 }
5289#endif
5290}
5291
5292/*
5293 * "libcall()" function
5294 */
5295 static void
5296f_libcall(typval_T *argvars, typval_T *rettv)
5297{
5298 libcall_common(argvars, rettv, VAR_STRING);
5299}
5300
5301/*
5302 * "libcallnr()" function
5303 */
5304 static void
5305f_libcallnr(typval_T *argvars, typval_T *rettv)
5306{
5307 libcall_common(argvars, rettv, VAR_NUMBER);
5308}
5309
5310/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005311 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005312 */
5313 static void
5314f_line(typval_T *argvars, typval_T *rettv)
5315{
5316 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005317 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005318 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005319 int id;
5320 tabpage_T *tp;
5321 win_T *wp;
5322 win_T *save_curwin;
5323 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005324
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005325 if (argvars[1].v_type != VAR_UNKNOWN)
5326 {
5327 // use window specified in the second argument
5328 id = (int)tv_get_number(&argvars[1]);
5329 wp = win_id2wp_tp(id, &tp);
5330 if (wp != NULL && tp != NULL)
5331 {
5332 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5333 == OK)
5334 {
5335 check_cursor();
5336 fp = var2fpos(&argvars[0], TRUE, &fnum);
5337 }
5338 restore_win_noblock(save_curwin, save_curtab, TRUE);
5339 }
5340 }
5341 else
5342 // use current window
5343 fp = var2fpos(&argvars[0], TRUE, &fnum);
5344
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005345 if (fp != NULL)
5346 lnum = fp->lnum;
5347 rettv->vval.v_number = lnum;
5348}
5349
5350/*
5351 * "line2byte(lnum)" function
5352 */
5353 static void
5354f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5355{
5356#ifndef FEAT_BYTEOFF
5357 rettv->vval.v_number = -1;
5358#else
5359 linenr_T lnum;
5360
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005361 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005362 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5363 rettv->vval.v_number = -1;
5364 else
5365 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5366 if (rettv->vval.v_number >= 0)
5367 ++rettv->vval.v_number;
5368#endif
5369}
5370
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005371#ifdef FEAT_FLOAT
5372/*
5373 * "log()" function
5374 */
5375 static void
5376f_log(typval_T *argvars, typval_T *rettv)
5377{
5378 float_T f = 0.0;
5379
5380 rettv->v_type = VAR_FLOAT;
5381 if (get_float_arg(argvars, &f) == OK)
5382 rettv->vval.v_float = log(f);
5383 else
5384 rettv->vval.v_float = 0.0;
5385}
5386
5387/*
5388 * "log10()" function
5389 */
5390 static void
5391f_log10(typval_T *argvars, typval_T *rettv)
5392{
5393 float_T f = 0.0;
5394
5395 rettv->v_type = VAR_FLOAT;
5396 if (get_float_arg(argvars, &f) == OK)
5397 rettv->vval.v_float = log10(f);
5398 else
5399 rettv->vval.v_float = 0.0;
5400}
5401#endif
5402
5403#ifdef FEAT_LUA
5404/*
5405 * "luaeval()" function
5406 */
5407 static void
5408f_luaeval(typval_T *argvars, typval_T *rettv)
5409{
5410 char_u *str;
5411 char_u buf[NUMBUFLEN];
5412
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005413 if (check_restricted() || check_secure())
5414 return;
5415
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005416 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 do_luaeval(str, argvars + 1, rettv);
5418}
5419#endif
5420
5421/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005422 * "maparg()" function
5423 */
5424 static void
5425f_maparg(typval_T *argvars, typval_T *rettv)
5426{
5427 get_maparg(argvars, rettv, TRUE);
5428}
5429
5430/*
5431 * "mapcheck()" function
5432 */
5433 static void
5434f_mapcheck(typval_T *argvars, typval_T *rettv)
5435{
5436 get_maparg(argvars, rettv, FALSE);
5437}
5438
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005439typedef enum
5440{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005441 MATCH_END, // matchend()
5442 MATCH_MATCH, // match()
5443 MATCH_STR, // matchstr()
5444 MATCH_LIST, // matchlist()
5445 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005446} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005447
5448 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005449find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005450{
5451 char_u *str = NULL;
5452 long len = 0;
5453 char_u *expr = NULL;
5454 char_u *pat;
5455 regmatch_T regmatch;
5456 char_u patbuf[NUMBUFLEN];
5457 char_u strbuf[NUMBUFLEN];
5458 char_u *save_cpo;
5459 long start = 0;
5460 long nth = 1;
5461 colnr_T startcol = 0;
5462 int match = 0;
5463 list_T *l = NULL;
5464 listitem_T *li = NULL;
5465 long idx = 0;
5466 char_u *tofree = NULL;
5467
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005468 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005469 save_cpo = p_cpo;
5470 p_cpo = (char_u *)"";
5471
5472 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005473 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005474 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005475 // type MATCH_LIST: return empty list when there are no matches.
5476 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005477 if (rettv_list_alloc(rettv) == FAIL)
5478 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005479 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005480 && (list_append_string(rettv->vval.v_list,
5481 (char_u *)"", 0) == FAIL
5482 || list_append_number(rettv->vval.v_list,
5483 (varnumber_T)-1) == FAIL
5484 || list_append_number(rettv->vval.v_list,
5485 (varnumber_T)-1) == FAIL
5486 || list_append_number(rettv->vval.v_list,
5487 (varnumber_T)-1) == FAIL))
5488 {
5489 list_free(rettv->vval.v_list);
5490 rettv->vval.v_list = NULL;
5491 goto theend;
5492 }
5493 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005494 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005495 {
5496 rettv->v_type = VAR_STRING;
5497 rettv->vval.v_string = NULL;
5498 }
5499
5500 if (argvars[0].v_type == VAR_LIST)
5501 {
5502 if ((l = argvars[0].vval.v_list) == NULL)
5503 goto theend;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02005504 CHECK_LIST_MATERIALIZE(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005505 li = l->lv_first;
5506 }
5507 else
5508 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005509 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005510 len = (long)STRLEN(str);
5511 }
5512
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005513 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514 if (pat == NULL)
5515 goto theend;
5516
5517 if (argvars[2].v_type != VAR_UNKNOWN)
5518 {
5519 int error = FALSE;
5520
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005521 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005522 if (error)
5523 goto theend;
5524 if (l != NULL)
5525 {
5526 li = list_find(l, start);
5527 if (li == NULL)
5528 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005529 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005530 }
5531 else
5532 {
5533 if (start < 0)
5534 start = 0;
5535 if (start > len)
5536 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005537 // When "count" argument is there ignore matches before "start",
5538 // otherwise skip part of the string. Differs when pattern is "^"
5539 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005540 if (argvars[3].v_type != VAR_UNKNOWN)
5541 startcol = start;
5542 else
5543 {
5544 str += start;
5545 len -= start;
5546 }
5547 }
5548
5549 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005550 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005551 if (error)
5552 goto theend;
5553 }
5554
5555 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5556 if (regmatch.regprog != NULL)
5557 {
5558 regmatch.rm_ic = p_ic;
5559
5560 for (;;)
5561 {
5562 if (l != NULL)
5563 {
5564 if (li == NULL)
5565 {
5566 match = FALSE;
5567 break;
5568 }
5569 vim_free(tofree);
5570 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5571 if (str == NULL)
5572 break;
5573 }
5574
5575 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5576
5577 if (match && --nth <= 0)
5578 break;
5579 if (l == NULL && !match)
5580 break;
5581
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005582 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005583 if (l != NULL)
5584 {
5585 li = li->li_next;
5586 ++idx;
5587 }
5588 else
5589 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005590 startcol = (colnr_T)(regmatch.startp[0]
5591 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005592 if (startcol > (colnr_T)len
5593 || str + startcol <= regmatch.startp[0])
5594 {
5595 match = FALSE;
5596 break;
5597 }
5598 }
5599 }
5600
5601 if (match)
5602 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005603 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 {
5605 listitem_T *li1 = rettv->vval.v_list->lv_first;
5606 listitem_T *li2 = li1->li_next;
5607 listitem_T *li3 = li2->li_next;
5608 listitem_T *li4 = li3->li_next;
5609
5610 vim_free(li1->li_tv.vval.v_string);
5611 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005612 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005613 li3->li_tv.vval.v_number =
5614 (varnumber_T)(regmatch.startp[0] - expr);
5615 li4->li_tv.vval.v_number =
5616 (varnumber_T)(regmatch.endp[0] - expr);
5617 if (l != NULL)
5618 li2->li_tv.vval.v_number = (varnumber_T)idx;
5619 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005620 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005621 {
5622 int i;
5623
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005624 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625 for (i = 0; i < NSUBEXP; ++i)
5626 {
5627 if (regmatch.endp[i] == NULL)
5628 {
5629 if (list_append_string(rettv->vval.v_list,
5630 (char_u *)"", 0) == FAIL)
5631 break;
5632 }
5633 else if (list_append_string(rettv->vval.v_list,
5634 regmatch.startp[i],
5635 (int)(regmatch.endp[i] - regmatch.startp[i]))
5636 == FAIL)
5637 break;
5638 }
5639 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005640 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005641 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005642 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005643 if (l != NULL)
5644 copy_tv(&li->li_tv, rettv);
5645 else
5646 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
Bram Moolenaardf44a272020-06-07 20:49:05 +02005647 regmatch.endp[0] - regmatch.startp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648 }
5649 else if (l != NULL)
5650 rettv->vval.v_number = idx;
5651 else
5652 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005653 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005654 rettv->vval.v_number =
5655 (varnumber_T)(regmatch.startp[0] - str);
5656 else
5657 rettv->vval.v_number =
5658 (varnumber_T)(regmatch.endp[0] - str);
5659 rettv->vval.v_number += (varnumber_T)(str - expr);
5660 }
5661 }
5662 vim_regfree(regmatch.regprog);
5663 }
5664
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005665theend:
5666 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005667 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005668 listitem_remove(rettv->vval.v_list,
5669 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005670 vim_free(tofree);
5671 p_cpo = save_cpo;
5672}
5673
5674/*
5675 * "match()" function
5676 */
5677 static void
5678f_match(typval_T *argvars, typval_T *rettv)
5679{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005680 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005681}
5682
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005683/*
5684 * "matchend()" function
5685 */
5686 static void
5687f_matchend(typval_T *argvars, typval_T *rettv)
5688{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005689 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005690}
5691
5692/*
5693 * "matchlist()" function
5694 */
5695 static void
5696f_matchlist(typval_T *argvars, typval_T *rettv)
5697{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005698 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005699}
5700
5701/*
5702 * "matchstr()" function
5703 */
5704 static void
5705f_matchstr(typval_T *argvars, typval_T *rettv)
5706{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005707 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005708}
5709
5710/*
5711 * "matchstrpos()" function
5712 */
5713 static void
5714f_matchstrpos(typval_T *argvars, typval_T *rettv)
5715{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005716 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005717}
5718
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005719 static void
5720max_min(typval_T *argvars, typval_T *rettv, int domax)
5721{
5722 varnumber_T n = 0;
5723 varnumber_T i;
5724 int error = FALSE;
5725
5726 if (argvars[0].v_type == VAR_LIST)
5727 {
5728 list_T *l;
5729 listitem_T *li;
5730
5731 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005732 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005733 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005734 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005735 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005736 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5737 n = l->lv_u.nonmat.lv_start;
5738 else
5739 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5740 * l->lv_u.nonmat.lv_stride;
5741 }
5742 else
5743 {
5744 li = l->lv_first;
5745 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005746 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005747 n = tv_get_number_chk(&li->li_tv, &error);
5748 for (;;)
5749 {
5750 li = li->li_next;
5751 if (li == NULL)
5752 break;
5753 i = tv_get_number_chk(&li->li_tv, &error);
5754 if (domax ? i > n : i < n)
5755 n = i;
5756 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005757 }
5758 }
5759 }
5760 }
5761 else if (argvars[0].v_type == VAR_DICT)
5762 {
5763 dict_T *d;
5764 int first = TRUE;
5765 hashitem_T *hi;
5766 int todo;
5767
5768 d = argvars[0].vval.v_dict;
5769 if (d != NULL)
5770 {
5771 todo = (int)d->dv_hashtab.ht_used;
5772 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5773 {
5774 if (!HASHITEM_EMPTY(hi))
5775 {
5776 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005777 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005778 if (first)
5779 {
5780 n = i;
5781 first = FALSE;
5782 }
5783 else if (domax ? i > n : i < n)
5784 n = i;
5785 }
5786 }
5787 }
5788 }
5789 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005790 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791 rettv->vval.v_number = error ? 0 : n;
5792}
5793
5794/*
5795 * "max()" function
5796 */
5797 static void
5798f_max(typval_T *argvars, typval_T *rettv)
5799{
5800 max_min(argvars, rettv, TRUE);
5801}
5802
5803/*
5804 * "min()" function
5805 */
5806 static void
5807f_min(typval_T *argvars, typval_T *rettv)
5808{
5809 max_min(argvars, rettv, FALSE);
5810}
5811
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005812#if defined(FEAT_MZSCHEME) || defined(PROTO)
5813/*
5814 * "mzeval()" function
5815 */
5816 static void
5817f_mzeval(typval_T *argvars, typval_T *rettv)
5818{
5819 char_u *str;
5820 char_u buf[NUMBUFLEN];
5821
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005822 if (check_restricted() || check_secure())
5823 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005824 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005825 do_mzeval(str, rettv);
5826}
5827
5828 void
5829mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5830{
5831 typval_T argvars[3];
5832
5833 argvars[0].v_type = VAR_STRING;
5834 argvars[0].vval.v_string = name;
5835 copy_tv(args, &argvars[1]);
5836 argvars[2].v_type = VAR_UNKNOWN;
5837 f_call(argvars, rettv);
5838 clear_tv(&argvars[1]);
5839}
5840#endif
5841
5842/*
5843 * "nextnonblank()" function
5844 */
5845 static void
5846f_nextnonblank(typval_T *argvars, typval_T *rettv)
5847{
5848 linenr_T lnum;
5849
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005850 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005851 {
5852 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5853 {
5854 lnum = 0;
5855 break;
5856 }
5857 if (*skipwhite(ml_get(lnum)) != NUL)
5858 break;
5859 }
5860 rettv->vval.v_number = lnum;
5861}
5862
5863/*
5864 * "nr2char()" function
5865 */
5866 static void
5867f_nr2char(typval_T *argvars, typval_T *rettv)
5868{
5869 char_u buf[NUMBUFLEN];
5870
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005871 if (has_mbyte)
5872 {
5873 int utf8 = 0;
5874
5875 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005876 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005877 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005878 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005879 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005880 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005881 }
5882 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005883 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005884 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 buf[1] = NUL;
5886 }
5887 rettv->v_type = VAR_STRING;
5888 rettv->vval.v_string = vim_strsave(buf);
5889}
5890
5891/*
5892 * "or(expr, expr)" function
5893 */
5894 static void
5895f_or(typval_T *argvars, typval_T *rettv)
5896{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005897 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5898 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005899}
5900
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005901#ifdef FEAT_PERL
5902/*
5903 * "perleval()" function
5904 */
5905 static void
5906f_perleval(typval_T *argvars, typval_T *rettv)
5907{
5908 char_u *str;
5909 char_u buf[NUMBUFLEN];
5910
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005911 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912 do_perleval(str, rettv);
5913}
5914#endif
5915
5916#ifdef FEAT_FLOAT
5917/*
5918 * "pow()" function
5919 */
5920 static void
5921f_pow(typval_T *argvars, typval_T *rettv)
5922{
5923 float_T fx = 0.0, fy = 0.0;
5924
5925 rettv->v_type = VAR_FLOAT;
5926 if (get_float_arg(argvars, &fx) == OK
5927 && get_float_arg(&argvars[1], &fy) == OK)
5928 rettv->vval.v_float = pow(fx, fy);
5929 else
5930 rettv->vval.v_float = 0.0;
5931}
5932#endif
5933
5934/*
5935 * "prevnonblank()" function
5936 */
5937 static void
5938f_prevnonblank(typval_T *argvars, typval_T *rettv)
5939{
5940 linenr_T lnum;
5941
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005942 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005943 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5944 lnum = 0;
5945 else
5946 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5947 --lnum;
5948 rettv->vval.v_number = lnum;
5949}
5950
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005951// This dummy va_list is here because:
5952// - passing a NULL pointer doesn't work when va_list isn't a pointer
5953// - locally in the function results in a "used before set" warning
5954// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005955static va_list ap;
5956
5957/*
5958 * "printf()" function
5959 */
5960 static void
5961f_printf(typval_T *argvars, typval_T *rettv)
5962{
5963 char_u buf[NUMBUFLEN];
5964 int len;
5965 char_u *s;
5966 int saved_did_emsg = did_emsg;
5967 char *fmt;
5968
5969 rettv->v_type = VAR_STRING;
5970 rettv->vval.v_string = NULL;
5971
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005972 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005973 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005974 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005975 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 if (!did_emsg)
5977 {
5978 s = alloc(len + 1);
5979 if (s != NULL)
5980 {
5981 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005982 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5983 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005984 }
5985 }
5986 did_emsg |= saved_did_emsg;
5987}
5988
5989/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005990 * "pum_getpos()" function
5991 */
5992 static void
5993f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5994{
5995 if (rettv_dict_alloc(rettv) != OK)
5996 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005997 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005998}
5999
6000/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006001 * "pumvisible()" function
6002 */
6003 static void
6004f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6005{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006 if (pum_visible())
6007 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006008}
6009
6010#ifdef FEAT_PYTHON3
6011/*
6012 * "py3eval()" function
6013 */
6014 static void
6015f_py3eval(typval_T *argvars, typval_T *rettv)
6016{
6017 char_u *str;
6018 char_u buf[NUMBUFLEN];
6019
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006020 if (check_restricted() || check_secure())
6021 return;
6022
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006023 if (p_pyx == 0)
6024 p_pyx = 3;
6025
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006026 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006027 do_py3eval(str, rettv);
6028}
6029#endif
6030
6031#ifdef FEAT_PYTHON
6032/*
6033 * "pyeval()" function
6034 */
6035 static void
6036f_pyeval(typval_T *argvars, typval_T *rettv)
6037{
6038 char_u *str;
6039 char_u buf[NUMBUFLEN];
6040
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006041 if (check_restricted() || check_secure())
6042 return;
6043
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006044 if (p_pyx == 0)
6045 p_pyx = 2;
6046
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006047 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006048 do_pyeval(str, rettv);
6049}
6050#endif
6051
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006052#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
6053/*
6054 * "pyxeval()" function
6055 */
6056 static void
6057f_pyxeval(typval_T *argvars, typval_T *rettv)
6058{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006059 if (check_restricted() || check_secure())
6060 return;
6061
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006062# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
6063 init_pyxversion();
6064 if (p_pyx == 2)
6065 f_pyeval(argvars, rettv);
6066 else
6067 f_py3eval(argvars, rettv);
6068# elif defined(FEAT_PYTHON)
6069 f_pyeval(argvars, rettv);
6070# elif defined(FEAT_PYTHON3)
6071 f_py3eval(argvars, rettv);
6072# endif
6073}
6074#endif
6075
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006076static UINT32_T srand_seed_for_testing = 0;
6077static int srand_seed_for_testing_is_used = FALSE;
6078
6079 static void
6080f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
6081{
6082 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006083 srand_seed_for_testing_is_used = FALSE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006084 else
6085 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006086 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
6087 srand_seed_for_testing_is_used = TRUE;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006088 }
6089}
6090
6091 static void
6092init_srand(UINT32_T *x)
6093{
6094#ifndef MSWIN
6095 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6096#endif
6097
6098 if (srand_seed_for_testing_is_used)
6099 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02006100 *x = srand_seed_for_testing;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006101 return;
6102 }
6103#ifndef MSWIN
6104 if (dev_urandom_state != FAIL)
6105 {
6106 int fd = open("/dev/urandom", O_RDONLY);
6107 struct {
6108 union {
6109 UINT32_T number;
6110 char bytes[sizeof(UINT32_T)];
6111 } contents;
6112 } buf;
6113
6114 // Attempt reading /dev/urandom.
6115 if (fd == -1)
6116 dev_urandom_state = FAIL;
6117 else
6118 {
6119 buf.contents.number = 0;
6120 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6121 != sizeof(UINT32_T))
6122 dev_urandom_state = FAIL;
6123 else
6124 {
6125 dev_urandom_state = OK;
6126 *x = buf.contents.number;
6127 }
6128 close(fd);
6129 }
6130 }
6131 if (dev_urandom_state != OK)
6132 // Reading /dev/urandom doesn't work, fall back to time().
6133#endif
6134 *x = vim_time();
6135}
6136
6137#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6138#define SPLITMIX32(x, z) ( \
6139 z = (x += 0x9e3779b9), \
6140 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6141 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6142 z ^ (z >> 16) \
6143 )
6144#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6145 result = ROTL(y * 5, 7) * 9; \
6146 t = y << 9; \
6147 z ^= x; \
6148 w ^= y; \
6149 y ^= z, x ^= w; \
6150 z ^= t; \
6151 w = ROTL(w, 11);
6152
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006153/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006154 * "rand()" function
6155 */
6156 static void
6157f_rand(typval_T *argvars, typval_T *rettv)
6158{
6159 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006160 static UINT32_T gx, gy, gz, gw;
6161 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006162 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006163 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006164
6165 if (argvars[0].v_type == VAR_UNKNOWN)
6166 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006167 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006168 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006169 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006170 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006171 init_srand(&x);
6172
6173 gx = SPLITMIX32(x, z);
6174 gy = SPLITMIX32(x, z);
6175 gz = SPLITMIX32(x, z);
6176 gw = SPLITMIX32(x, z);
6177 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006178 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006179
6180 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006181 }
6182 else if (argvars[0].v_type == VAR_LIST)
6183 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006184 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006185 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006186 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006187
6188 lx = list_find(l, 0L);
6189 ly = list_find(l, 1L);
6190 lz = list_find(l, 2L);
6191 lw = list_find(l, 3L);
6192 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6193 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6194 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6195 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6196 x = (UINT32_T)lx->li_tv.vval.v_number;
6197 y = (UINT32_T)ly->li_tv.vval.v_number;
6198 z = (UINT32_T)lz->li_tv.vval.v_number;
6199 w = (UINT32_T)lw->li_tv.vval.v_number;
6200
6201 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6202
6203 lx->li_tv.vval.v_number = (varnumber_T)x;
6204 ly->li_tv.vval.v_number = (varnumber_T)y;
6205 lz->li_tv.vval.v_number = (varnumber_T)z;
6206 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006207 }
6208 else
6209 goto theend;
6210
6211 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006212 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006213 return;
6214
6215theend:
6216 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006217 rettv->v_type = VAR_NUMBER;
6218 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006219}
6220
6221/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006222 * "srand()" function
6223 */
6224 static void
6225f_srand(typval_T *argvars, typval_T *rettv)
6226{
6227 UINT32_T x = 0, z;
6228
6229 if (rettv_list_alloc(rettv) == FAIL)
6230 return;
6231 if (argvars[0].v_type == VAR_UNKNOWN)
6232 {
6233 init_srand(&x);
6234 }
6235 else
6236 {
6237 int error = FALSE;
6238
6239 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6240 if (error)
6241 return;
6242 }
6243
6244 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6245 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6246 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6247 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6248}
6249
6250#undef ROTL
6251#undef SPLITMIX32
6252#undef SHUFFLE_XOSHIRO128STARSTAR
6253
6254/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006255 * "range()" function
6256 */
6257 static void
6258f_range(typval_T *argvars, typval_T *rettv)
6259{
6260 varnumber_T start;
6261 varnumber_T end;
6262 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006263 int error = FALSE;
6264
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006265 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006266 if (argvars[1].v_type == VAR_UNKNOWN)
6267 {
6268 end = start - 1;
6269 start = 0;
6270 }
6271 else
6272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006273 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006274 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006275 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006276 }
6277
6278 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006279 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006280 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006281 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006282 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006283 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006284 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006286 list_T *list = rettv->vval.v_list;
6287
6288 // Create a non-materialized list. This is much more efficient and
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006289 // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006290 // be called.
6291 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006292 list->lv_u.nonmat.lv_start = start;
6293 list->lv_u.nonmat.lv_end = end;
6294 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006295 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006296 }
6297}
6298
6299/*
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006300 * Materialize "list".
6301 * Do not call directly, use CHECK_LIST_MATERIALIZE()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006302 */
6303 void
6304range_list_materialize(list_T *list)
6305{
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006306 varnumber_T start = list->lv_u.nonmat.lv_start;
6307 varnumber_T end = list->lv_u.nonmat.lv_end;
6308 int stride = list->lv_u.nonmat.lv_stride;
6309 varnumber_T i;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006310
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02006311 list->lv_first = NULL;
6312 list->lv_u.mat.lv_last = NULL;
6313 list->lv_len = 0;
6314 list->lv_u.mat.lv_idx_item = NULL;
6315 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6316 if (list_append_number(list, (varnumber_T)i) == FAIL)
6317 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318}
6319
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006320/*
6321 * "getreginfo()" function
6322 */
6323 static void
6324f_getreginfo(typval_T *argvars, typval_T *rettv)
6325{
6326 char_u *strregname;
6327 int regname;
6328 char_u buf[NUMBUFLEN + 2];
6329 long reglen = 0;
6330 dict_T *dict;
6331 list_T *list;
6332
6333 if (argvars[0].v_type != VAR_UNKNOWN)
6334 {
6335 strregname = tv_get_string_chk(&argvars[0]);
6336 if (strregname == NULL)
6337 return;
6338 }
6339 else
6340 strregname = get_vim_var_str(VV_REG);
6341
6342 regname = (strregname == NULL ? '"' : *strregname);
6343 if (regname == 0 || regname == '@')
6344 regname = '"';
6345
6346 if (rettv_dict_alloc(rettv) == FAIL)
6347 return;
6348 dict = rettv->vval.v_dict;
6349
6350 list = (list_T *)get_reg_contents(regname, GREG_EXPR_SRC | GREG_LIST);
6351 if (list == NULL)
6352 return;
Bram Moolenaar91639192020-06-29 19:55:58 +02006353 (void)dict_add_list(dict, "regcontents", list);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006354
6355 buf[0] = NUL;
6356 buf[1] = NUL;
6357 switch (get_reg_type(regname, &reglen))
6358 {
6359 case MLINE: buf[0] = 'V'; break;
6360 case MCHAR: buf[0] = 'v'; break;
6361 case MBLOCK:
6362 vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
6363 reglen + 1);
6364 break;
6365 }
Bram Moolenaar91639192020-06-29 19:55:58 +02006366 (void)dict_add_string(dict, (char *)"regtype", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006367
6368 buf[0] = get_register_name(get_unname_register());
6369 buf[1] = NUL;
6370 if (regname == '"')
Bram Moolenaar91639192020-06-29 19:55:58 +02006371 (void)dict_add_string(dict, (char *)"points_to", buf);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006372 else
6373 {
6374 dictitem_T *item = dictitem_alloc((char_u *)"isunnamed");
6375
6376 if (item != NULL)
6377 {
6378 item->di_tv.v_type = VAR_SPECIAL;
6379 item->di_tv.vval.v_number = regname == buf[0]
6380 ? VVAL_TRUE : VVAL_FALSE;
Bram Moolenaar91639192020-06-29 19:55:58 +02006381 (void)dict_add(dict, item);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02006382 }
6383 }
6384}
6385
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006386 static void
6387return_register(int regname, typval_T *rettv)
6388{
6389 char_u buf[2] = {0, 0};
6390
6391 buf[0] = (char_u)regname;
6392 rettv->v_type = VAR_STRING;
6393 rettv->vval.v_string = vim_strsave(buf);
6394}
6395
6396/*
6397 * "reg_executing()" function
6398 */
6399 static void
6400f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6401{
6402 return_register(reg_executing, rettv);
6403}
6404
6405/*
6406 * "reg_recording()" function
6407 */
6408 static void
6409f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6410{
6411 return_register(reg_recording, rettv);
6412}
6413
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006414/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 * "rename({from}, {to})" function
6416 */
6417 static void
6418f_rename(typval_T *argvars, typval_T *rettv)
6419{
6420 char_u buf[NUMBUFLEN];
6421
6422 if (check_restricted() || check_secure())
6423 rettv->vval.v_number = -1;
6424 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006425 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6426 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427}
6428
6429/*
6430 * "repeat()" function
6431 */
6432 static void
6433f_repeat(typval_T *argvars, typval_T *rettv)
6434{
6435 char_u *p;
6436 int n;
6437 int slen;
6438 int len;
6439 char_u *r;
6440 int i;
6441
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006442 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443 if (argvars[0].v_type == VAR_LIST)
6444 {
6445 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6446 while (n-- > 0)
6447 if (list_extend(rettv->vval.v_list,
6448 argvars[0].vval.v_list, NULL) == FAIL)
6449 break;
6450 }
6451 else
6452 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006453 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006454 rettv->v_type = VAR_STRING;
6455 rettv->vval.v_string = NULL;
6456
6457 slen = (int)STRLEN(p);
6458 len = slen * n;
6459 if (len <= 0)
6460 return;
6461
6462 r = alloc(len + 1);
6463 if (r != NULL)
6464 {
6465 for (i = 0; i < n; i++)
6466 mch_memmove(r + i * slen, p, (size_t)slen);
6467 r[len] = NUL;
6468 }
6469
6470 rettv->vval.v_string = r;
6471 }
6472}
6473
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006474#define SP_NOMOVE 0x01 // don't move cursor
6475#define SP_REPEAT 0x02 // repeat to find outer pair
6476#define SP_RETCOUNT 0x04 // return matchcount
6477#define SP_SETPCMARK 0x08 // set previous context mark
6478#define SP_START 0x10 // accept match at start position
6479#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6480#define SP_END 0x40 // leave cursor at end of match
6481#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006483/*
6484 * Get flags for a search function.
6485 * Possibly sets "p_ws".
6486 * Returns BACKWARD, FORWARD or zero (for an error).
6487 */
6488 static int
6489get_search_arg(typval_T *varp, int *flagsp)
6490{
6491 int dir = FORWARD;
6492 char_u *flags;
6493 char_u nbuf[NUMBUFLEN];
6494 int mask;
6495
6496 if (varp->v_type != VAR_UNKNOWN)
6497 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006498 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006500 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 while (*flags != NUL)
6502 {
6503 switch (*flags)
6504 {
6505 case 'b': dir = BACKWARD; break;
6506 case 'w': p_ws = TRUE; break;
6507 case 'W': p_ws = FALSE; break;
6508 default: mask = 0;
6509 if (flagsp != NULL)
6510 switch (*flags)
6511 {
6512 case 'c': mask = SP_START; break;
6513 case 'e': mask = SP_END; break;
6514 case 'm': mask = SP_RETCOUNT; break;
6515 case 'n': mask = SP_NOMOVE; break;
6516 case 'p': mask = SP_SUBPAT; break;
6517 case 'r': mask = SP_REPEAT; break;
6518 case 's': mask = SP_SETPCMARK; break;
6519 case 'z': mask = SP_COLUMN; break;
6520 }
6521 if (mask == 0)
6522 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006523 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006524 dir = 0;
6525 }
6526 else
6527 *flagsp |= mask;
6528 }
6529 if (dir == 0)
6530 break;
6531 ++flags;
6532 }
6533 }
6534 return dir;
6535}
6536
6537/*
6538 * Shared by search() and searchpos() functions.
6539 */
6540 static int
6541search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6542{
6543 int flags;
6544 char_u *pat;
6545 pos_T pos;
6546 pos_T save_cursor;
6547 int save_p_ws = p_ws;
6548 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006549 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006551#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006552 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006553 long time_limit = 0;
6554#endif
6555 int options = SEARCH_KEEP;
6556 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006557 searchit_arg_T sia;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006558 int use_skip = FALSE;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006559 pos_T firstpos;
6560
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006561 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006562 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006563 if (dir == 0)
6564 goto theend;
6565 flags = *flagsp;
6566 if (flags & SP_START)
6567 options |= SEARCH_START;
6568 if (flags & SP_END)
6569 options |= SEARCH_END;
6570 if (flags & SP_COLUMN)
6571 options |= SEARCH_COL;
6572
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006573 // Optional arguments: line number to stop searching, timeout and skip.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6575 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006576 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006577 if (lnum_stop < 0)
6578 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006579 if (argvars[3].v_type != VAR_UNKNOWN)
6580 {
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006581#ifdef FEAT_RELTIME
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006582 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583 if (time_limit < 0)
6584 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006585#endif
Bram Moolenaara9c01042020-06-07 14:50:50 +02006586 use_skip = eval_expr_valid_arg(&argvars[4]);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006587 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 }
6589
6590#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006591 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006592 profile_setlimit(time_limit, &tm);
6593#endif
6594
6595 /*
6596 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6597 * Check to make sure only those flags are set.
6598 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6599 * flags cannot be set. Check for that condition also.
6600 */
6601 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6602 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6603 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006604 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006605 goto theend;
6606 }
6607
6608 pos = save_cursor = curwin->w_cursor;
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006609 CLEAR_FIELD(firstpos);
Bram Moolenaara80faa82020-04-12 19:37:17 +02006610 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006611 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6612#ifdef FEAT_RELTIME
6613 sia.sa_tm = &tm;
6614#endif
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006615
6616 // Repeat until {skip} returns FALSE.
6617 for (;;)
6618 {
6619 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006620 options, RE_SEARCH, &sia);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006621 // finding the first match again means there is no match where {skip}
6622 // evaluates to zero.
6623 if (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos))
6624 subpatnum = FAIL;
6625
Bram Moolenaara9c01042020-06-07 14:50:50 +02006626 if (subpatnum == FAIL || !use_skip)
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006627 // didn't find it or no skip argument
6628 break;
6629 firstpos = pos;
6630
Bram Moolenaara9c01042020-06-07 14:50:50 +02006631 // If the skip expression matches, ignore this match.
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006632 {
6633 int do_skip;
6634 int err;
6635 pos_T save_pos = curwin->w_cursor;
6636
6637 curwin->w_cursor = pos;
Bram Moolenaara9c01042020-06-07 14:50:50 +02006638 err = FALSE;
6639 do_skip = eval_expr_to_bool(&argvars[4], &err);
Bram Moolenaaradc17a52020-06-06 18:37:51 +02006640 curwin->w_cursor = save_pos;
6641 if (err)
6642 {
6643 // Evaluating {skip} caused an error, break here.
6644 subpatnum = FAIL;
6645 break;
6646 }
6647 if (!do_skip)
6648 break;
6649 }
6650 }
6651
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652 if (subpatnum != FAIL)
6653 {
6654 if (flags & SP_SUBPAT)
6655 retval = subpatnum;
6656 else
6657 retval = pos.lnum;
6658 if (flags & SP_SETPCMARK)
6659 setpcmark();
6660 curwin->w_cursor = pos;
6661 if (match_pos != NULL)
6662 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006663 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006664 match_pos->lnum = pos.lnum;
6665 match_pos->col = pos.col + 1;
6666 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006667 // "/$" will put the cursor after the end of the line, may need to
6668 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006669 check_cursor();
6670 }
6671
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006672 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006673 if (flags & SP_NOMOVE)
6674 curwin->w_cursor = save_cursor;
6675 else
6676 curwin->w_set_curswant = TRUE;
6677theend:
6678 p_ws = save_p_ws;
6679
6680 return retval;
6681}
6682
6683#ifdef FEAT_FLOAT
6684
6685/*
6686 * round() is not in C90, use ceil() or floor() instead.
6687 */
6688 float_T
6689vim_round(float_T f)
6690{
6691 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6692}
6693
6694/*
6695 * "round({float})" function
6696 */
6697 static void
6698f_round(typval_T *argvars, typval_T *rettv)
6699{
6700 float_T f = 0.0;
6701
6702 rettv->v_type = VAR_FLOAT;
6703 if (get_float_arg(argvars, &f) == OK)
6704 rettv->vval.v_float = vim_round(f);
6705 else
6706 rettv->vval.v_float = 0.0;
6707}
6708#endif
6709
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006710#ifdef FEAT_RUBY
6711/*
6712 * "rubyeval()" function
6713 */
6714 static void
6715f_rubyeval(typval_T *argvars, typval_T *rettv)
6716{
6717 char_u *str;
6718 char_u buf[NUMBUFLEN];
6719
6720 str = tv_get_string_buf(&argvars[0], buf);
6721 do_rubyeval(str, rettv);
6722}
6723#endif
6724
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006725/*
6726 * "screenattr()" function
6727 */
6728 static void
6729f_screenattr(typval_T *argvars, typval_T *rettv)
6730{
6731 int row;
6732 int col;
6733 int c;
6734
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006735 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6736 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 if (row < 0 || row >= screen_Rows
6738 || col < 0 || col >= screen_Columns)
6739 c = -1;
6740 else
6741 c = ScreenAttrs[LineOffset[row] + col];
6742 rettv->vval.v_number = c;
6743}
6744
6745/*
6746 * "screenchar()" function
6747 */
6748 static void
6749f_screenchar(typval_T *argvars, typval_T *rettv)
6750{
6751 int row;
6752 int col;
6753 int off;
6754 int c;
6755
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006756 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6757 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006758 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759 c = -1;
6760 else
6761 {
6762 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006763 if (enc_utf8 && ScreenLinesUC[off] != 0)
6764 c = ScreenLinesUC[off];
6765 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006766 c = ScreenLines[off];
6767 }
6768 rettv->vval.v_number = c;
6769}
6770
6771/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006772 * "screenchars()" function
6773 */
6774 static void
6775f_screenchars(typval_T *argvars, typval_T *rettv)
6776{
6777 int row;
6778 int col;
6779 int off;
6780 int c;
6781 int i;
6782
6783 if (rettv_list_alloc(rettv) == FAIL)
6784 return;
6785 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6786 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6787 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6788 return;
6789
6790 off = LineOffset[row] + col;
6791 if (enc_utf8 && ScreenLinesUC[off] != 0)
6792 c = ScreenLinesUC[off];
6793 else
6794 c = ScreenLines[off];
6795 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6796
6797 if (enc_utf8)
6798
6799 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6800 list_append_number(rettv->vval.v_list,
6801 (varnumber_T)ScreenLinesC[i][off]);
6802}
6803
6804/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006805 * "screencol()" function
6806 *
6807 * First column is 1 to be consistent with virtcol().
6808 */
6809 static void
6810f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6811{
6812 rettv->vval.v_number = screen_screencol() + 1;
6813}
6814
6815/*
6816 * "screenrow()" function
6817 */
6818 static void
6819f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6820{
6821 rettv->vval.v_number = screen_screenrow() + 1;
6822}
6823
6824/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006825 * "screenstring()" function
6826 */
6827 static void
6828f_screenstring(typval_T *argvars, typval_T *rettv)
6829{
6830 int row;
6831 int col;
6832 int off;
6833 int c;
6834 int i;
6835 char_u buf[MB_MAXBYTES + 1];
6836 int buflen = 0;
6837
6838 rettv->vval.v_string = NULL;
6839 rettv->v_type = VAR_STRING;
6840
6841 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6842 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6843 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6844 return;
6845
6846 off = LineOffset[row] + col;
6847 if (enc_utf8 && ScreenLinesUC[off] != 0)
6848 c = ScreenLinesUC[off];
6849 else
6850 c = ScreenLines[off];
6851 buflen += mb_char2bytes(c, buf);
6852
6853 if (enc_utf8)
6854 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6855 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6856
6857 buf[buflen] = NUL;
6858 rettv->vval.v_string = vim_strsave(buf);
6859}
6860
6861/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 * "search()" function
6863 */
6864 static void
6865f_search(typval_T *argvars, typval_T *rettv)
6866{
6867 int flags = 0;
6868
6869 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6870}
6871
6872/*
6873 * "searchdecl()" function
6874 */
6875 static void
6876f_searchdecl(typval_T *argvars, typval_T *rettv)
6877{
6878 int locally = 1;
6879 int thisblock = 0;
6880 int error = FALSE;
6881 char_u *name;
6882
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006883 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006884
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006885 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006886 if (argvars[1].v_type != VAR_UNKNOWN)
6887 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006888 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006889 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006890 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006891 }
6892 if (!error && name != NULL)
6893 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6894 locally, thisblock, SEARCH_KEEP) == FAIL;
6895}
6896
6897/*
6898 * Used by searchpair() and searchpairpos()
6899 */
6900 static int
6901searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6902{
6903 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006904 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006905 int save_p_ws = p_ws;
6906 int dir;
6907 int flags = 0;
6908 char_u nbuf1[NUMBUFLEN];
6909 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006910 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006911 long lnum_stop = 0;
6912 long time_limit = 0;
6913
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006914 // Get the three pattern arguments: start, middle, end. Will result in an
6915 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006916 spat = tv_get_string_chk(&argvars[0]);
6917 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6918 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006919 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006920 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006921
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006922 // Handle the optional fourth argument: flags
6923 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006924 if (dir == 0)
6925 goto theend;
6926
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006927 // Don't accept SP_END or SP_SUBPAT.
6928 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006929 if ((flags & (SP_END | SP_SUBPAT)) != 0
6930 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6931 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006932 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006933 goto theend;
6934 }
6935
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006936 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006937 if (flags & SP_REPEAT)
6938 p_ws = FALSE;
6939
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006940 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006941 if (argvars[3].v_type == VAR_UNKNOWN
6942 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006943 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006944 else
6945 {
Bram Moolenaara9c01042020-06-07 14:50:50 +02006946 // Type is checked later.
Bram Moolenaar48570482017-10-30 21:48:41 +01006947 skip = &argvars[4];
Bram Moolenaara9c01042020-06-07 14:50:50 +02006948
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006949 if (argvars[5].v_type != VAR_UNKNOWN)
6950 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006951 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006952 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006953 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006954 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006955 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006956 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006957#ifdef FEAT_RELTIME
6958 if (argvars[6].v_type != VAR_UNKNOWN)
6959 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006960 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006962 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006963 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006964 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006965 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 }
6967#endif
6968 }
6969 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970
6971 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6972 match_pos, lnum_stop, time_limit);
6973
6974theend:
6975 p_ws = save_p_ws;
6976
6977 return retval;
6978}
6979
6980/*
6981 * "searchpair()" function
6982 */
6983 static void
6984f_searchpair(typval_T *argvars, typval_T *rettv)
6985{
6986 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6987}
6988
6989/*
6990 * "searchpairpos()" function
6991 */
6992 static void
6993f_searchpairpos(typval_T *argvars, typval_T *rettv)
6994{
6995 pos_T match_pos;
6996 int lnum = 0;
6997 int col = 0;
6998
6999 if (rettv_list_alloc(rettv) == FAIL)
7000 return;
7001
7002 if (searchpair_cmn(argvars, &match_pos) > 0)
7003 {
7004 lnum = match_pos.lnum;
7005 col = match_pos.col;
7006 }
7007
7008 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7009 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7010}
7011
7012/*
7013 * Search for a start/middle/end thing.
7014 * Used by searchpair(), see its documentation for the details.
7015 * Returns 0 or -1 for no match,
7016 */
7017 long
7018do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007019 char_u *spat, // start pattern
7020 char_u *mpat, // middle pattern
7021 char_u *epat, // end pattern
7022 int dir, // BACKWARD or FORWARD
7023 typval_T *skip, // skip expression
7024 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007026 linenr_T lnum_stop, // stop at this line if not zero
7027 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007028{
7029 char_u *save_cpo;
7030 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7031 long retval = 0;
7032 pos_T pos;
7033 pos_T firstpos;
7034 pos_T foundpos;
7035 pos_T save_cursor;
7036 pos_T save_pos;
7037 int n;
7038 int r;
7039 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007040 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007041 int err;
7042 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007043#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007044 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007045#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007046
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007047 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048 save_cpo = p_cpo;
7049 p_cpo = empty_option;
7050
7051#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007052 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007053 profile_setlimit(time_limit, &tm);
7054#endif
7055
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007056 // Make two search patterns: start/end (pat2, for in nested pairs) and
7057 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02007058 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7059 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007060 if (pat2 == NULL || pat3 == NULL)
7061 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007062 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063 if (*mpat == NUL)
7064 STRCPY(pat3, pat2);
7065 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007066 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007067 spat, epat, mpat);
7068 if (flags & SP_START)
7069 options |= SEARCH_START;
7070
Bram Moolenaar48570482017-10-30 21:48:41 +01007071 if (skip != NULL)
Bram Moolenaara9c01042020-06-07 14:50:50 +02007072 use_skip = eval_expr_valid_arg(skip);
Bram Moolenaar48570482017-10-30 21:48:41 +01007073
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074 save_cursor = curwin->w_cursor;
7075 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007076 CLEAR_POS(&firstpos);
7077 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078 pat = pat3;
7079 for (;;)
7080 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007081 searchit_arg_T sia;
7082
Bram Moolenaara80faa82020-04-12 19:37:17 +02007083 CLEAR_FIELD(sia);
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007084 sia.sa_stop_lnum = lnum_stop;
7085#ifdef FEAT_RELTIME
7086 sia.sa_tm = &tm;
7087#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007088 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007089 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007090 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007091 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 break;
7093
7094 if (firstpos.lnum == 0)
7095 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007096 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007097 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007098 // Found the same position again. Can happen with a pattern that
7099 // has "\zs" at the end and searching backwards. Advance one
7100 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007101 if (dir == BACKWARD)
7102 decl(&pos);
7103 else
7104 incl(&pos);
7105 }
7106 foundpos = pos;
7107
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007108 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007109 options &= ~SEARCH_START;
7110
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007111 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007112 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007113 {
7114 save_pos = curwin->w_cursor;
7115 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007116 err = FALSE;
7117 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 curwin->w_cursor = save_pos;
7119 if (err)
7120 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007121 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007122 curwin->w_cursor = save_cursor;
7123 retval = -1;
7124 break;
7125 }
7126 if (r)
7127 continue;
7128 }
7129
7130 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7131 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007132 // Found end when searching backwards or start when searching
7133 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007134 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007135 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 }
7137 else
7138 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007139 // Found end when searching forward or start when searching
7140 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007141 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007142 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007143 }
7144
7145 if (nest == 0)
7146 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007147 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 if (flags & SP_RETCOUNT)
7149 ++retval;
7150 else
7151 retval = pos.lnum;
7152 if (flags & SP_SETPCMARK)
7153 setpcmark();
7154 curwin->w_cursor = pos;
7155 if (!(flags & SP_REPEAT))
7156 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007157 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007158 }
7159 }
7160
7161 if (match_pos != NULL)
7162 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007163 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 match_pos->lnum = curwin->w_cursor.lnum;
7165 match_pos->col = curwin->w_cursor.col + 1;
7166 }
7167
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007168 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007169 if ((flags & SP_NOMOVE) || retval == 0)
7170 curwin->w_cursor = save_cursor;
7171
7172theend:
7173 vim_free(pat2);
7174 vim_free(pat3);
7175 if (p_cpo == empty_option)
7176 p_cpo = save_cpo;
7177 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007178 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007179 free_string_option(save_cpo);
7180
7181 return retval;
7182}
7183
7184/*
7185 * "searchpos()" function
7186 */
7187 static void
7188f_searchpos(typval_T *argvars, typval_T *rettv)
7189{
7190 pos_T match_pos;
7191 int lnum = 0;
7192 int col = 0;
7193 int n;
7194 int flags = 0;
7195
7196 if (rettv_list_alloc(rettv) == FAIL)
7197 return;
7198
7199 n = search_cmn(argvars, &match_pos, &flags);
7200 if (n > 0)
7201 {
7202 lnum = match_pos.lnum;
7203 col = match_pos.col;
7204 }
7205
7206 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7207 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7208 if (flags & SP_SUBPAT)
7209 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7210}
7211
7212 static void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007213f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7214{
7215 dict_T *d;
7216 dictitem_T *di;
7217 char_u *csearch;
7218
7219 if (argvars[0].v_type != VAR_DICT)
7220 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007221 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007222 return;
7223 }
7224
7225 if ((d = argvars[0].vval.v_dict) != NULL)
7226 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007227 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 if (csearch != NULL)
7229 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230 if (enc_utf8)
7231 {
7232 int pcc[MAX_MCO];
7233 int c = utfc_ptr2char(csearch, pcc);
7234
7235 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7236 }
7237 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007239 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007240 }
7241
7242 di = dict_find(d, (char_u *)"forward", -1);
7243 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007244 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007245 ? FORWARD : BACKWARD);
7246
7247 di = dict_find(d, (char_u *)"until", -1);
7248 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007249 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250 }
7251}
7252
7253/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007254 * "setenv()" function
7255 */
7256 static void
7257f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7258{
7259 char_u namebuf[NUMBUFLEN];
7260 char_u valbuf[NUMBUFLEN];
7261 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7262
7263 if (argvars[1].v_type == VAR_SPECIAL
7264 && argvars[1].vval.v_number == VVAL_NULL)
7265 vim_unsetenv(name);
7266 else
7267 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7268}
7269
7270/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007271 * "setfperm({fname}, {mode})" function
7272 */
7273 static void
7274f_setfperm(typval_T *argvars, typval_T *rettv)
7275{
7276 char_u *fname;
7277 char_u modebuf[NUMBUFLEN];
7278 char_u *mode_str;
7279 int i;
7280 int mask;
7281 int mode = 0;
7282
7283 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007284 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 if (fname == NULL)
7286 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007287 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 if (mode_str == NULL)
7289 return;
7290 if (STRLEN(mode_str) != 9)
7291 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007292 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007293 return;
7294 }
7295
7296 mask = 1;
7297 for (i = 8; i >= 0; --i)
7298 {
7299 if (mode_str[i] != '-')
7300 mode |= mask;
7301 mask = mask << 1;
7302 }
7303 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7304}
7305
7306/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007307 * "setpos()" function
7308 */
7309 static void
7310f_setpos(typval_T *argvars, typval_T *rettv)
7311{
7312 pos_T pos;
7313 int fnum;
7314 char_u *name;
7315 colnr_T curswant = -1;
7316
7317 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007318 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319 if (name != NULL)
7320 {
7321 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7322 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007323 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324 pos.col = 0;
7325 if (name[0] == '.' && name[1] == NUL)
7326 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007327 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007328 curwin->w_cursor = pos;
7329 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007330 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007331 curwin->w_curswant = curswant - 1;
7332 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007333 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007334 check_cursor();
7335 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336 }
7337 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7338 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007339 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007340 if (setmark_pos(name[1], &pos, fnum) == OK)
7341 rettv->vval.v_number = 0;
7342 }
7343 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007344 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 }
7346 }
7347}
7348
7349/*
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007350 * Translate a register type string to the yank type and block length
7351 */
7352 static int
7353get_yank_type(char_u **pp, char_u *yank_type, long *block_len)
7354{
7355 char_u *stropt = *pp;
7356 switch (*stropt)
7357 {
7358 case 'v': case 'c': // character-wise selection
7359 *yank_type = MCHAR;
7360 break;
7361 case 'V': case 'l': // line-wise selection
7362 *yank_type = MLINE;
7363 break;
7364 case 'b': case Ctrl_V: // block-wise selection
7365 *yank_type = MBLOCK;
7366 if (VIM_ISDIGIT(stropt[1]))
7367 {
7368 ++stropt;
7369 *block_len = getdigits(&stropt) - 1;
7370 --stropt;
7371 }
7372 break;
7373 default:
7374 return FAIL;
7375 }
7376 *pp = stropt;
7377 return OK;
7378}
7379
7380/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007381 * "setreg()" function
7382 */
7383 static void
7384f_setreg(typval_T *argvars, typval_T *rettv)
7385{
7386 int regname;
7387 char_u *strregname;
7388 char_u *stropt;
7389 char_u *strval;
7390 int append;
7391 char_u yank_type;
7392 long block_len;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007393 typval_T *regcontents;
7394 int pointreg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007395
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007396 pointreg = 0;
7397 regcontents = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398 block_len = -1;
7399 yank_type = MAUTO;
7400 append = FALSE;
7401
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007402 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007403 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007404
7405 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007406 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 regname = *strregname;
7408 if (regname == 0 || regname == '@')
7409 regname = '"';
7410
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007411 if (argvars[1].v_type == VAR_DICT)
7412 {
7413 dict_T *d = argvars[1].vval.v_dict;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007414 dictitem_T *di;
7415
7416 if (d == NULL || d->dv_hashtab.ht_used == 0)
7417 {
7418 // Empty dict, clear the register (like setreg(0, []))
7419 char_u *lstval[2] = {NULL, NULL};
7420 write_reg_contents_lst(regname, lstval, 0, FALSE, MAUTO, -1);
7421 return;
7422 }
7423
7424 di = dict_find(d, (char_u *)"regcontents", -1);
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007425 if (di != NULL)
7426 regcontents = &di->di_tv;
7427
7428 stropt = dict_get_string(d, (char_u *)"regtype", FALSE);
7429 if (stropt != NULL)
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007430 {
7431 int ret = get_yank_type(&stropt, &yank_type, &block_len);
7432
7433 if (ret == FAIL || *++stropt != NUL)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007434 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007435 semsg(_(e_invargval), "value");
7436 return;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007437 }
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007438 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007439
7440 if (regname == '"')
7441 {
7442 stropt = dict_get_string(d, (char_u *)"points_to", FALSE);
7443 if (stropt != NULL)
7444 {
7445 pointreg = *stropt;
7446 regname = pointreg;
7447 }
7448 }
Bram Moolenaar6a950582020-08-28 16:39:33 +02007449 else if (dict_get_bool(d, (char_u *)"isunnamed", -1) > 0)
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007450 pointreg = regname;
7451 }
7452 else
7453 regcontents = &argvars[1];
7454
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455 if (argvars[2].v_type != VAR_UNKNOWN)
7456 {
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007457 if (yank_type != MAUTO)
7458 {
7459 semsg(_(e_toomanyarg), "setreg");
7460 return;
7461 }
7462
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007463 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007465 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007466 for (; *stropt != NUL; ++stropt)
7467 switch (*stropt)
7468 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007469 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470 append = TRUE;
7471 break;
Bram Moolenaar7633fe52020-06-22 19:10:56 +02007472 default:
7473 get_yank_type(&stropt, &yank_type, &block_len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007474 }
7475 }
7476
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007477 if (regcontents && regcontents->v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478 {
7479 char_u **lstval;
7480 char_u **allocval;
7481 char_u buf[NUMBUFLEN];
7482 char_u **curval;
7483 char_u **curallocval;
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007484 list_T *ll = regcontents->vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007485 listitem_T *li;
7486 int len;
7487
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007488 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007489 len = ll == NULL ? 0 : ll->lv_len;
7490
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007491 // First half: use for pointers to result lines; second half: use for
7492 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007493 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007494 if (lstval == NULL)
7495 return;
7496 curval = lstval;
7497 allocval = lstval + len + 2;
7498 curallocval = allocval;
7499
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007500 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501 {
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02007502 CHECK_LIST_MATERIALIZE(ll);
Bram Moolenaar00d253e2020-04-06 22:13:01 +02007503 FOR_ALL_LIST_ITEMS(ll, li)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007505 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506 if (strval == NULL)
7507 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007508 if (strval == buf)
7509 {
7510 // Need to make a copy, next tv_get_string_buf_chk() will
7511 // overwrite the string.
7512 strval = vim_strsave(buf);
7513 if (strval == NULL)
7514 goto free_lstval;
7515 *curallocval++ = strval;
7516 }
7517 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519 }
7520 *curval++ = NULL;
7521
7522 write_reg_contents_lst(regname, lstval, -1,
7523 append, yank_type, block_len);
7524free_lstval:
7525 while (curallocval > allocval)
7526 vim_free(*--curallocval);
7527 vim_free(lstval);
7528 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007529 else if (regcontents)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007530 {
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007531 strval = tv_get_string_chk(regcontents);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532 if (strval == NULL)
7533 return;
7534 write_reg_contents_ex(regname, strval, -1,
7535 append, yank_type, block_len);
7536 }
Bram Moolenaarbb861e22020-06-07 18:16:36 +02007537 if (pointreg != 0)
7538 get_yank_register(pointreg, TRUE);
7539
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540 rettv->vval.v_number = 0;
7541}
7542
7543/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007544 * "settagstack()" function
7545 */
7546 static void
7547f_settagstack(typval_T *argvars, typval_T *rettv)
7548{
7549 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7550 win_T *wp;
7551 dict_T *d;
7552 int action = 'r';
7553
7554 rettv->vval.v_number = -1;
7555
7556 // first argument: window number or id
7557 wp = find_win_by_nr_or_id(&argvars[0]);
7558 if (wp == NULL)
7559 return;
7560
7561 // second argument: dict with items to set in the tag stack
7562 if (argvars[1].v_type != VAR_DICT)
7563 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007564 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007565 return;
7566 }
7567 d = argvars[1].vval.v_dict;
7568 if (d == NULL)
7569 return;
7570
7571 // third argument: action - 'a' for append and 'r' for replace.
7572 // default is to replace the stack.
7573 if (argvars[2].v_type == VAR_UNKNOWN)
7574 action = 'r';
7575 else if (argvars[2].v_type == VAR_STRING)
7576 {
7577 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007578 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007579 if (actstr == NULL)
7580 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007581 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7582 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007583 action = *actstr;
7584 else
7585 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007586 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007587 return;
7588 }
7589 }
7590 else
7591 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007592 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007593 return;
7594 }
7595
7596 if (set_tagstack(wp, d, action) == OK)
7597 rettv->vval.v_number = 0;
7598}
7599
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600#ifdef FEAT_CRYPT
7601/*
7602 * "sha256({string})" function
7603 */
7604 static void
7605f_sha256(typval_T *argvars, typval_T *rettv)
7606{
7607 char_u *p;
7608
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007609 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 rettv->vval.v_string = vim_strsave(
7611 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7612 rettv->v_type = VAR_STRING;
7613}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007614#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007615
7616/*
7617 * "shellescape({string})" function
7618 */
7619 static void
7620f_shellescape(typval_T *argvars, typval_T *rettv)
7621{
Bram Moolenaar20615522017-06-05 18:46:26 +02007622 int do_special = non_zero_arg(&argvars[1]);
7623
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007624 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007625 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626 rettv->v_type = VAR_STRING;
7627}
7628
7629/*
7630 * shiftwidth() function
7631 */
7632 static void
7633f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7634{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007635 rettv->vval.v_number = 0;
7636
7637 if (argvars[0].v_type != VAR_UNKNOWN)
7638 {
7639 long col;
7640
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007641 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007642 if (col < 0)
7643 return; // type error; errmsg already given
7644#ifdef FEAT_VARTABS
7645 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7646 return;
7647#endif
7648 }
7649
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650 rettv->vval.v_number = get_sw_value(curbuf);
7651}
7652
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653#ifdef FEAT_FLOAT
7654/*
7655 * "sin()" function
7656 */
7657 static void
7658f_sin(typval_T *argvars, typval_T *rettv)
7659{
7660 float_T f = 0.0;
7661
7662 rettv->v_type = VAR_FLOAT;
7663 if (get_float_arg(argvars, &f) == OK)
7664 rettv->vval.v_float = sin(f);
7665 else
7666 rettv->vval.v_float = 0.0;
7667}
7668
7669/*
7670 * "sinh()" function
7671 */
7672 static void
7673f_sinh(typval_T *argvars, typval_T *rettv)
7674{
7675 float_T f = 0.0;
7676
7677 rettv->v_type = VAR_FLOAT;
7678 if (get_float_arg(argvars, &f) == OK)
7679 rettv->vval.v_float = sinh(f);
7680 else
7681 rettv->vval.v_float = 0.0;
7682}
7683#endif
7684
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007685/*
7686 * "soundfold({word})" function
7687 */
7688 static void
7689f_soundfold(typval_T *argvars, typval_T *rettv)
7690{
7691 char_u *s;
7692
7693 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007694 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007695#ifdef FEAT_SPELL
7696 rettv->vval.v_string = eval_soundfold(s);
7697#else
7698 rettv->vval.v_string = vim_strsave(s);
7699#endif
7700}
7701
7702/*
7703 * "spellbadword()" function
7704 */
7705 static void
7706f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7707{
7708 char_u *word = (char_u *)"";
7709 hlf_T attr = HLF_COUNT;
7710 int len = 0;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007711#ifdef FEAT_SPELL
7712 int wo_spell_save = curwin->w_p_spell;
7713
7714 if (!curwin->w_p_spell)
7715 {
7716 did_set_spelllang(curwin);
7717 curwin->w_p_spell = TRUE;
7718 }
7719
7720 if (*curwin->w_s->b_p_spl == NUL)
7721 {
7722 emsg(_(e_no_spell));
7723 curwin->w_p_spell = wo_spell_save;
7724 return;
7725 }
7726#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727
7728 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007729 {
7730#ifdef FEAT_SPELL
7731 curwin->w_p_spell = wo_spell_save;
7732#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007733 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007734 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007735
7736#ifdef FEAT_SPELL
7737 if (argvars[0].v_type == VAR_UNKNOWN)
7738 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007739 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007740 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7741 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007742 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007743 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007744 curwin->w_set_curswant = TRUE;
7745 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007747 else if (*curbuf->b_s.b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007749 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 int capcol = -1;
7751
7752 if (str != NULL)
7753 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007754 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007755 while (*str != NUL)
7756 {
7757 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7758 if (attr != HLF_COUNT)
7759 {
7760 word = str;
7761 break;
7762 }
7763 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007764 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007765 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007766 }
7767 }
7768 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007769 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770#endif
7771
7772 list_append_string(rettv->vval.v_list, word, len);
7773 list_append_string(rettv->vval.v_list, (char_u *)(
7774 attr == HLF_SPB ? "bad" :
7775 attr == HLF_SPR ? "rare" :
7776 attr == HLF_SPL ? "local" :
7777 attr == HLF_SPC ? "caps" :
7778 ""), -1);
7779}
7780
7781/*
7782 * "spellsuggest()" function
7783 */
7784 static void
7785f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7786{
7787#ifdef FEAT_SPELL
7788 char_u *str;
7789 int typeerr = FALSE;
7790 int maxcount;
7791 garray_T ga;
7792 int i;
7793 listitem_T *li;
7794 int need_capital = FALSE;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007795 int wo_spell_save = curwin->w_p_spell;
7796
7797 if (!curwin->w_p_spell)
7798 {
7799 did_set_spelllang(curwin);
7800 curwin->w_p_spell = TRUE;
7801 }
7802
7803 if (*curwin->w_s->b_p_spl == NUL)
7804 {
7805 emsg(_(e_no_spell));
7806 curwin->w_p_spell = wo_spell_save;
7807 return;
7808 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007809#endif
7810
7811 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007812 {
7813#ifdef FEAT_SPELL
7814 curwin->w_p_spell = wo_spell_save;
7815#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007816 return;
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007817 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007818
7819#ifdef FEAT_SPELL
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007820 if (*curwin->w_s->b_p_spl != NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007821 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007822 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007823 if (argvars[1].v_type != VAR_UNKNOWN)
7824 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007825 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 if (maxcount <= 0)
7827 return;
7828 if (argvars[2].v_type != VAR_UNKNOWN)
7829 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007830 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007831 if (typeerr)
7832 return;
7833 }
7834 }
7835 else
7836 maxcount = 25;
7837
7838 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7839
7840 for (i = 0; i < ga.ga_len; ++i)
7841 {
7842 str = ((char_u **)ga.ga_data)[i];
7843
7844 li = listitem_alloc();
7845 if (li == NULL)
7846 vim_free(str);
7847 else
7848 {
7849 li->li_tv.v_type = VAR_STRING;
7850 li->li_tv.v_lock = 0;
7851 li->li_tv.vval.v_string = str;
7852 list_append(rettv->vval.v_list, li);
7853 }
7854 }
7855 ga_clear(&ga);
7856 }
Bram Moolenaar152e79e2020-06-10 15:32:08 +02007857 curwin->w_p_spell = wo_spell_save;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858#endif
7859}
7860
7861 static void
7862f_split(typval_T *argvars, typval_T *rettv)
7863{
7864 char_u *str;
7865 char_u *end;
7866 char_u *pat = NULL;
7867 regmatch_T regmatch;
7868 char_u patbuf[NUMBUFLEN];
7869 char_u *save_cpo;
7870 int match;
7871 colnr_T col = 0;
7872 int keepempty = FALSE;
7873 int typeerr = FALSE;
7874
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007875 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007876 save_cpo = p_cpo;
7877 p_cpo = (char_u *)"";
7878
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007879 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 if (argvars[1].v_type != VAR_UNKNOWN)
7881 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007882 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007883 if (pat == NULL)
7884 typeerr = TRUE;
7885 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007886 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 }
7888 if (pat == NULL || *pat == NUL)
7889 pat = (char_u *)"[\\x01- ]\\+";
7890
7891 if (rettv_list_alloc(rettv) == FAIL)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007892 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 if (typeerr)
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007894 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007895
7896 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7897 if (regmatch.regprog != NULL)
7898 {
7899 regmatch.rm_ic = FALSE;
7900 while (*str != NUL || keepempty)
7901 {
7902 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007903 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 else
7905 match = vim_regexec_nl(&regmatch, str, col);
7906 if (match)
7907 end = regmatch.startp[0];
7908 else
7909 end = str + STRLEN(str);
7910 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7911 && *str != NUL && match && end < regmatch.endp[0]))
7912 {
7913 if (list_append_string(rettv->vval.v_list, str,
7914 (int)(end - str)) == FAIL)
7915 break;
7916 }
7917 if (!match)
7918 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007919 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007920 if (regmatch.endp[0] > str)
7921 col = 0;
7922 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007923 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007925 str = regmatch.endp[0];
7926 }
7927
7928 vim_regfree(regmatch.regprog);
7929 }
7930
Bram Moolenaar7d5e7442020-07-21 22:25:51 +02007931theend:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007932 p_cpo = save_cpo;
7933}
7934
7935#ifdef FEAT_FLOAT
7936/*
7937 * "sqrt()" function
7938 */
7939 static void
7940f_sqrt(typval_T *argvars, typval_T *rettv)
7941{
7942 float_T f = 0.0;
7943
7944 rettv->v_type = VAR_FLOAT;
7945 if (get_float_arg(argvars, &f) == OK)
7946 rettv->vval.v_float = sqrt(f);
7947 else
7948 rettv->vval.v_float = 0.0;
7949}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007950#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007952#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007953/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954 * "str2float()" function
7955 */
7956 static void
7957f_str2float(typval_T *argvars, typval_T *rettv)
7958{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007959 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007960 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007961
Bram Moolenaar08243d22017-01-10 16:12:29 +01007962 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963 p = skipwhite(p + 1);
7964 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007965 if (isneg)
7966 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007967 rettv->v_type = VAR_FLOAT;
7968}
7969#endif
7970
7971/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007972 * "str2list()" function
7973 */
7974 static void
7975f_str2list(typval_T *argvars, typval_T *rettv)
7976{
7977 char_u *p;
7978 int utf8 = FALSE;
7979
7980 if (rettv_list_alloc(rettv) == FAIL)
7981 return;
7982
7983 if (argvars[1].v_type != VAR_UNKNOWN)
7984 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7985
7986 p = tv_get_string(&argvars[0]);
7987
7988 if (has_mbyte || utf8)
7989 {
7990 int (*ptr2len)(char_u *);
7991 int (*ptr2char)(char_u *);
7992
7993 if (utf8 || enc_utf8)
7994 {
7995 ptr2len = utf_ptr2len;
7996 ptr2char = utf_ptr2char;
7997 }
7998 else
7999 {
8000 ptr2len = mb_ptr2len;
8001 ptr2char = mb_ptr2char;
8002 }
8003
8004 for ( ; *p != NUL; p += (*ptr2len)(p))
8005 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8006 }
8007 else
8008 for ( ; *p != NUL; ++p)
8009 list_append_number(rettv->vval.v_list, *p);
8010}
8011
8012/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008013 * "str2nr()" function
8014 */
8015 static void
8016f_str2nr(typval_T *argvars, typval_T *rettv)
8017{
8018 int base = 10;
8019 char_u *p;
8020 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008021 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008022 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023
8024 if (argvars[1].v_type != VAR_UNKNOWN)
8025 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008026 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008027 if (base != 2 && base != 8 && base != 10 && base != 16)
8028 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008029 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030 return;
8031 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008032 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
8033 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008034 }
8035
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008036 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008037 isneg = (*p == '-');
8038 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039 p = skipwhite(p + 1);
8040 switch (base)
8041 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008042 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
Bram Moolenaarc17e66c2020-06-02 21:38:22 +02008043 case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008044 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008045 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008046 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8047 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008048 if (isneg)
8049 rettv->vval.v_number = -n;
8050 else
8051 rettv->vval.v_number = n;
8052
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053}
8054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008055/*
8056 * "strgetchar()" function
8057 */
8058 static void
8059f_strgetchar(typval_T *argvars, typval_T *rettv)
8060{
8061 char_u *str;
8062 int len;
8063 int error = FALSE;
8064 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008065 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066
8067 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008068 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069 if (str == NULL)
8070 return;
8071 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008072 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008073 if (error)
8074 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008075
Bram Moolenaar13505972019-01-24 15:04:48 +01008076 while (charidx >= 0 && byteidx < len)
8077 {
8078 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008080 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8081 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008083 --charidx;
8084 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008085 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086}
8087
8088/*
8089 * "stridx()" function
8090 */
8091 static void
8092f_stridx(typval_T *argvars, typval_T *rettv)
8093{
8094 char_u buf[NUMBUFLEN];
8095 char_u *needle;
8096 char_u *haystack;
8097 char_u *save_haystack;
8098 char_u *pos;
8099 int start_idx;
8100
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008101 needle = tv_get_string_chk(&argvars[1]);
8102 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008103 rettv->vval.v_number = -1;
8104 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008105 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106
8107 if (argvars[2].v_type != VAR_UNKNOWN)
8108 {
8109 int error = FALSE;
8110
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008111 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008112 if (error || start_idx >= (int)STRLEN(haystack))
8113 return;
8114 if (start_idx >= 0)
8115 haystack += start_idx;
8116 }
8117
8118 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8119 if (pos != NULL)
8120 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8121}
8122
8123/*
8124 * "string()" function
8125 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008126 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008127f_string(typval_T *argvars, typval_T *rettv)
8128{
8129 char_u *tofree;
8130 char_u numbuf[NUMBUFLEN];
8131
8132 rettv->v_type = VAR_STRING;
8133 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8134 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008135 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008136 if (rettv->vval.v_string != NULL && tofree == NULL)
8137 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8138}
8139
8140/*
8141 * "strlen()" function
8142 */
8143 static void
8144f_strlen(typval_T *argvars, typval_T *rettv)
8145{
8146 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008147 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148}
8149
8150/*
8151 * "strchars()" function
8152 */
8153 static void
8154f_strchars(typval_T *argvars, typval_T *rettv)
8155{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008156 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008157 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158 varnumber_T len = 0;
8159 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160
8161 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008162 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008164 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165 else
8166 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8168 while (*s != NUL)
8169 {
8170 func_mb_ptr2char_adv(&s);
8171 ++len;
8172 }
8173 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174 }
8175}
8176
8177/*
8178 * "strdisplaywidth()" function
8179 */
8180 static void
8181f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8182{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008183 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 int col = 0;
8185
8186 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008187 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188
8189 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8190}
8191
8192/*
8193 * "strwidth()" function
8194 */
8195 static void
8196f_strwidth(typval_T *argvars, typval_T *rettv)
8197{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008198 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008199
Bram Moolenaar13505972019-01-24 15:04:48 +01008200 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201}
8202
8203/*
8204 * "strcharpart()" function
8205 */
8206 static void
8207f_strcharpart(typval_T *argvars, typval_T *rettv)
8208{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008209 char_u *p;
8210 int nchar;
8211 int nbyte = 0;
8212 int charlen;
8213 int len = 0;
8214 int slen;
8215 int error = FALSE;
8216
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008217 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008218 slen = (int)STRLEN(p);
8219
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008220 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008221 if (!error)
8222 {
8223 if (nchar > 0)
8224 while (nchar > 0 && nbyte < slen)
8225 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008226 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008227 --nchar;
8228 }
8229 else
8230 nbyte = nchar;
8231 if (argvars[2].v_type != VAR_UNKNOWN)
8232 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008233 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008234 while (charlen > 0 && nbyte + len < slen)
8235 {
8236 int off = nbyte + len;
8237
8238 if (off < 0)
8239 len += 1;
8240 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008241 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008242 --charlen;
8243 }
8244 }
8245 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008246 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008247 }
8248
8249 /*
8250 * Only return the overlap between the specified part and the actual
8251 * string.
8252 */
8253 if (nbyte < 0)
8254 {
8255 len += nbyte;
8256 nbyte = 0;
8257 }
8258 else if (nbyte > slen)
8259 nbyte = slen;
8260 if (len < 0)
8261 len = 0;
8262 else if (nbyte + len > slen)
8263 len = slen - nbyte;
8264
8265 rettv->v_type = VAR_STRING;
8266 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008267}
8268
8269/*
8270 * "strpart()" function
8271 */
8272 static void
8273f_strpart(typval_T *argvars, typval_T *rettv)
8274{
8275 char_u *p;
8276 int n;
8277 int len;
8278 int slen;
8279 int error = FALSE;
8280
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008281 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008282 slen = (int)STRLEN(p);
8283
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008284 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008285 if (error)
8286 len = 0;
8287 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008288 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008289 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008290 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008291
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02008292 // Only return the overlap between the specified part and the actual
8293 // string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008294 if (n < 0)
8295 {
8296 len += n;
8297 n = 0;
8298 }
8299 else if (n > slen)
8300 n = slen;
8301 if (len < 0)
8302 len = 0;
8303 else if (n + len > slen)
8304 len = slen - n;
8305
Bram Moolenaar6c53fca2020-08-23 17:34:46 +02008306 if (argvars[2].v_type != VAR_UNKNOWN && argvars[3].v_type != VAR_UNKNOWN)
8307 {
8308 int off;
8309
8310 // length in characters
8311 for (off = n; off < slen && len > 0; --len)
8312 off += mb_ptr2len(p + off);
8313 len = off - n;
8314 }
8315
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316 rettv->v_type = VAR_STRING;
8317 rettv->vval.v_string = vim_strnsave(p + n, len);
8318}
8319
8320/*
8321 * "strridx()" function
8322 */
8323 static void
8324f_strridx(typval_T *argvars, typval_T *rettv)
8325{
8326 char_u buf[NUMBUFLEN];
8327 char_u *needle;
8328 char_u *haystack;
8329 char_u *rest;
8330 char_u *lastmatch = NULL;
8331 int haystack_len, end_idx;
8332
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008333 needle = tv_get_string_chk(&argvars[1]);
8334 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008335
8336 rettv->vval.v_number = -1;
8337 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008338 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339
8340 haystack_len = (int)STRLEN(haystack);
8341 if (argvars[2].v_type != VAR_UNKNOWN)
8342 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008343 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008344 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008345 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008346 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008347 }
8348 else
8349 end_idx = haystack_len;
8350
8351 if (*needle == NUL)
8352 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008353 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008354 lastmatch = haystack + end_idx;
8355 }
8356 else
8357 {
8358 for (rest = haystack; *rest != '\0'; ++rest)
8359 {
8360 rest = (char_u *)strstr((char *)rest, (char *)needle);
8361 if (rest == NULL || rest > haystack + end_idx)
8362 break;
8363 lastmatch = rest;
8364 }
8365 }
8366
8367 if (lastmatch == NULL)
8368 rettv->vval.v_number = -1;
8369 else
8370 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8371}
8372
8373/*
8374 * "strtrans()" function
8375 */
8376 static void
8377f_strtrans(typval_T *argvars, typval_T *rettv)
8378{
8379 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008380 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008381}
8382
8383/*
8384 * "submatch()" function
8385 */
8386 static void
8387f_submatch(typval_T *argvars, typval_T *rettv)
8388{
8389 int error = FALSE;
8390 int no;
8391 int retList = 0;
8392
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008393 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008394 if (error)
8395 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008396 if (no < 0 || no >= NSUBEXP)
8397 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008398 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008399 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008400 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008401 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008402 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008403 if (error)
8404 return;
8405
8406 if (retList == 0)
8407 {
8408 rettv->v_type = VAR_STRING;
8409 rettv->vval.v_string = reg_submatch(no);
8410 }
8411 else
8412 {
8413 rettv->v_type = VAR_LIST;
8414 rettv->vval.v_list = reg_submatch_list(no);
8415 }
8416}
8417
8418/*
8419 * "substitute()" function
8420 */
8421 static void
8422f_substitute(typval_T *argvars, typval_T *rettv)
8423{
8424 char_u patbuf[NUMBUFLEN];
8425 char_u subbuf[NUMBUFLEN];
8426 char_u flagsbuf[NUMBUFLEN];
8427
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008428 char_u *str = tv_get_string_chk(&argvars[0]);
8429 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008430 char_u *sub = NULL;
8431 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008432 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008433
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008434 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8435 expr = &argvars[2];
8436 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008437 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008438
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008439 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008440 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8441 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008442 rettv->vval.v_string = NULL;
8443 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008444 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008445}
8446
8447/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008448 * "swapinfo(swap_filename)" function
8449 */
8450 static void
8451f_swapinfo(typval_T *argvars, typval_T *rettv)
8452{
8453 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008454 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008455}
8456
8457/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008458 * "swapname(expr)" function
8459 */
8460 static void
8461f_swapname(typval_T *argvars, typval_T *rettv)
8462{
8463 buf_T *buf;
8464
8465 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008466 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008467 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8468 || buf->b_ml.ml_mfp->mf_fname == NULL)
8469 rettv->vval.v_string = NULL;
8470 else
8471 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8472}
8473
8474/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008475 * "synID(lnum, col, trans)" function
8476 */
8477 static void
8478f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8479{
8480 int id = 0;
8481#ifdef FEAT_SYN_HL
8482 linenr_T lnum;
8483 colnr_T col;
8484 int trans;
8485 int transerr = FALSE;
8486
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008487 lnum = tv_get_lnum(argvars); // -1 on type error
8488 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008489 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490
8491 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8492 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8493 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8494#endif
8495
8496 rettv->vval.v_number = id;
8497}
8498
8499/*
8500 * "synIDattr(id, what [, mode])" function
8501 */
8502 static void
8503f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8504{
8505 char_u *p = NULL;
8506#ifdef FEAT_SYN_HL
8507 int id;
8508 char_u *what;
8509 char_u *mode;
8510 char_u modebuf[NUMBUFLEN];
8511 int modec;
8512
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008513 id = (int)tv_get_number(&argvars[0]);
8514 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008515 if (argvars[2].v_type != VAR_UNKNOWN)
8516 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008517 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008518 modec = TOLOWER_ASC(mode[0]);
8519 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008520 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008521 }
8522 else
8523 {
8524#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8525 if (USE_24BIT)
8526 modec = 'g';
8527 else
8528#endif
8529 if (t_colors > 1)
8530 modec = 'c';
8531 else
8532 modec = 't';
8533 }
8534
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008535 switch (TOLOWER_ASC(what[0]))
8536 {
8537 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008538 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008539 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008540 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008541 p = highlight_has_attr(id, HL_BOLD, modec);
8542 break;
8543
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008544 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008545 p = highlight_color(id, what, modec);
8546 break;
8547
8548 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008549 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008550 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008551 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008552 p = highlight_has_attr(id, HL_ITALIC, modec);
8553 break;
8554
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008555 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008556 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008557 break;
8558
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008559 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008560 p = highlight_has_attr(id, HL_INVERSE, modec);
8561 break;
8562
8563 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008564 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008565 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008566 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008567 else if (TOLOWER_ASC(what[1]) == 't' &&
8568 TOLOWER_ASC(what[2]) == 'r')
8569 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008570 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008571 p = highlight_has_attr(id, HL_STANDOUT, modec);
8572 break;
8573
8574 case 'u':
8575 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008576 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008577 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8578 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008579 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008580 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8581 break;
8582 }
8583
8584 if (p != NULL)
8585 p = vim_strsave(p);
8586#endif
8587 rettv->v_type = VAR_STRING;
8588 rettv->vval.v_string = p;
8589}
8590
8591/*
8592 * "synIDtrans(id)" function
8593 */
8594 static void
8595f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8596{
8597 int id;
8598
8599#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008600 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008601
8602 if (id > 0)
8603 id = syn_get_final_id(id);
8604 else
8605#endif
8606 id = 0;
8607
8608 rettv->vval.v_number = id;
8609}
8610
8611/*
8612 * "synconcealed(lnum, col)" function
8613 */
8614 static void
8615f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8616{
8617#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8618 linenr_T lnum;
8619 colnr_T col;
8620 int syntax_flags = 0;
8621 int cchar;
8622 int matchid = 0;
8623 char_u str[NUMBUFLEN];
8624#endif
8625
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008626 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008627
8628#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008629 lnum = tv_get_lnum(argvars); // -1 on type error
8630 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008631
Bram Moolenaara80faa82020-04-12 19:37:17 +02008632 CLEAR_FIELD(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008633
8634 if (rettv_list_alloc(rettv) != FAIL)
8635 {
8636 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8637 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8638 && curwin->w_p_cole > 0)
8639 {
8640 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8641 syntax_flags = get_syntax_info(&matchid);
8642
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008643 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8645 {
8646 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008647 if (cchar == NUL && curwin->w_p_cole == 1)
8648 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008649 if (cchar != NUL)
8650 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008651 if (has_mbyte)
8652 (*mb_char2bytes)(cchar, str);
8653 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008654 str[0] = cchar;
8655 }
8656 }
8657 }
8658
8659 list_append_number(rettv->vval.v_list,
8660 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008661 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008662 list_append_string(rettv->vval.v_list, str, -1);
8663 list_append_number(rettv->vval.v_list, matchid);
8664 }
8665#endif
8666}
8667
8668/*
8669 * "synstack(lnum, col)" function
8670 */
8671 static void
8672f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8673{
8674#ifdef FEAT_SYN_HL
8675 linenr_T lnum;
8676 colnr_T col;
8677 int i;
8678 int id;
8679#endif
8680
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008681 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008682
8683#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008684 lnum = tv_get_lnum(argvars); // -1 on type error
8685 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008686
8687 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8688 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8689 && rettv_list_alloc(rettv) != FAIL)
8690 {
8691 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8692 for (i = 0; ; ++i)
8693 {
8694 id = syn_get_stack_item(i);
8695 if (id < 0)
8696 break;
8697 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8698 break;
8699 }
8700 }
8701#endif
8702}
8703
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008704/*
8705 * "tabpagebuflist()" function
8706 */
8707 static void
8708f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8709{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008710 tabpage_T *tp;
8711 win_T *wp = NULL;
8712
8713 if (argvars[0].v_type == VAR_UNKNOWN)
8714 wp = firstwin;
8715 else
8716 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008717 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008718 if (tp != NULL)
8719 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8720 }
8721 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8722 {
8723 for (; wp != NULL; wp = wp->w_next)
8724 if (list_append_number(rettv->vval.v_list,
8725 wp->w_buffer->b_fnum) == FAIL)
8726 break;
8727 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008728}
8729
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008730/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008731 * "tagfiles()" function
8732 */
8733 static void
8734f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8735{
8736 char_u *fname;
8737 tagname_T tn;
8738 int first;
8739
8740 if (rettv_list_alloc(rettv) == FAIL)
8741 return;
8742 fname = alloc(MAXPATHL);
8743 if (fname == NULL)
8744 return;
8745
8746 for (first = TRUE; ; first = FALSE)
8747 if (get_tagfname(&tn, first, fname) == FAIL
8748 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8749 break;
8750 tagname_free(&tn);
8751 vim_free(fname);
8752}
8753
8754/*
8755 * "taglist()" function
8756 */
8757 static void
8758f_taglist(typval_T *argvars, typval_T *rettv)
8759{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008760 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008761 char_u *tag_pattern;
8762
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008763 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008764
8765 rettv->vval.v_number = FALSE;
8766 if (*tag_pattern == NUL)
8767 return;
8768
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008769 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008770 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008771 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008772 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008773}
8774
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008775#ifdef FEAT_FLOAT
8776/*
8777 * "tan()" function
8778 */
8779 static void
8780f_tan(typval_T *argvars, typval_T *rettv)
8781{
8782 float_T f = 0.0;
8783
8784 rettv->v_type = VAR_FLOAT;
8785 if (get_float_arg(argvars, &f) == OK)
8786 rettv->vval.v_float = tan(f);
8787 else
8788 rettv->vval.v_float = 0.0;
8789}
8790
8791/*
8792 * "tanh()" function
8793 */
8794 static void
8795f_tanh(typval_T *argvars, typval_T *rettv)
8796{
8797 float_T f = 0.0;
8798
8799 rettv->v_type = VAR_FLOAT;
8800 if (get_float_arg(argvars, &f) == OK)
8801 rettv->vval.v_float = tanh(f);
8802 else
8803 rettv->vval.v_float = 0.0;
8804}
8805#endif
8806
8807/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008808 * "tolower(string)" function
8809 */
8810 static void
8811f_tolower(typval_T *argvars, typval_T *rettv)
8812{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008813 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008814 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008815}
8816
8817/*
8818 * "toupper(string)" function
8819 */
8820 static void
8821f_toupper(typval_T *argvars, typval_T *rettv)
8822{
8823 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008824 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008825}
8826
8827/*
8828 * "tr(string, fromstr, tostr)" function
8829 */
8830 static void
8831f_tr(typval_T *argvars, typval_T *rettv)
8832{
8833 char_u *in_str;
8834 char_u *fromstr;
8835 char_u *tostr;
8836 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008837 int inlen;
8838 int fromlen;
8839 int tolen;
8840 int idx;
8841 char_u *cpstr;
8842 int cplen;
8843 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008844 char_u buf[NUMBUFLEN];
8845 char_u buf2[NUMBUFLEN];
8846 garray_T ga;
8847
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008848 in_str = tv_get_string(&argvars[0]);
8849 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8850 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008851
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008852 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008853 rettv->v_type = VAR_STRING;
8854 rettv->vval.v_string = NULL;
8855 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008856 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008857 ga_init2(&ga, (int)sizeof(char), 80);
8858
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008859 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008860 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008861 if (STRLEN(fromstr) != STRLEN(tostr))
8862 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008863error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008864 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008865 ga_clear(&ga);
8866 return;
8867 }
8868
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008869 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008870 while (*in_str != NUL)
8871 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008872 if (has_mbyte)
8873 {
8874 inlen = (*mb_ptr2len)(in_str);
8875 cpstr = in_str;
8876 cplen = inlen;
8877 idx = 0;
8878 for (p = fromstr; *p != NUL; p += fromlen)
8879 {
8880 fromlen = (*mb_ptr2len)(p);
8881 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8882 {
8883 for (p = tostr; *p != NUL; p += tolen)
8884 {
8885 tolen = (*mb_ptr2len)(p);
8886 if (idx-- == 0)
8887 {
8888 cplen = tolen;
8889 cpstr = p;
8890 break;
8891 }
8892 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008893 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008894 goto error;
8895 break;
8896 }
8897 ++idx;
8898 }
8899
8900 if (first && cpstr == in_str)
8901 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008902 // Check that fromstr and tostr have the same number of
8903 // (multi-byte) characters. Done only once when a character
8904 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008905 first = FALSE;
8906 for (p = tostr; *p != NUL; p += tolen)
8907 {
8908 tolen = (*mb_ptr2len)(p);
8909 --idx;
8910 }
8911 if (idx != 0)
8912 goto error;
8913 }
8914
8915 (void)ga_grow(&ga, cplen);
8916 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8917 ga.ga_len += cplen;
8918
8919 in_str += inlen;
8920 }
8921 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008922 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008923 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008924 p = vim_strchr(fromstr, *in_str);
8925 if (p != NULL)
8926 ga_append(&ga, tostr[p - fromstr]);
8927 else
8928 ga_append(&ga, *in_str);
8929 ++in_str;
8930 }
8931 }
8932
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008933 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008934 (void)ga_grow(&ga, 1);
8935 ga_append(&ga, NUL);
8936
8937 rettv->vval.v_string = ga.ga_data;
8938}
8939
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008940/*
8941 * "trim({expr})" function
8942 */
8943 static void
8944f_trim(typval_T *argvars, typval_T *rettv)
8945{
8946 char_u buf1[NUMBUFLEN];
8947 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008948 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008949 char_u *mask = NULL;
8950 char_u *tail;
8951 char_u *prev;
8952 char_u *p;
8953 int c1;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008954 int dir = 0;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008955
8956 rettv->v_type = VAR_STRING;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008957 rettv->vval.v_string = NULL;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008958 if (head == NULL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008959 return;
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008960
8961 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008962 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008963 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008964
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008965 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008966 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008967 int error = 0;
8968
8969 // leading or trailing characters to trim
8970 dir = (int)tv_get_number_chk(&argvars[2], &error);
8971 if (error)
8972 return;
8973 if (dir < 0 || dir > 2)
8974 {
8975 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
8976 return;
8977 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008978 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008979 }
8980
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008981 if (dir == 0 || dir == 1)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008982 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008983 // Trim leading characters
8984 while (*head != NUL)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008985 {
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008986 c1 = PTR2CHAR(head);
8987 if (mask == NULL)
8988 {
8989 if (c1 > ' ' && c1 != 0xa0)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008990 break;
Bram Moolenaar2245ae12020-05-31 22:20:36 +02008991 }
8992 else
8993 {
8994 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8995 if (c1 == PTR2CHAR(p))
8996 break;
8997 if (*p == NUL)
8998 break;
8999 }
9000 MB_PTR_ADV(head);
9001 }
9002 }
9003
9004 tail = head + STRLEN(head);
9005 if (dir == 0 || dir == 2)
9006 {
9007 // Trim trailing characters
9008 for (; tail > head; tail = prev)
9009 {
9010 prev = tail;
9011 MB_PTR_BACK(head, prev);
9012 c1 = PTR2CHAR(prev);
9013 if (mask == NULL)
9014 {
9015 if (c1 > ' ' && c1 != 0xa0)
9016 break;
9017 }
9018 else
9019 {
9020 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9021 if (c1 == PTR2CHAR(p))
9022 break;
9023 if (*p == NUL)
9024 break;
9025 }
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009026 }
9027 }
Bram Moolenaardf44a272020-06-07 20:49:05 +02009028 rettv->vval.v_string = vim_strnsave(head, tail - head);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009029}
9030
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009031#ifdef FEAT_FLOAT
9032/*
9033 * "trunc({float})" function
9034 */
9035 static void
9036f_trunc(typval_T *argvars, typval_T *rettv)
9037{
9038 float_T f = 0.0;
9039
9040 rettv->v_type = VAR_FLOAT;
9041 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009042 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009043 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
9044 else
9045 rettv->vval.v_float = 0.0;
9046}
9047#endif
9048
9049/*
9050 * "type(expr)" function
9051 */
9052 static void
9053f_type(typval_T *argvars, typval_T *rettv)
9054{
9055 int n = -1;
9056
9057 switch (argvars[0].v_type)
9058 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009059 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
9060 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009061 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009062 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
9063 case VAR_LIST: n = VAR_TYPE_LIST; break;
9064 case VAR_DICT: n = VAR_TYPE_DICT; break;
9065 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
9066 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
9067 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02009068 case VAR_JOB: n = VAR_TYPE_JOB; break;
9069 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009070 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009071 case VAR_UNKNOWN:
Bram Moolenaar4c683752020-04-05 21:38:23 +02009072 case VAR_ANY:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01009073 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01009074 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009075 n = -1;
9076 break;
9077 }
9078 rettv->vval.v_number = n;
9079}
9080
9081/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009082 * "virtcol(string)" function
9083 */
9084 static void
9085f_virtcol(typval_T *argvars, typval_T *rettv)
9086{
9087 colnr_T vcol = 0;
9088 pos_T *fp;
9089 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009090 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009091
9092 fp = var2fpos(&argvars[0], FALSE, &fnum);
9093 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9094 && fnum == curbuf->b_fnum)
9095 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009096 // Limit the column to a valid value, getvvcol() doesn't check.
9097 if (fp->col < 0)
9098 fp->col = 0;
9099 else
9100 {
9101 len = (int)STRLEN(ml_get(fp->lnum));
9102 if (fp->col > len)
9103 fp->col = len;
9104 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009105 getvvcol(curwin, fp, NULL, NULL, &vcol);
9106 ++vcol;
9107 }
9108
9109 rettv->vval.v_number = vcol;
9110}
9111
9112/*
9113 * "visualmode()" function
9114 */
9115 static void
9116f_visualmode(typval_T *argvars, typval_T *rettv)
9117{
9118 char_u str[2];
9119
9120 rettv->v_type = VAR_STRING;
9121 str[0] = curbuf->b_visual_mode_eval;
9122 str[1] = NUL;
9123 rettv->vval.v_string = vim_strsave(str);
9124
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009125 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009126 if (non_zero_arg(&argvars[0]))
9127 curbuf->b_visual_mode_eval = NUL;
9128}
9129
9130/*
9131 * "wildmenumode()" function
9132 */
9133 static void
9134f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9135{
9136#ifdef FEAT_WILDMENU
9137 if (wild_menu_showing)
9138 rettv->vval.v_number = 1;
9139#endif
9140}
9141
9142/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01009143 * "windowsversion()" function
9144 */
9145 static void
9146f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9147{
9148 rettv->v_type = VAR_STRING;
9149 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
9150}
9151
9152/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009153 * "wordcount()" function
9154 */
9155 static void
9156f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
9157{
9158 if (rettv_dict_alloc(rettv) == FAIL)
9159 return;
9160 cursor_pos_info(rettv->vval.v_dict);
9161}
9162
9163/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009164 * "xor(expr, expr)" function
9165 */
9166 static void
9167f_xor(typval_T *argvars, typval_T *rettv)
9168{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009169 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9170 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009171}
9172
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009173#endif // FEAT_EVAL