blob: 9e8e0fed0b322f117896037f65649135a8fc13d1 [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);
97static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010098static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
100static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_hlID(typval_T *argvars, typval_T *rettv);
102static void f_hlexists(typval_T *argvars, typval_T *rettv);
103static void f_hostname(typval_T *argvars, typval_T *rettv);
104static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_index(typval_T *argvars, typval_T *rettv);
106static void f_input(typval_T *argvars, typval_T *rettv);
107static void f_inputdialog(typval_T *argvars, typval_T *rettv);
108static void f_inputlist(typval_T *argvars, typval_T *rettv);
109static void f_inputrestore(typval_T *argvars, typval_T *rettv);
110static void f_inputsave(typval_T *argvars, typval_T *rettv);
111static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100112static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200113static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_islocked(typval_T *argvars, typval_T *rettv);
115#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200116static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_isnan(typval_T *argvars, typval_T *rettv);
118#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
120static void f_len(typval_T *argvars, typval_T *rettv);
121static void f_libcall(typval_T *argvars, typval_T *rettv);
122static void f_libcallnr(typval_T *argvars, typval_T *rettv);
123static void f_line(typval_T *argvars, typval_T *rettv);
124static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125#ifdef FEAT_FLOAT
126static void f_log(typval_T *argvars, typval_T *rettv);
127static void f_log10(typval_T *argvars, typval_T *rettv);
128#endif
129#ifdef FEAT_LUA
130static void f_luaeval(typval_T *argvars, typval_T *rettv);
131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_maparg(typval_T *argvars, typval_T *rettv);
133static void f_mapcheck(typval_T *argvars, typval_T *rettv);
134static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_matchend(typval_T *argvars, typval_T *rettv);
136static void f_matchlist(typval_T *argvars, typval_T *rettv);
137static void f_matchstr(typval_T *argvars, typval_T *rettv);
138static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
139static void f_max(typval_T *argvars, typval_T *rettv);
140static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141#ifdef FEAT_MZSCHEME
142static void f_mzeval(typval_T *argvars, typval_T *rettv);
143#endif
144static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
145static void f_nr2char(typval_T *argvars, typval_T *rettv);
146static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_PERL
148static void f_perleval(typval_T *argvars, typval_T *rettv);
149#endif
150#ifdef FEAT_FLOAT
151static void f_pow(typval_T *argvars, typval_T *rettv);
152#endif
153static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
154static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200155static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_pumvisible(typval_T *argvars, typval_T *rettv);
157#ifdef FEAT_PYTHON3
158static void f_py3eval(typval_T *argvars, typval_T *rettv);
159#endif
160#ifdef FEAT_PYTHON
161static void f_pyeval(typval_T *argvars, typval_T *rettv);
162#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
164static void f_pyxeval(typval_T *argvars, typval_T *rettv);
165#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100166static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100167static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200169static void f_reg_executing(typval_T *argvars, typval_T *rettv);
170static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_remote_expr(typval_T *argvars, typval_T *rettv);
172static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
173static void f_remote_peek(typval_T *argvars, typval_T *rettv);
174static void f_remote_read(typval_T *argvars, typval_T *rettv);
175static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100176static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_rename(typval_T *argvars, typval_T *rettv);
178static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179#ifdef FEAT_FLOAT
180static void f_round(typval_T *argvars, typval_T *rettv);
181#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100182#ifdef FEAT_RUBY
183static void f_rubyeval(typval_T *argvars, typval_T *rettv);
184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_screenattr(typval_T *argvars, typval_T *rettv);
186static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100187static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_screencol(typval_T *argvars, typval_T *rettv);
189static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100190static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_search(typval_T *argvars, typval_T *rettv);
192static void f_searchdecl(typval_T *argvars, typval_T *rettv);
193static void f_searchpair(typval_T *argvars, typval_T *rettv);
194static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
195static void f_searchpos(typval_T *argvars, typval_T *rettv);
196static void f_server2client(typval_T *argvars, typval_T *rettv);
197static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200199static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100203static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204#ifdef FEAT_CRYPT
205static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_shellescape(typval_T *argvars, typval_T *rettv);
208static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209#ifdef FEAT_FLOAT
210static void f_sin(typval_T *argvars, typval_T *rettv);
211static void f_sinh(typval_T *argvars, typval_T *rettv);
212#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_soundfold(typval_T *argvars, typval_T *rettv);
214static void f_spellbadword(typval_T *argvars, typval_T *rettv);
215static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
216static void f_split(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100219#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100220static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100221#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_str2float(typval_T *argvars, typval_T *rettv);
223#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200224static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_str2nr(typval_T *argvars, typval_T *rettv);
226static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200227static void f_strgetchar(typval_T *argvars, typval_T *rettv);
228static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200229static void f_strlen(typval_T *argvars, typval_T *rettv);
230static void f_strcharpart(typval_T *argvars, typval_T *rettv);
231static void f_strpart(typval_T *argvars, typval_T *rettv);
232static void f_strridx(typval_T *argvars, typval_T *rettv);
233static void f_strtrans(typval_T *argvars, typval_T *rettv);
234static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
235static void f_strwidth(typval_T *argvars, typval_T *rettv);
236static void f_submatch(typval_T *argvars, typval_T *rettv);
237static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200238static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200239static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_synID(typval_T *argvars, typval_T *rettv);
241static void f_synIDattr(typval_T *argvars, typval_T *rettv);
242static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
243static void f_synstack(typval_T *argvars, typval_T *rettv);
244static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_taglist(typval_T *argvars, typval_T *rettv);
247static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248#ifdef FEAT_FLOAT
249static void f_tan(typval_T *argvars, typval_T *rettv);
250static void f_tanh(typval_T *argvars, typval_T *rettv);
251#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200252static void f_tolower(typval_T *argvars, typval_T *rettv);
253static void f_toupper(typval_T *argvars, typval_T *rettv);
254static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100255static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256#ifdef FEAT_FLOAT
257static void f_trunc(typval_T *argvars, typval_T *rettv);
258#endif
259static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_virtcol(typval_T *argvars, typval_T *rettv);
261static void f_visualmode(typval_T *argvars, typval_T *rettv);
262static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100263static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_wordcount(typval_T *argvars, typval_T *rettv);
265static void f_xor(typval_T *argvars, typval_T *rettv);
266
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100267
268 static type_T *
269ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
270{
271 return &t_void;
272}
273 static type_T *
274ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
275{
276 return &t_any;
277}
278 static type_T *
279ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
280{
281 return &t_number;
282}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100283#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100284 static type_T *
285ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
286{
287 return &t_float;
288}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100289#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100290 static type_T *
291ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
292{
293 return &t_string;
294}
295 static type_T * ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
296{
297 return &t_list_any;
298}
299 static type_T *
300ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
301{
302 return &t_list_number;
303}
304 static type_T *
305ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
306{
307 return &t_list_string;
308}
309 static type_T *
310ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
311{
312 return &t_list_dict_any;
313}
314 static type_T *
315ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
316{
317 return &t_dict_any;
318}
319 static type_T *
320ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
321{
322 return &t_dict_number;
323}
324 static type_T *
325ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
326{
327 return &t_dict_string;
328}
329 static type_T *
330ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
331{
332 return &t_blob;
333}
334 static type_T *
335ret_partial_void(int argcount UNUSED, type_T **argtypes UNUSED)
336{
337 return &t_partial_void;
338}
339#ifdef FEAT_JOB_CHANNEL
340 static type_T *
341ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
342{
343 return &t_channel;
344}
345 static type_T *
346ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
347{
348 return &t_job;
349}
350#endif
351
352static type_T *ret_f_function(int argcount, type_T **argtypes);
353
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200354/*
355 * Array with names and number of arguments of all internal functions
356 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
357 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200358typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200360 char *f_name; // function name
361 char f_min_argc; // minimal number of arguments
362 char f_max_argc; // maximal number of arguments
363 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100364 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
365 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200367 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200368} funcentry_T;
369
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200370// values for f_argtype; zero means it cannot be used as a method
371#define FEARG_1 1 // base is the first argument
372#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200373#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200374#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200375#define FEARG_LAST 9 // base is the last argument
376
Bram Moolenaarac92e252019-08-03 21:58:38 +0200377static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378{
379#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100380 {"abs", 1, 1, FEARG_1, ret_any, f_abs},
381 {"acos", 1, 1, FEARG_1, ret_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200382#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100383 {"add", 2, 2, FEARG_1, ret_any, f_add},
384 {"and", 2, 2, FEARG_1, ret_number, f_and},
385 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
386 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
387 {"argc", 0, 1, 0, ret_number, f_argc},
388 {"argidx", 0, 0, 0, ret_number, f_argidx},
389 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
390 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100392 {"asin", 1, 1, FEARG_1, ret_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200393#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100394 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
395 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
396 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile},
397 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
398 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
399 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
400 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
401 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
402 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
403 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
404 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
405 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100407 {"atan", 1, 1, FEARG_1, ret_float, f_atan},
408 {"atan2", 2, 2, FEARG_1, ret_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100410#ifdef FEAT_BEVAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100411 {"balloon_gettext", 0, 0, 0, ret_string, f_balloon_gettext},
412 {"balloon_show", 1, 1, FEARG_1, ret_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100413# if defined(FEAT_BEVAL_TERM)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100414 {"balloon_split", 1, 1, FEARG_1, ret_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100415# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100416#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100417 {"browse", 4, 4, 0, ret_string, f_browse},
418 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
419 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
420 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
421 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
422 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
423 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
424 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
425 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
426 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
427 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
428 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
429 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
430 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
431 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
432 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
433 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
434 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100436 {"ceil", 1, 1, FEARG_1, ret_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
438#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100439 {"ch_canread", 1, 1, FEARG_1, ret_number, f_ch_canread},
440 {"ch_close", 1, 1, FEARG_1, ret_void, f_ch_close},
441 {"ch_close_in", 1, 1, FEARG_1, ret_void, f_ch_close_in},
442 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, f_ch_evalexpr},
443 {"ch_evalraw", 2, 3, FEARG_1, ret_any, f_ch_evalraw},
444 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, f_ch_getbufnr},
445 {"ch_getjob", 1, 1, FEARG_1, ret_job, f_ch_getjob},
446 {"ch_info", 1, 1, FEARG_1, ret_dict_any, f_ch_info},
447 {"ch_log", 1, 2, FEARG_1, ret_void, f_ch_log},
448 {"ch_logfile", 1, 2, FEARG_1, ret_void, f_ch_logfile},
449 {"ch_open", 1, 2, FEARG_1, ret_channel, f_ch_open},
450 {"ch_read", 1, 2, FEARG_1, ret_string, f_ch_read},
451 {"ch_readblob", 1, 2, FEARG_1, ret_blob, f_ch_readblob},
452 {"ch_readraw", 1, 2, FEARG_1, ret_string, f_ch_readraw},
453 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, f_ch_sendexpr},
454 {"ch_sendraw", 2, 3, FEARG_1, ret_void, f_ch_sendraw},
455 {"ch_setoptions", 2, 2, FEARG_1, ret_void, f_ch_setoptions},
456 {"ch_status", 1, 2, FEARG_1, ret_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200457#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100458 {"changenr", 0, 0, 0, ret_number, f_changenr},
459 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
460 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
461 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
462 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
463 {"col", 1, 1, FEARG_1, ret_number, f_col},
464 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
465 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
466 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
467 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
468 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
469 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200470#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100471 {"cos", 1, 1, FEARG_1, ret_float, f_cos},
472 {"cosh", 1, 1, FEARG_1, ret_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100474 {"count", 2, 4, FEARG_1, ret_number, f_count},
475 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
476 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100477#ifdef MSWIN
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100478 {"debugbreak", 1, 1, FEARG_1, ret_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200479#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100480 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
481 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
482 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
483 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
484 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
485 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
486 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
487 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
488 {"environ", 0, 0, 0, ret_dict_string, f_environ},
489 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
490 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
491 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
492 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
493 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
494 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
495 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200496#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"exp", 1, 1, FEARG_1, ret_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100499 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
500 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
501 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
502 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
503 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
504 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
505 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
506 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
507 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
508 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100510 {"float2nr", 1, 1, FEARG_1, ret_number, f_float2nr},
511 {"floor", 1, 1, FEARG_1, ret_float, f_floor},
512 {"fmod", 2, 2, FEARG_1, ret_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100514 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
515 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
516 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
517 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
518 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
519 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
520 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
521 {"foreground", 0, 0, 0, ret_void, f_foreground},
522 {"funcref", 1, 3, FEARG_1, ret_partial_void, f_funcref},
523 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
524 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
525 {"get", 2, 3, FEARG_1, ret_any, f_get},
526 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
527 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
528 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
529 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
530 {"getchar", 0, 1, 0, ret_number, f_getchar},
531 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
532 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
533 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
534 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
535 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
536 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
537 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
538 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
539 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
540 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
541 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
542 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
543 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
544 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
545 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
546 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
547 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
548 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
549 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
550 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
551 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
552 {"getpid", 0, 0, 0, ret_number, f_getpid},
553 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
554 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
555 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
556 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
557 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
558 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
559 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
560 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
561 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
562 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
563 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
564 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
565 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
566 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
567 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
568 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
569 {"has", 1, 1, 0, ret_number, f_has},
570 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
571 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
572 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
573 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
574 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
575 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
576 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
577 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
578 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
579 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
580 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
581 {"hostname", 0, 0, 0, ret_string, f_hostname},
582 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
583 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
584 {"index", 2, 4, FEARG_1, ret_number, f_index},
585 {"input", 1, 3, FEARG_1, ret_string, f_input},
586 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
587 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
588 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
589 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
590 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
591 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
592 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
593 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
594 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200595#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100596 {"isinf", 1, 1, FEARG_1, ret_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200597#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100598 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"isnan", 1, 1, FEARG_1, ret_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100602 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100604 {"job_getchannel", 1, 1, FEARG_1, ret_channel, f_job_getchannel},
605 {"job_info", 0, 1, FEARG_1, ret_dict_any, f_job_info},
606 {"job_setoptions", 2, 2, FEARG_1, ret_void, f_job_setoptions},
607 {"job_start", 1, 2, FEARG_1, ret_job, f_job_start},
608 {"job_status", 1, 1, FEARG_1, ret_string, f_job_status},
609 {"job_stop", 1, 2, FEARG_1, ret_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100611 {"join", 1, 2, FEARG_1, ret_string, f_join},
612 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
613 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
614 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
615 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
616 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
617 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
618 {"len", 1, 1, FEARG_1, ret_number, f_len},
619 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
620 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
621 {"line", 1, 2, FEARG_1, ret_number, f_line},
622 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
623 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
624 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
625 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
626 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
627 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
628 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200629#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100630 {"log", 1, 1, FEARG_1, ret_float, f_log},
631 {"log10", 1, 1, FEARG_1, ret_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#endif
633#ifdef FEAT_LUA
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"luaeval", 1, 2, FEARG_1, ret_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100636 {"map", 2, 2, FEARG_1, ret_any, f_map},
637 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
638 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
639 {"match", 2, 4, FEARG_1, ret_any, f_match},
640 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
641 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
642 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
643 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
644 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
645 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
646 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
647 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
648 {"max", 1, 1, FEARG_1, ret_any, f_max},
649 {"min", 1, 1, FEARG_1, ret_any, f_min},
650 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
651 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652#ifdef FEAT_MZSCHEME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100653 {"mzeval", 1, 1, FEARG_1, ret_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200654#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100655 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
656 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
657 {"or", 2, 2, FEARG_1, ret_number, f_or},
658 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200659#ifdef FEAT_PERL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100660 {"perleval", 1, 1, FEARG_1, ret_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100662#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100663 {"popup_atcursor", 2, 2, FEARG_1, ret_number, f_popup_atcursor},
664 {"popup_beval", 2, 2, FEARG_1, ret_number, f_popup_beval},
665 {"popup_clear", 0, 0, 0, ret_void, f_popup_clear},
666 {"popup_close", 1, 2, FEARG_1, ret_void, f_popup_close},
667 {"popup_create", 2, 2, FEARG_1, ret_number, f_popup_create},
668 {"popup_dialog", 2, 2, FEARG_1, ret_number, f_popup_dialog},
669 {"popup_filter_menu", 2, 2, 0, ret_number, f_popup_filter_menu},
670 {"popup_filter_yesno", 2, 2, 0, ret_number, f_popup_filter_yesno},
671 {"popup_findinfo", 0, 0, 0, ret_number, f_popup_findinfo},
672 {"popup_findpreview", 0, 0, 0, ret_number, f_popup_findpreview},
673 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, f_popup_getoptions},
674 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, f_popup_getpos},
675 {"popup_hide", 1, 1, FEARG_1, ret_void, f_popup_hide},
676 {"popup_locate", 2, 2, 0, ret_number, f_popup_locate},
677 {"popup_menu", 2, 2, FEARG_1, ret_number, f_popup_menu},
678 {"popup_move", 2, 2, FEARG_1, ret_void, f_popup_move},
679 {"popup_notification", 2, 2, FEARG_1, ret_number, f_popup_notification},
680 {"popup_setoptions", 2, 2, FEARG_1, ret_void, f_popup_setoptions},
681 {"popup_settext", 2, 2, FEARG_1, ret_void, f_popup_settext},
682 {"popup_show", 1, 1, FEARG_1, ret_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200683#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200684#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100685 {"pow", 2, 2, FEARG_1, ret_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200686#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100687 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
688 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200689#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100690 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, f_prompt_setcallback},
691 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, f_prompt_setinterrupt},
692 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200693#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100694#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100695 {"prop_add", 3, 3, FEARG_1, ret_void, f_prop_add},
696 {"prop_clear", 1, 3, FEARG_1, ret_void, f_prop_clear},
697 {"prop_find", 1, 2, FEARG_1, ret_dict_any, f_prop_find},
698 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, f_prop_list},
699 {"prop_remove", 1, 3, FEARG_1, ret_number, f_prop_remove},
700 {"prop_type_add", 2, 2, FEARG_1, ret_void, f_prop_type_add},
701 {"prop_type_change", 2, 2, FEARG_1, ret_void, f_prop_type_change},
702 {"prop_type_delete", 1, 2, FEARG_1, ret_void, f_prop_type_delete},
703 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, f_prop_type_get},
704 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100705#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100706 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
707 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200708#ifdef FEAT_PYTHON3
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100709 {"py3eval", 1, 1, FEARG_1, ret_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200710#endif
711#ifdef FEAT_PYTHON
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100712 {"pyeval", 1, 1, FEARG_1, ret_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200713#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100714#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100715 {"pyxeval", 1, 1, FEARG_1, ret_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100716#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100717 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
718 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
719 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
720 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
721 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
722 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
723 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200724#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100725 {"reltimefloat", 1, 1, FEARG_1, ret_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200726#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100727 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
728 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
729 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
730 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
731 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
732 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
733 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
734 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
735 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
736 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
737 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
738 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200739#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100740 {"round", 1, 1, FEARG_1, ret_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200741#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100742#ifdef FEAT_RUBY
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100743 {"rubyeval", 1, 1, FEARG_1, ret_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100744#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100745 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
746 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
747 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
748 {"screencol", 0, 0, 0, ret_number, f_screencol},
749 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
750 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
751 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
752 {"search", 1, 4, FEARG_1, ret_number, f_search},
753 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
754 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
755 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
756 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
757 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
758 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
759 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
760 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
761 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
762 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
763 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
764 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
765 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
766 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
767 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
768 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
769 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
770 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
771 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
772 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
773 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
774 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200775#ifdef FEAT_CRYPT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100776 {"sha256", 1, 1, FEARG_1, ret_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100778 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
779 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100780#ifdef FEAT_SIGNS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100781 {"sign_define", 1, 2, FEARG_1, ret_any, f_sign_define},
782 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, f_sign_getdefined},
783 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, f_sign_getplaced},
784 {"sign_jump", 3, 3, FEARG_1, ret_number, f_sign_jump},
785 {"sign_place", 4, 5, FEARG_1, ret_number, f_sign_place},
786 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, f_sign_placelist},
787 {"sign_undefine", 0, 1, FEARG_1, ret_number, f_sign_undefine},
788 {"sign_unplace", 1, 2, FEARG_1, ret_number, f_sign_unplace},
789 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100790#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100791 {"simplify", 1, 1, 0, ret_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200792#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100793 {"sin", 1, 1, FEARG_1, ret_float, f_sin},
794 {"sinh", 1, 1, FEARG_1, ret_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200795#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100796 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200797#ifdef FEAT_SOUND
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100798 {"sound_clear", 0, 0, 0, ret_void, f_sound_clear},
799 {"sound_playevent", 1, 2, FEARG_1, ret_number, f_sound_playevent},
800 {"sound_playfile", 1, 2, FEARG_1, ret_number, f_sound_playfile},
801 {"sound_stop", 1, 1, FEARG_1, ret_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200802#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100803 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
804 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
805 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
806 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100808 {"sqrt", 1, 1, FEARG_1, ret_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200809#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100810 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
811 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200812#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100813 {"str2float", 1, 1, FEARG_1, ret_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100815 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
816 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
817 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
818 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
819 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820#ifdef HAVE_STRFTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100821 {"strftime", 1, 2, FEARG_1, ret_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100823 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
824 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
825 {"string", 1, 1, FEARG_1, ret_string, f_string},
826 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
827 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100828#ifdef HAVE_STRPTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100829 {"strptime", 2, 2, FEARG_1, ret_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100830#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100831 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
832 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
833 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
834 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
835 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
836 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
837 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
838 {"synID", 3, 3, 0, ret_number, f_synID},
839 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
840 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
841 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
842 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
843 {"system", 1, 2, FEARG_1, ret_string, f_system},
844 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
845 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
846 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
847 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
848 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
849 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100851 {"tan", 1, 1, FEARG_1, ret_float, f_tan},
852 {"tanh", 1, 1, FEARG_1, ret_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100854 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200855#ifdef FEAT_TERMINAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100856 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, f_term_dumpdiff},
857 {"term_dumpload", 1, 2, FEARG_1, ret_number, f_term_dumpload},
858 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, f_term_dumpwrite},
859 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200860# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100861 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200862# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100863 {"term_getattr", 2, 2, FEARG_1, ret_number, f_term_getattr},
864 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, f_term_getcursor},
865 {"term_getjob", 1, 1, FEARG_1, ret_job, f_term_getjob},
866 {"term_getline", 2, 2, FEARG_1, ret_string, f_term_getline},
867 {"term_getscrolled", 1, 1, FEARG_1, ret_number, f_term_getscrolled},
868 {"term_getsize", 1, 1, FEARG_1, ret_list_number, f_term_getsize},
869 {"term_getstatus", 1, 1, FEARG_1, ret_string, f_term_getstatus},
870 {"term_gettitle", 1, 1, FEARG_1, ret_string, f_term_gettitle},
871 {"term_gettty", 1, 2, FEARG_1, ret_string, f_term_gettty},
872 {"term_list", 0, 0, 0, ret_list_number, f_term_list},
873 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, f_term_scrape},
874 {"term_sendkeys", 2, 2, FEARG_1, ret_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200875# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100876 {"term_setansicolors", 2, 2, FEARG_1, ret_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200877# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100878 {"term_setapi", 2, 2, FEARG_1, ret_void, f_term_setapi},
879 {"term_setkill", 2, 2, FEARG_1, ret_void, f_term_setkill},
880 {"term_setrestore", 2, 2, FEARG_1, ret_void, f_term_setrestore},
881 {"term_setsize", 3, 3, FEARG_1, ret_void, f_term_setsize},
882 {"term_start", 1, 2, FEARG_1, ret_number, f_term_start},
883 {"term_wait", 1, 2, FEARG_1, ret_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200884#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100885 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
886 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
887 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
888 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
889 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
890 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
891 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
892 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200893#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100894 {"test_null_channel", 0, 0, 0, ret_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200895#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100896 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200897#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100898 {"test_null_job", 0, 0, 0, ret_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200899#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100900 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
901 {"test_null_partial", 0, 0, 0, ret_partial_void, f_test_null_partial},
902 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
903 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
904 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
905 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200906#ifdef FEAT_GUI
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100907 {"test_scrollbar", 3, 3, FEARG_2, ret_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200908#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100909 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
910 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
911 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
912 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
913 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200914#ifdef FEAT_TIMERS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100915 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, f_timer_info},
916 {"timer_pause", 2, 2, FEARG_1, ret_void, f_timer_pause},
917 {"timer_start", 2, 3, FEARG_1, ret_number, f_timer_start},
918 {"timer_stop", 1, 1, FEARG_1, ret_void, f_timer_stop},
919 {"timer_stopall", 0, 0, 0, ret_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100921 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
922 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
923 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
924 {"trim", 1, 2, FEARG_1, ret_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100926 {"trunc", 1, 1, FEARG_1, ret_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200927#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100928 {"type", 1, 1, FEARG_1, ret_number, f_type},
929 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
930 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
931 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
932 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
933 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
934 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
935 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
936 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
937 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
938 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
939 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
940 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
941 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
942 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
943 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
944 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
945 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
946 {"wincol", 0, 0, 0, ret_number, f_wincol},
947 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
948 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
949 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
950 {"winline", 0, 0, 0, ret_number, f_winline},
951 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
952 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
953 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
954 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
955 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
956 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
957 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
958 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200959};
960
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200961/*
962 * Function given to ExpandGeneric() to obtain the list of internal
963 * or user defined function names.
964 */
965 char_u *
966get_function_name(expand_T *xp, int idx)
967{
968 static int intidx = -1;
969 char_u *name;
970
971 if (idx == 0)
972 intidx = -1;
973 if (intidx < 0)
974 {
975 name = get_user_func_name(xp, idx);
976 if (name != NULL)
977 return name;
978 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200979 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200980 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200981 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200982 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200983 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200984 STRCAT(IObuff, ")");
985 return IObuff;
986 }
987
988 return NULL;
989}
990
991/*
992 * Function given to ExpandGeneric() to obtain the list of internal or
993 * user defined variable or function names.
994 */
995 char_u *
996get_expr_name(expand_T *xp, int idx)
997{
998 static int intidx = -1;
999 char_u *name;
1000
1001 if (idx == 0)
1002 intidx = -1;
1003 if (intidx < 0)
1004 {
1005 name = get_function_name(xp, idx);
1006 if (name != NULL)
1007 return name;
1008 }
1009 return get_user_var_name(xp, ++intidx);
1010}
1011
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001013 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014 * Return index, or -1 if not found
1015 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001016 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001017find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001018{
1019 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001020 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001021 int cmp;
1022 int x;
1023
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001024 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001025
1026 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001027 while (first <= last)
1028 {
1029 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001030 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001031 if (cmp < 0)
1032 last = x - 1;
1033 else if (cmp > 0)
1034 first = x + 1;
1035 else
1036 return x;
1037 }
1038 return -1;
1039}
1040
1041 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042has_internal_func(char_u *name)
1043{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001044 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001045}
1046
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001047 char *
1048internal_func_name(int idx)
1049{
1050 return global_functions[idx].f_name;
1051}
1052
1053 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001054internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001055{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001056 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001057}
1058
1059/*
1060 * Check the argument count to use for internal function "idx".
1061 * Returns OK or FAIL;
1062 */
1063 int
1064check_internal_func(int idx, int argcount)
1065{
1066 int res;
1067 char *name;
1068
1069 if (argcount < global_functions[idx].f_min_argc)
1070 res = FCERR_TOOFEW;
1071 else if (argcount > global_functions[idx].f_max_argc)
1072 res = FCERR_TOOMANY;
1073 else
1074 return OK;
1075
1076 name = internal_func_name(idx);
1077 if (res == FCERR_TOOMANY)
1078 semsg(_(e_toomanyarg), name);
1079 else
1080 semsg(_(e_toofewarg), name);
1081 return FAIL;
1082}
1083
Bram Moolenaarac92e252019-08-03 21:58:38 +02001084 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001085call_internal_func(
1086 char_u *name,
1087 int argcount,
1088 typval_T *argvars,
1089 typval_T *rettv)
1090{
1091 int i;
1092
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001093 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001094 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001095 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001096 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001097 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001098 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001099 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001100 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001101 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001102 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001103}
1104
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001105 void
1106call_internal_func_by_idx(
1107 int idx,
1108 typval_T *argvars,
1109 typval_T *rettv)
1110{
1111 global_functions[idx].f_func(argvars, rettv);
1112}
1113
Bram Moolenaarac92e252019-08-03 21:58:38 +02001114/*
1115 * Invoke a method for base->method().
1116 */
1117 int
1118call_internal_method(
1119 char_u *name,
1120 int argcount,
1121 typval_T *argvars,
1122 typval_T *rettv,
1123 typval_T *basetv)
1124{
1125 int i;
1126 int fi;
1127 typval_T argv[MAX_FUNC_ARGS + 1];
1128
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001129 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001130 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001131 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001132 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001133 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001134 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001135 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001136 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001137 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001138
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001139 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001140 {
1141 // base value goes last
1142 for (i = 0; i < argcount; ++i)
1143 argv[i] = argvars[i];
1144 argv[argcount] = *basetv;
1145 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001146 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001147 {
1148 // base value goes second
1149 argv[0] = argvars[0];
1150 argv[1] = *basetv;
1151 for (i = 1; i < argcount; ++i)
1152 argv[i + 1] = argvars[i];
1153 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001154 else if (global_functions[fi].f_argtype == FEARG_3)
1155 {
1156 // base value goes third
1157 argv[0] = argvars[0];
1158 argv[1] = argvars[1];
1159 argv[2] = *basetv;
1160 for (i = 2; i < argcount; ++i)
1161 argv[i + 1] = argvars[i];
1162 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001163 else if (global_functions[fi].f_argtype == FEARG_4)
1164 {
1165 // base value goes fourth
1166 argv[0] = argvars[0];
1167 argv[1] = argvars[1];
1168 argv[2] = argvars[2];
1169 argv[3] = *basetv;
1170 for (i = 3; i < argcount; ++i)
1171 argv[i + 1] = argvars[i];
1172 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001173 else
1174 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001175 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001176 argv[0] = *basetv;
1177 for (i = 0; i < argcount; ++i)
1178 argv[i + 1] = argvars[i];
1179 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001180 argv[argcount + 1].v_type = VAR_UNKNOWN;
1181
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001182 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001183 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001184}
1185
1186/*
1187 * Return TRUE for a non-zero Number and a non-empty String.
1188 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001189 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001190non_zero_arg(typval_T *argvars)
1191{
1192 return ((argvars[0].v_type == VAR_NUMBER
1193 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001194 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001195 && argvars[0].vval.v_number == VVAL_TRUE)
1196 || (argvars[0].v_type == VAR_STRING
1197 && argvars[0].vval.v_string != NULL
1198 && *argvars[0].vval.v_string != NUL));
1199}
1200
1201/*
1202 * Get the lnum from the first argument.
1203 * Also accepts ".", "$", etc., but that only works for the current buffer.
1204 * Returns -1 on error.
1205 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001206 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001207tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001208{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001209 linenr_T lnum;
1210
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001211 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001212 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001213 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001214 int fnum;
1215 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1216
1217 if (fp != NULL)
1218 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001219 }
1220 return lnum;
1221}
1222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001223/*
1224 * Get the lnum from the first argument.
1225 * Also accepts "$", then "buf" is used.
1226 * Returns 0 on error.
1227 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001228 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001229tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1230{
1231 if (argvars[0].v_type == VAR_STRING
1232 && argvars[0].vval.v_string != NULL
1233 && argvars[0].vval.v_string[0] == '$'
1234 && buf != NULL)
1235 return buf->b_ml.ml_line_count;
1236 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1237}
1238
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001239#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001240/*
1241 * Get the float value of "argvars[0]" into "f".
1242 * Returns FAIL when the argument is not a Number or Float.
1243 */
1244 static int
1245get_float_arg(typval_T *argvars, float_T *f)
1246{
1247 if (argvars[0].v_type == VAR_FLOAT)
1248 {
1249 *f = argvars[0].vval.v_float;
1250 return OK;
1251 }
1252 if (argvars[0].v_type == VAR_NUMBER)
1253 {
1254 *f = (float_T)argvars[0].vval.v_number;
1255 return OK;
1256 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001257 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001258 return FAIL;
1259}
1260
1261/*
1262 * "abs(expr)" function
1263 */
1264 static void
1265f_abs(typval_T *argvars, typval_T *rettv)
1266{
1267 if (argvars[0].v_type == VAR_FLOAT)
1268 {
1269 rettv->v_type = VAR_FLOAT;
1270 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1271 }
1272 else
1273 {
1274 varnumber_T n;
1275 int error = FALSE;
1276
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001277 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001278 if (error)
1279 rettv->vval.v_number = -1;
1280 else if (n > 0)
1281 rettv->vval.v_number = n;
1282 else
1283 rettv->vval.v_number = -n;
1284 }
1285}
1286
1287/*
1288 * "acos()" function
1289 */
1290 static void
1291f_acos(typval_T *argvars, typval_T *rettv)
1292{
1293 float_T f = 0.0;
1294
1295 rettv->v_type = VAR_FLOAT;
1296 if (get_float_arg(argvars, &f) == OK)
1297 rettv->vval.v_float = acos(f);
1298 else
1299 rettv->vval.v_float = 0.0;
1300}
1301#endif
1302
1303/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001304 * "and(expr, expr)" function
1305 */
1306 static void
1307f_and(typval_T *argvars, typval_T *rettv)
1308{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001309 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1310 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001311}
1312
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001313#ifdef FEAT_FLOAT
1314/*
1315 * "asin()" function
1316 */
1317 static void
1318f_asin(typval_T *argvars, typval_T *rettv)
1319{
1320 float_T f = 0.0;
1321
1322 rettv->v_type = VAR_FLOAT;
1323 if (get_float_arg(argvars, &f) == OK)
1324 rettv->vval.v_float = asin(f);
1325 else
1326 rettv->vval.v_float = 0.0;
1327}
1328
1329/*
1330 * "atan()" function
1331 */
1332 static void
1333f_atan(typval_T *argvars, typval_T *rettv)
1334{
1335 float_T f = 0.0;
1336
1337 rettv->v_type = VAR_FLOAT;
1338 if (get_float_arg(argvars, &f) == OK)
1339 rettv->vval.v_float = atan(f);
1340 else
1341 rettv->vval.v_float = 0.0;
1342}
1343
1344/*
1345 * "atan2()" function
1346 */
1347 static void
1348f_atan2(typval_T *argvars, typval_T *rettv)
1349{
1350 float_T fx = 0.0, fy = 0.0;
1351
1352 rettv->v_type = VAR_FLOAT;
1353 if (get_float_arg(argvars, &fx) == OK
1354 && get_float_arg(&argvars[1], &fy) == OK)
1355 rettv->vval.v_float = atan2(fx, fy);
1356 else
1357 rettv->vval.v_float = 0.0;
1358}
1359#endif
1360
1361/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001362 * "balloon_show()" function
1363 */
1364#ifdef FEAT_BEVAL
1365 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001366f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1367{
1368 rettv->v_type = VAR_STRING;
1369 if (balloonEval != NULL)
1370 {
1371 if (balloonEval->msg == NULL)
1372 rettv->vval.v_string = NULL;
1373 else
1374 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1375 }
1376}
1377
1378 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001379f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1380{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001381 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001382 {
1383 if (argvars[0].v_type == VAR_LIST
1384# ifdef FEAT_GUI
1385 && !gui.in_use
1386# endif
1387 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001388 {
1389 list_T *l = argvars[0].vval.v_list;
1390
1391 // empty list removes the balloon
1392 post_balloon(balloonEval, NULL,
1393 l == NULL || l->lv_len == 0 ? NULL : l);
1394 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001395 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001396 {
1397 char_u *mesg = tv_get_string_chk(&argvars[0]);
1398
1399 if (mesg != NULL)
1400 // empty string removes the balloon
1401 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1402 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001403 }
1404}
1405
Bram Moolenaar669a8282017-11-19 20:13:05 +01001406# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001407 static void
1408f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1409{
1410 if (rettv_list_alloc(rettv) == OK)
1411 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001412 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001413
1414 if (msg != NULL)
1415 {
1416 pumitem_T *array;
1417 int size = split_message(msg, &array);
1418 int i;
1419
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001420 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001421 for (i = 1; i < size - 1; ++i)
1422 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001423 while (size > 0)
1424 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001425 vim_free(array);
1426 }
1427 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001428}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001429# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001430#endif
1431
1432/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001433 * Get buffer by number or pattern.
1434 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001435 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001436tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001437{
1438 char_u *name = tv->vval.v_string;
1439 buf_T *buf;
1440
1441 if (tv->v_type == VAR_NUMBER)
1442 return buflist_findnr((int)tv->vval.v_number);
1443 if (tv->v_type != VAR_STRING)
1444 return NULL;
1445 if (name == NULL || *name == NUL)
1446 return curbuf;
1447 if (name[0] == '$' && name[1] == NUL)
1448 return lastbuf;
1449
1450 buf = buflist_find_by_name(name, curtab_only);
1451
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001452 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001453 if (buf == NULL)
1454 buf = find_buffer(tv);
1455
1456 return buf;
1457}
1458
1459/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001460 * Get the buffer from "arg" and give an error and return NULL if it is not
1461 * valid.
1462 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001463 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001464get_buf_arg(typval_T *arg)
1465{
1466 buf_T *buf;
1467
1468 ++emsg_off;
1469 buf = tv_get_buf(arg, FALSE);
1470 --emsg_off;
1471 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001472 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001473 return buf;
1474}
1475
1476/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001477 * "byte2line(byte)" function
1478 */
1479 static void
1480f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1481{
1482#ifndef FEAT_BYTEOFF
1483 rettv->vval.v_number = -1;
1484#else
1485 long boff = 0;
1486
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001487 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488 if (boff < 0)
1489 rettv->vval.v_number = -1;
1490 else
1491 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1492 (linenr_T)0, &boff);
1493#endif
1494}
1495
1496 static void
1497byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1498{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001499 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001500 char_u *str;
1501 varnumber_T idx;
1502
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001503 str = tv_get_string_chk(&argvars[0]);
1504 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001505 rettv->vval.v_number = -1;
1506 if (str == NULL || idx < 0)
1507 return;
1508
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001509 t = str;
1510 for ( ; idx > 0; idx--)
1511 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001512 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001513 return;
1514 if (enc_utf8 && comp)
1515 t += utf_ptr2len(t);
1516 else
1517 t += (*mb_ptr2len)(t);
1518 }
1519 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001520}
1521
1522/*
1523 * "byteidx()" function
1524 */
1525 static void
1526f_byteidx(typval_T *argvars, typval_T *rettv)
1527{
1528 byteidx(argvars, rettv, FALSE);
1529}
1530
1531/*
1532 * "byteidxcomp()" function
1533 */
1534 static void
1535f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1536{
1537 byteidx(argvars, rettv, TRUE);
1538}
1539
1540/*
1541 * "call(func, arglist [, dict])" function
1542 */
1543 static void
1544f_call(typval_T *argvars, typval_T *rettv)
1545{
1546 char_u *func;
1547 partial_T *partial = NULL;
1548 dict_T *selfdict = NULL;
1549
1550 if (argvars[1].v_type != VAR_LIST)
1551 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001552 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001553 return;
1554 }
1555 if (argvars[1].vval.v_list == NULL)
1556 return;
1557
1558 if (argvars[0].v_type == VAR_FUNC)
1559 func = argvars[0].vval.v_string;
1560 else if (argvars[0].v_type == VAR_PARTIAL)
1561 {
1562 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001563 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001564 }
1565 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001566 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001568 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001569
1570 if (argvars[2].v_type != VAR_UNKNOWN)
1571 {
1572 if (argvars[2].v_type != VAR_DICT)
1573 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001574 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575 return;
1576 }
1577 selfdict = argvars[2].vval.v_dict;
1578 }
1579
1580 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1581}
1582
1583#ifdef FEAT_FLOAT
1584/*
1585 * "ceil({float})" function
1586 */
1587 static void
1588f_ceil(typval_T *argvars, typval_T *rettv)
1589{
1590 float_T f = 0.0;
1591
1592 rettv->v_type = VAR_FLOAT;
1593 if (get_float_arg(argvars, &f) == OK)
1594 rettv->vval.v_float = ceil(f);
1595 else
1596 rettv->vval.v_float = 0.0;
1597}
1598#endif
1599
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001600/*
1601 * "changenr()" function
1602 */
1603 static void
1604f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1605{
1606 rettv->vval.v_number = curbuf->b_u_seq_cur;
1607}
1608
1609/*
1610 * "char2nr(string)" function
1611 */
1612 static void
1613f_char2nr(typval_T *argvars, typval_T *rettv)
1614{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001615 if (has_mbyte)
1616 {
1617 int utf8 = 0;
1618
1619 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001620 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001621
1622 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001623 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001625 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001626 }
1627 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001628 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001629}
1630
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001631 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001632get_optional_window(typval_T *argvars, int idx)
1633{
1634 win_T *win = curwin;
1635
1636 if (argvars[idx].v_type != VAR_UNKNOWN)
1637 {
1638 win = find_win_by_nr_or_id(&argvars[idx]);
1639 if (win == NULL)
1640 {
1641 emsg(_(e_invalwindow));
1642 return NULL;
1643 }
1644 }
1645 return win;
1646}
1647
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649 * "col(string)" function
1650 */
1651 static void
1652f_col(typval_T *argvars, typval_T *rettv)
1653{
1654 colnr_T col = 0;
1655 pos_T *fp;
1656 int fnum = curbuf->b_fnum;
1657
1658 fp = var2fpos(&argvars[0], FALSE, &fnum);
1659 if (fp != NULL && fnum == curbuf->b_fnum)
1660 {
1661 if (fp->col == MAXCOL)
1662 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001663 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001664 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1665 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1666 else
1667 col = MAXCOL;
1668 }
1669 else
1670 {
1671 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001672 // col(".") when the cursor is on the NUL at the end of the line
1673 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001674 if (virtual_active() && fp == &curwin->w_cursor)
1675 {
1676 char_u *p = ml_get_cursor();
1677
1678 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1679 curwin->w_virtcol - curwin->w_cursor.coladd))
1680 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 int l;
1682
1683 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1684 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 }
1686 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 }
1688 }
1689 rettv->vval.v_number = col;
1690}
1691
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692/*
1693 * "confirm(message, buttons[, default [, type]])" function
1694 */
1695 static void
1696f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1697{
1698#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1699 char_u *message;
1700 char_u *buttons = NULL;
1701 char_u buf[NUMBUFLEN];
1702 char_u buf2[NUMBUFLEN];
1703 int def = 1;
1704 int type = VIM_GENERIC;
1705 char_u *typestr;
1706 int error = FALSE;
1707
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001708 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001709 if (message == NULL)
1710 error = TRUE;
1711 if (argvars[1].v_type != VAR_UNKNOWN)
1712 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001713 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 if (buttons == NULL)
1715 error = TRUE;
1716 if (argvars[2].v_type != VAR_UNKNOWN)
1717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001718 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001719 if (argvars[3].v_type != VAR_UNKNOWN)
1720 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001721 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722 if (typestr == NULL)
1723 error = TRUE;
1724 else
1725 {
1726 switch (TOUPPER_ASC(*typestr))
1727 {
1728 case 'E': type = VIM_ERROR; break;
1729 case 'Q': type = VIM_QUESTION; break;
1730 case 'I': type = VIM_INFO; break;
1731 case 'W': type = VIM_WARNING; break;
1732 case 'G': type = VIM_GENERIC; break;
1733 }
1734 }
1735 }
1736 }
1737 }
1738
1739 if (buttons == NULL || *buttons == NUL)
1740 buttons = (char_u *)_("&Ok");
1741
1742 if (!error)
1743 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1744 def, NULL, FALSE);
1745#endif
1746}
1747
1748/*
1749 * "copy()" function
1750 */
1751 static void
1752f_copy(typval_T *argvars, typval_T *rettv)
1753{
1754 item_copy(&argvars[0], rettv, FALSE, 0);
1755}
1756
1757#ifdef FEAT_FLOAT
1758/*
1759 * "cos()" function
1760 */
1761 static void
1762f_cos(typval_T *argvars, typval_T *rettv)
1763{
1764 float_T f = 0.0;
1765
1766 rettv->v_type = VAR_FLOAT;
1767 if (get_float_arg(argvars, &f) == OK)
1768 rettv->vval.v_float = cos(f);
1769 else
1770 rettv->vval.v_float = 0.0;
1771}
1772
1773/*
1774 * "cosh()" function
1775 */
1776 static void
1777f_cosh(typval_T *argvars, typval_T *rettv)
1778{
1779 float_T f = 0.0;
1780
1781 rettv->v_type = VAR_FLOAT;
1782 if (get_float_arg(argvars, &f) == OK)
1783 rettv->vval.v_float = cosh(f);
1784 else
1785 rettv->vval.v_float = 0.0;
1786}
1787#endif
1788
1789/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790 * "cursor(lnum, col)" function, or
1791 * "cursor(list)"
1792 *
1793 * Moves the cursor to the specified line and column.
1794 * Returns 0 when the position could be set, -1 otherwise.
1795 */
1796 static void
1797f_cursor(typval_T *argvars, typval_T *rettv)
1798{
1799 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001800 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001801 int set_curswant = TRUE;
1802
1803 rettv->vval.v_number = -1;
1804 if (argvars[1].v_type == VAR_UNKNOWN)
1805 {
1806 pos_T pos;
1807 colnr_T curswant = -1;
1808
1809 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1810 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001811 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001812 return;
1813 }
1814 line = pos.lnum;
1815 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001816 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001817 if (curswant >= 0)
1818 {
1819 curwin->w_curswant = curswant - 1;
1820 set_curswant = FALSE;
1821 }
1822 }
1823 else
1824 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001825 line = tv_get_lnum(argvars);
1826 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001827 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001828 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001829 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001830 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001831 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 if (line > 0)
1833 curwin->w_cursor.lnum = line;
1834 if (col > 0)
1835 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001836 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001837
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001838 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001840 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001841 if (has_mbyte)
1842 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001843
1844 curwin->w_set_curswant = set_curswant;
1845 rettv->vval.v_number = 0;
1846}
1847
Bram Moolenaar4f974752019-02-17 17:44:42 +01001848#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001849/*
1850 * "debugbreak()" function
1851 */
1852 static void
1853f_debugbreak(typval_T *argvars, typval_T *rettv)
1854{
1855 int pid;
1856
1857 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001858 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001859 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001860 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001861 else
1862 {
1863 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1864
1865 if (hProcess != NULL)
1866 {
1867 DebugBreakProcess(hProcess);
1868 CloseHandle(hProcess);
1869 rettv->vval.v_number = OK;
1870 }
1871 }
1872}
1873#endif
1874
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001875/*
1876 * "deepcopy()" function
1877 */
1878 static void
1879f_deepcopy(typval_T *argvars, typval_T *rettv)
1880{
1881 int noref = 0;
1882 int copyID;
1883
1884 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001885 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001886 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001887 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001888 else
1889 {
1890 copyID = get_copyID();
1891 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1892 }
1893}
1894
1895/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001896 * "did_filetype()" function
1897 */
1898 static void
1899f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1900{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001901 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902}
1903
1904/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001905 * "echoraw({expr})" function
1906 */
1907 static void
1908f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1909{
1910 char_u *str = tv_get_string_chk(&argvars[0]);
1911
1912 if (str != NULL && *str != NUL)
1913 {
1914 out_str(str);
1915 out_flush();
1916 }
1917}
1918
1919/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001920 * "empty({expr})" function
1921 */
1922 static void
1923f_empty(typval_T *argvars, typval_T *rettv)
1924{
1925 int n = FALSE;
1926
1927 switch (argvars[0].v_type)
1928 {
1929 case VAR_STRING:
1930 case VAR_FUNC:
1931 n = argvars[0].vval.v_string == NULL
1932 || *argvars[0].vval.v_string == NUL;
1933 break;
1934 case VAR_PARTIAL:
1935 n = FALSE;
1936 break;
1937 case VAR_NUMBER:
1938 n = argvars[0].vval.v_number == 0;
1939 break;
1940 case VAR_FLOAT:
1941#ifdef FEAT_FLOAT
1942 n = argvars[0].vval.v_float == 0.0;
1943 break;
1944#endif
1945 case VAR_LIST:
1946 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001947 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001948 break;
1949 case VAR_DICT:
1950 n = argvars[0].vval.v_dict == NULL
1951 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1952 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001953 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001954 case VAR_SPECIAL:
1955 n = argvars[0].vval.v_number != VVAL_TRUE;
1956 break;
1957
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001958 case VAR_BLOB:
1959 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001960 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1961 break;
1962
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001963 case VAR_JOB:
1964#ifdef FEAT_JOB_CHANNEL
1965 n = argvars[0].vval.v_job == NULL
1966 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1967 break;
1968#endif
1969 case VAR_CHANNEL:
1970#ifdef FEAT_JOB_CHANNEL
1971 n = argvars[0].vval.v_channel == NULL
1972 || !channel_is_open(argvars[0].vval.v_channel);
1973 break;
1974#endif
1975 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001976 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001977 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978 n = TRUE;
1979 break;
1980 }
1981
1982 rettv->vval.v_number = n;
1983}
1984
1985/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001986 * "environ()" function
1987 */
1988 static void
1989f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1990{
1991#if !defined(AMIGA)
1992 int i = 0;
1993 char_u *entry, *value;
1994# ifdef MSWIN
1995 extern wchar_t **_wenviron;
1996# else
1997 extern char **environ;
1998# endif
1999
2000 if (rettv_dict_alloc(rettv) != OK)
2001 return;
2002
2003# ifdef MSWIN
2004 if (*_wenviron == NULL)
2005 return;
2006# else
2007 if (*environ == NULL)
2008 return;
2009# endif
2010
2011 for (i = 0; ; ++i)
2012 {
2013# ifdef MSWIN
2014 short_u *p;
2015
2016 if ((p = (short_u *)_wenviron[i]) == NULL)
2017 return;
2018 entry = utf16_to_enc(p, NULL);
2019# else
2020 if ((entry = (char_u *)environ[i]) == NULL)
2021 return;
2022 entry = vim_strsave(entry);
2023# endif
2024 if (entry == NULL) // out of memory
2025 return;
2026 if ((value = vim_strchr(entry, '=')) == NULL)
2027 {
2028 vim_free(entry);
2029 continue;
2030 }
2031 *value++ = NUL;
2032 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2033 vim_free(entry);
2034 }
2035#endif
2036}
2037
2038/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039 * "escape({string}, {chars})" function
2040 */
2041 static void
2042f_escape(typval_T *argvars, typval_T *rettv)
2043{
2044 char_u buf[NUMBUFLEN];
2045
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002046 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2047 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002048 rettv->v_type = VAR_STRING;
2049}
2050
2051/*
2052 * "eval()" function
2053 */
2054 static void
2055f_eval(typval_T *argvars, typval_T *rettv)
2056{
2057 char_u *s, *p;
2058
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002059 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002060 if (s != NULL)
2061 s = skipwhite(s);
2062
2063 p = s;
2064 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2065 {
2066 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002067 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002068 need_clr_eos = FALSE;
2069 rettv->v_type = VAR_NUMBER;
2070 rettv->vval.v_number = 0;
2071 }
2072 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002073 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002074}
2075
2076/*
2077 * "eventhandler()" function
2078 */
2079 static void
2080f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2081{
2082 rettv->vval.v_number = vgetc_busy;
2083}
2084
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002085static garray_T redir_execute_ga;
2086
2087/*
2088 * Append "value[value_len]" to the execute() output.
2089 */
2090 void
2091execute_redir_str(char_u *value, int value_len)
2092{
2093 int len;
2094
2095 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002096 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002098 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002099 if (ga_grow(&redir_execute_ga, len) == OK)
2100 {
2101 mch_memmove((char *)redir_execute_ga.ga_data
2102 + redir_execute_ga.ga_len, value, len);
2103 redir_execute_ga.ga_len += len;
2104 }
2105}
2106
2107/*
2108 * Get next line from a list.
2109 * Called by do_cmdline() to get the next line.
2110 * Returns allocated string, or NULL for end of function.
2111 */
2112
2113 static char_u *
2114get_list_line(
2115 int c UNUSED,
2116 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002117 int indent UNUSED,
2118 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002119{
2120 listitem_T **p = (listitem_T **)cookie;
2121 listitem_T *item = *p;
2122 char_u buf[NUMBUFLEN];
2123 char_u *s;
2124
2125 if (item == NULL)
2126 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002127 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002128 *p = item->li_next;
2129 return s == NULL ? NULL : vim_strsave(s);
2130}
2131
2132/*
2133 * "execute()" function
2134 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002135 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002136execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002137{
2138 char_u *cmd = NULL;
2139 list_T *list = NULL;
2140 int save_msg_silent = msg_silent;
2141 int save_emsg_silent = emsg_silent;
2142 int save_emsg_noredir = emsg_noredir;
2143 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002144 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002145 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002146 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002147 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002148
2149 rettv->vval.v_string = NULL;
2150 rettv->v_type = VAR_STRING;
2151
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002152 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002154 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002155 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002156 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002157 return;
2158 ++list->lv_refcount;
2159 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002160 else if (argvars[arg_off].v_type == VAR_JOB
2161 || argvars[arg_off].v_type == VAR_CHANNEL)
2162 {
2163 emsg(_(e_inval_string));
2164 return;
2165 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 else
2167 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002168 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 if (cmd == NULL)
2170 return;
2171 }
2172
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002173 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002174 {
2175 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002176 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177
2178 if (s == NULL)
2179 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002180 if (*s == NUL)
2181 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182 if (STRNCMP(s, "silent", 6) == 0)
2183 ++msg_silent;
2184 if (STRCMP(s, "silent!") == 0)
2185 {
2186 emsg_silent = TRUE;
2187 emsg_noredir = TRUE;
2188 }
2189 }
2190 else
2191 ++msg_silent;
2192
2193 if (redir_execute)
2194 save_ga = redir_execute_ga;
2195 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2196 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002197 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002198 if (!echo_output)
2199 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002200
2201 if (cmd != NULL)
2202 do_cmdline_cmd(cmd);
2203 else
2204 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002205 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002206
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002207 range_list_materialize(list);
2208 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002209 do_cmdline(NULL, get_list_line, (void *)&item,
2210 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2211 --list->lv_refcount;
2212 }
2213
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002214 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002215 if (ga_grow(&redir_execute_ga, 1) == OK)
2216 {
2217 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2218 rettv->vval.v_string = redir_execute_ga.ga_data;
2219 }
2220 else
2221 {
2222 ga_clear(&redir_execute_ga);
2223 rettv->vval.v_string = NULL;
2224 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002225 msg_silent = save_msg_silent;
2226 emsg_silent = save_emsg_silent;
2227 emsg_noredir = save_emsg_noredir;
2228
2229 redir_execute = save_redir_execute;
2230 if (redir_execute)
2231 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002232 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002233
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002234 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002235 if (echo_output)
2236 // When not working silently: put it in column zero. A following
2237 // "echon" will overwrite the message, unavoidably.
2238 msg_col = 0;
2239 else
2240 // When working silently: Put it back where it was, since nothing
2241 // should have been written.
2242 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002243}
2244
2245/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002246 * "execute()" function
2247 */
2248 static void
2249f_execute(typval_T *argvars, typval_T *rettv)
2250{
2251 execute_common(argvars, rettv, 0);
2252}
2253
2254/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002255 * "exists()" function
2256 */
2257 static void
2258f_exists(typval_T *argvars, typval_T *rettv)
2259{
2260 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002261 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002262
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002263 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002264 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002265 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002266 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002267 if (mch_getenv(p + 1) != NULL)
2268 n = TRUE;
2269 else
2270 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002271 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002272 p = expand_env_save(p);
2273 if (p != NULL && *p != '$')
2274 n = TRUE;
2275 vim_free(p);
2276 }
2277 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002278 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002279 {
2280 n = (get_option_tv(&p, NULL, TRUE) == OK);
2281 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002282 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002283 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002284 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002285 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002286 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002287 }
2288 else if (*p == ':')
2289 {
2290 n = cmd_exists(p + 1);
2291 }
2292 else if (*p == '#')
2293 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002294 if (p[1] == '#')
2295 n = autocmd_supported(p + 2);
2296 else
2297 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002298 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002299 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002300 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002301 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002302 }
2303
2304 rettv->vval.v_number = n;
2305}
2306
2307#ifdef FEAT_FLOAT
2308/*
2309 * "exp()" function
2310 */
2311 static void
2312f_exp(typval_T *argvars, typval_T *rettv)
2313{
2314 float_T f = 0.0;
2315
2316 rettv->v_type = VAR_FLOAT;
2317 if (get_float_arg(argvars, &f) == OK)
2318 rettv->vval.v_float = exp(f);
2319 else
2320 rettv->vval.v_float = 0.0;
2321}
2322#endif
2323
2324/*
2325 * "expand()" function
2326 */
2327 static void
2328f_expand(typval_T *argvars, typval_T *rettv)
2329{
2330 char_u *s;
2331 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002332 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002333 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2334 expand_T xpc;
2335 int error = FALSE;
2336 char_u *result;
2337
2338 rettv->v_type = VAR_STRING;
2339 if (argvars[1].v_type != VAR_UNKNOWN
2340 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002341 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002342 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002343 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002344
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002345 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002346 if (*s == '%' || *s == '#' || *s == '<')
2347 {
2348 ++emsg_off;
2349 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2350 --emsg_off;
2351 if (rettv->v_type == VAR_LIST)
2352 {
2353 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2354 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002355 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356 }
2357 else
2358 rettv->vval.v_string = result;
2359 }
2360 else
2361 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002362 // When the optional second argument is non-zero, don't remove matches
2363 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002365 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002366 options |= WILD_KEEP_ALL;
2367 if (!error)
2368 {
2369 ExpandInit(&xpc);
2370 xpc.xp_context = EXPAND_FILES;
2371 if (p_wic)
2372 options += WILD_ICASE;
2373 if (rettv->v_type == VAR_STRING)
2374 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2375 options, WILD_ALL);
2376 else if (rettv_list_alloc(rettv) != FAIL)
2377 {
2378 int i;
2379
2380 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2381 for (i = 0; i < xpc.xp_numfiles; i++)
2382 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2383 ExpandCleanup(&xpc);
2384 }
2385 }
2386 else
2387 rettv->vval.v_string = NULL;
2388 }
2389}
2390
2391/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002392 * "expandcmd()" function
2393 * Expand all the special characters in a command string.
2394 */
2395 static void
2396f_expandcmd(typval_T *argvars, typval_T *rettv)
2397{
2398 exarg_T eap;
2399 char_u *cmdstr;
2400 char *errormsg = NULL;
2401
2402 rettv->v_type = VAR_STRING;
2403 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2404
2405 memset(&eap, 0, sizeof(eap));
2406 eap.cmd = cmdstr;
2407 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002408 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002409 eap.usefilter = FALSE;
2410 eap.nextcmd = NULL;
2411 eap.cmdidx = CMD_USER;
2412
2413 expand_filename(&eap, &cmdstr, &errormsg);
2414 if (errormsg != NULL && *errormsg != NUL)
2415 emsg(errormsg);
2416
2417 rettv->vval.v_string = cmdstr;
2418}
2419
2420/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002421 * "feedkeys()" function
2422 */
2423 static void
2424f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2425{
2426 int remap = TRUE;
2427 int insert = FALSE;
2428 char_u *keys, *flags;
2429 char_u nbuf[NUMBUFLEN];
2430 int typed = FALSE;
2431 int execute = FALSE;
2432 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002433 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 char_u *keys_esc;
2435
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002436 // This is not allowed in the sandbox. If the commands would still be
2437 // executed in the sandbox it would be OK, but it probably happens later,
2438 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002439 if (check_secure())
2440 return;
2441
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002442 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002443
2444 if (argvars[1].v_type != VAR_UNKNOWN)
2445 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002446 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447 for ( ; *flags != NUL; ++flags)
2448 {
2449 switch (*flags)
2450 {
2451 case 'n': remap = FALSE; break;
2452 case 'm': remap = TRUE; break;
2453 case 't': typed = TRUE; break;
2454 case 'i': insert = TRUE; break;
2455 case 'x': execute = TRUE; break;
2456 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002457 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002458 }
2459 }
2460 }
2461
2462 if (*keys != NUL || execute)
2463 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002464 // Need to escape K_SPECIAL and CSI before putting the string in the
2465 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002466 keys_esc = vim_strsave_escape_csi(keys);
2467 if (keys_esc != NULL)
2468 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002469 if (lowlevel)
2470 {
2471#ifdef USE_INPUT_BUF
2472 add_to_input_buf(keys, (int)STRLEN(keys));
2473#else
2474 emsg(_("E980: lowlevel input not supported"));
2475#endif
2476 }
2477 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002478 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002479 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002480 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002481 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002482#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002483 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002484#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002485 )
2486 typebuf_was_filled = TRUE;
2487 }
2488 vim_free(keys_esc);
2489
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002490 if (execute)
2491 {
2492 int save_msg_scroll = msg_scroll;
2493
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002494 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002495 msg_scroll = FALSE;
2496
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002497 if (!dangerous)
2498 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002499 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002500 if (!dangerous)
2501 --ex_normal_busy;
2502
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002503 msg_scroll |= save_msg_scroll;
2504 }
2505 }
2506 }
2507}
2508
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002509#ifdef FEAT_FLOAT
2510/*
2511 * "float2nr({float})" function
2512 */
2513 static void
2514f_float2nr(typval_T *argvars, typval_T *rettv)
2515{
2516 float_T f = 0.0;
2517
2518 if (get_float_arg(argvars, &f) == OK)
2519 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002520 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002521 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002522 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002523 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002524 else
2525 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 }
2527}
2528
2529/*
2530 * "floor({float})" function
2531 */
2532 static void
2533f_floor(typval_T *argvars, typval_T *rettv)
2534{
2535 float_T f = 0.0;
2536
2537 rettv->v_type = VAR_FLOAT;
2538 if (get_float_arg(argvars, &f) == OK)
2539 rettv->vval.v_float = floor(f);
2540 else
2541 rettv->vval.v_float = 0.0;
2542}
2543
2544/*
2545 * "fmod()" function
2546 */
2547 static void
2548f_fmod(typval_T *argvars, typval_T *rettv)
2549{
2550 float_T fx = 0.0, fy = 0.0;
2551
2552 rettv->v_type = VAR_FLOAT;
2553 if (get_float_arg(argvars, &fx) == OK
2554 && get_float_arg(&argvars[1], &fy) == OK)
2555 rettv->vval.v_float = fmod(fx, fy);
2556 else
2557 rettv->vval.v_float = 0.0;
2558}
2559#endif
2560
2561/*
2562 * "fnameescape({string})" function
2563 */
2564 static void
2565f_fnameescape(typval_T *argvars, typval_T *rettv)
2566{
2567 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002568 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002569 rettv->v_type = VAR_STRING;
2570}
2571
2572/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002573 * "foreground()" function
2574 */
2575 static void
2576f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2577{
2578#ifdef FEAT_GUI
2579 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002580 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002581 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002582 return;
2583 }
2584#endif
2585#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002586 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587#endif
2588}
2589
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002590 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002591common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592{
2593 char_u *s;
2594 char_u *name;
2595 int use_string = FALSE;
2596 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002597 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002598
2599 if (argvars[0].v_type == VAR_FUNC)
2600 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002601 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 s = argvars[0].vval.v_string;
2603 }
2604 else if (argvars[0].v_type == VAR_PARTIAL
2605 && argvars[0].vval.v_partial != NULL)
2606 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002607 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002608 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002609 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002610 }
2611 else
2612 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002613 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002614 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002615 use_string = TRUE;
2616 }
2617
Bram Moolenaar843b8842016-08-21 14:36:15 +02002618 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002619 {
2620 name = s;
2621 trans_name = trans_function_name(&name, FALSE,
2622 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2623 if (*name != NUL)
2624 s = NULL;
2625 }
2626
Bram Moolenaar843b8842016-08-21 14:36:15 +02002627 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2628 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002629 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002630 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002631 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002632 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002633 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002634 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002635 else
2636 {
2637 int dict_idx = 0;
2638 int arg_idx = 0;
2639 list_T *list = NULL;
2640
2641 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2642 {
2643 char sid_buf[25];
2644 int off = *s == 's' ? 2 : 5;
2645
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002646 // Expand s: and <SID> into <SNR>nr_, so that the function can
2647 // also be called from another script. Using trans_function_name()
2648 // would also work, but some plugins depend on the name being
2649 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002650 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002651 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002652 if (name != NULL)
2653 {
2654 STRCPY(name, sid_buf);
2655 STRCAT(name, s + off);
2656 }
2657 }
2658 else
2659 name = vim_strsave(s);
2660
2661 if (argvars[1].v_type != VAR_UNKNOWN)
2662 {
2663 if (argvars[2].v_type != VAR_UNKNOWN)
2664 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002665 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666 arg_idx = 1;
2667 dict_idx = 2;
2668 }
2669 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002670 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002671 dict_idx = 1;
2672 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002673 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002674 arg_idx = 1;
2675 if (dict_idx > 0)
2676 {
2677 if (argvars[dict_idx].v_type != VAR_DICT)
2678 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002679 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002680 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002681 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 }
2683 if (argvars[dict_idx].vval.v_dict == NULL)
2684 dict_idx = 0;
2685 }
2686 if (arg_idx > 0)
2687 {
2688 if (argvars[arg_idx].v_type != VAR_LIST)
2689 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002690 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002692 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 }
2694 list = argvars[arg_idx].vval.v_list;
2695 if (list == NULL || list->lv_len == 0)
2696 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002697 else if (list->lv_len > MAX_FUNC_ARGS)
2698 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002699 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002700 vim_free(name);
2701 goto theend;
2702 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002703 }
2704 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002705 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002707 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002708
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002709 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002710 if (pt == NULL)
2711 vim_free(name);
2712 else
2713 {
2714 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2715 {
2716 listitem_T *li;
2717 int i = 0;
2718 int arg_len = 0;
2719 int lv_len = 0;
2720
2721 if (arg_pt != NULL)
2722 arg_len = arg_pt->pt_argc;
2723 if (list != NULL)
2724 lv_len = list->lv_len;
2725 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002726 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002727 if (pt->pt_argv == NULL)
2728 {
2729 vim_free(pt);
2730 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002731 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002732 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002733 for (i = 0; i < arg_len; i++)
2734 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2735 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002736 {
2737 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002738 for (li = list->lv_first; li != NULL;
2739 li = li->li_next)
2740 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002741 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002742 }
2743
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002744 // For "function(dict.func, [], dict)" and "func" is a partial
2745 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002746 if (dict_idx > 0)
2747 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002748 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002749 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2750 ++pt->pt_dict->dv_refcount;
2751 }
2752 else if (arg_pt != NULL)
2753 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002754 // If the dict was bound automatically the result is also
2755 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 pt->pt_dict = arg_pt->pt_dict;
2757 pt->pt_auto = arg_pt->pt_auto;
2758 if (pt->pt_dict != NULL)
2759 ++pt->pt_dict->dv_refcount;
2760 }
2761
2762 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002763 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2764 {
2765 pt->pt_func = arg_pt->pt_func;
2766 func_ptr_ref(pt->pt_func);
2767 vim_free(name);
2768 }
2769 else if (is_funcref)
2770 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002771 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002772 func_ptr_ref(pt->pt_func);
2773 vim_free(name);
2774 }
2775 else
2776 {
2777 pt->pt_name = name;
2778 func_ref(name);
2779 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002780 }
2781 rettv->v_type = VAR_PARTIAL;
2782 rettv->vval.v_partial = pt;
2783 }
2784 else
2785 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002786 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 rettv->v_type = VAR_FUNC;
2788 rettv->vval.v_string = name;
2789 func_ref(name);
2790 }
2791 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002792theend:
2793 vim_free(trans_name);
2794}
2795
2796/*
2797 * "funcref()" function
2798 */
2799 static void
2800f_funcref(typval_T *argvars, typval_T *rettv)
2801{
2802 common_function(argvars, rettv, TRUE);
2803}
2804
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002805 static type_T *
2806ret_f_function(int argcount, type_T **argtypes UNUSED)
2807{
2808 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2809 return &t_func_any;
2810 return &t_partial_void;
2811}
2812
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002813/*
2814 * "function()" function
2815 */
2816 static void
2817f_function(typval_T *argvars, typval_T *rettv)
2818{
2819 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002820}
2821
2822/*
2823 * "garbagecollect()" function
2824 */
2825 static void
2826f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2827{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002828 // This is postponed until we are back at the toplevel, because we may be
2829 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002830 want_garbage_collect = TRUE;
2831
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002832 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002833 garbage_collect_at_exit = TRUE;
2834}
2835
2836/*
2837 * "get()" function
2838 */
2839 static void
2840f_get(typval_T *argvars, typval_T *rettv)
2841{
2842 listitem_T *li;
2843 list_T *l;
2844 dictitem_T *di;
2845 dict_T *d;
2846 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002847 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002849 if (argvars[0].v_type == VAR_BLOB)
2850 {
2851 int error = FALSE;
2852 int idx = tv_get_number_chk(&argvars[1], &error);
2853
2854 if (!error)
2855 {
2856 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002857 if (idx < 0)
2858 idx = blob_len(argvars[0].vval.v_blob) + idx;
2859 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2860 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002861 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002862 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002863 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002864 tv = rettv;
2865 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002866 }
2867 }
2868 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869 {
2870 if ((l = argvars[0].vval.v_list) != NULL)
2871 {
2872 int error = FALSE;
2873
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002874 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002875 if (!error && li != NULL)
2876 tv = &li->li_tv;
2877 }
2878 }
2879 else if (argvars[0].v_type == VAR_DICT)
2880 {
2881 if ((d = argvars[0].vval.v_dict) != NULL)
2882 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002883 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002884 if (di != NULL)
2885 tv = &di->di_tv;
2886 }
2887 }
2888 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2889 {
2890 partial_T *pt;
2891 partial_T fref_pt;
2892
2893 if (argvars[0].v_type == VAR_PARTIAL)
2894 pt = argvars[0].vval.v_partial;
2895 else
2896 {
2897 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2898 fref_pt.pt_name = argvars[0].vval.v_string;
2899 pt = &fref_pt;
2900 }
2901
2902 if (pt != NULL)
2903 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002904 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002905 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002906
2907 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2908 {
2909 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002910 n = partial_name(pt);
2911 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 rettv->vval.v_string = NULL;
2913 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002914 {
2915 rettv->vval.v_string = vim_strsave(n);
2916 if (rettv->v_type == VAR_FUNC)
2917 func_ref(rettv->vval.v_string);
2918 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002919 }
2920 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002921 {
2922 what_is_dict = TRUE;
2923 if (pt->pt_dict != NULL)
2924 rettv_dict_set(rettv, pt->pt_dict);
2925 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926 else if (STRCMP(what, "args") == 0)
2927 {
2928 rettv->v_type = VAR_LIST;
2929 if (rettv_list_alloc(rettv) == OK)
2930 {
2931 int i;
2932
2933 for (i = 0; i < pt->pt_argc; ++i)
2934 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2935 }
2936 }
2937 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002938 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002939
2940 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2941 // third argument
2942 if (!what_is_dict)
2943 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002944 }
2945 }
2946 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002947 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002948
2949 if (tv == NULL)
2950 {
2951 if (argvars[2].v_type != VAR_UNKNOWN)
2952 copy_tv(&argvars[2], rettv);
2953 }
2954 else
2955 copy_tv(tv, rettv);
2956}
2957
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002958/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002959 * "getchangelist()" function
2960 */
2961 static void
2962f_getchangelist(typval_T *argvars, typval_T *rettv)
2963{
2964#ifdef FEAT_JUMPLIST
2965 buf_T *buf;
2966 int i;
2967 list_T *l;
2968 dict_T *d;
2969#endif
2970
2971 if (rettv_list_alloc(rettv) != OK)
2972 return;
2973
2974#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002975 if (argvars[0].v_type == VAR_UNKNOWN)
2976 buf = curbuf;
2977 else
2978 {
2979 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2980 ++emsg_off;
2981 buf = tv_get_buf(&argvars[0], FALSE);
2982 --emsg_off;
2983 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002984 if (buf == NULL)
2985 return;
2986
2987 l = list_alloc();
2988 if (l == NULL)
2989 return;
2990
2991 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2992 return;
2993 /*
2994 * The current window change list index tracks only the position in the
2995 * current buffer change list. For other buffers, use the change list
2996 * length as the current index.
2997 */
2998 list_append_number(rettv->vval.v_list,
2999 (varnumber_T)((buf == curwin->w_buffer)
3000 ? curwin->w_changelistidx : buf->b_changelistlen));
3001
3002 for (i = 0; i < buf->b_changelistlen; ++i)
3003 {
3004 if (buf->b_changelist[i].lnum == 0)
3005 continue;
3006 if ((d = dict_alloc()) == NULL)
3007 return;
3008 if (list_append_dict(l, d) == FAIL)
3009 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003010 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3011 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003012 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003013 }
3014#endif
3015}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016
3017/*
3018 * "getcharsearch()" function
3019 */
3020 static void
3021f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3022{
3023 if (rettv_dict_alloc(rettv) != FAIL)
3024 {
3025 dict_T *dict = rettv->vval.v_dict;
3026
Bram Moolenaare0be1672018-07-08 16:50:37 +02003027 dict_add_string(dict, "char", last_csearch());
3028 dict_add_number(dict, "forward", last_csearch_forward());
3029 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003030 }
3031}
3032
3033/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003034 * "getenv()" function
3035 */
3036 static void
3037f_getenv(typval_T *argvars, typval_T *rettv)
3038{
3039 int mustfree = FALSE;
3040 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3041
3042 if (p == NULL)
3043 {
3044 rettv->v_type = VAR_SPECIAL;
3045 rettv->vval.v_number = VVAL_NULL;
3046 return;
3047 }
3048 if (!mustfree)
3049 p = vim_strsave(p);
3050 rettv->vval.v_string = p;
3051 rettv->v_type = VAR_STRING;
3052}
3053
3054/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003055 * "getfontname()" function
3056 */
3057 static void
3058f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3059{
3060 rettv->v_type = VAR_STRING;
3061 rettv->vval.v_string = NULL;
3062#ifdef FEAT_GUI
3063 if (gui.in_use)
3064 {
3065 GuiFont font;
3066 char_u *name = NULL;
3067
3068 if (argvars[0].v_type == VAR_UNKNOWN)
3069 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003070 // Get the "Normal" font. Either the name saved by
3071 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003072 font = gui.norm_font;
3073 name = hl_get_font_name();
3074 }
3075 else
3076 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003077 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003078 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079 return;
3080 font = gui_mch_get_font(name, FALSE);
3081 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003082 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083 }
3084 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3085 if (argvars[0].v_type != VAR_UNKNOWN)
3086 gui_mch_free_font(font);
3087 }
3088#endif
3089}
3090
3091/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003092 * "getjumplist()" function
3093 */
3094 static void
3095f_getjumplist(typval_T *argvars, typval_T *rettv)
3096{
3097#ifdef FEAT_JUMPLIST
3098 win_T *wp;
3099 int i;
3100 list_T *l;
3101 dict_T *d;
3102#endif
3103
3104 if (rettv_list_alloc(rettv) != OK)
3105 return;
3106
3107#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003108 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003109 if (wp == NULL)
3110 return;
3111
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003112 cleanup_jumplist(wp, TRUE);
3113
Bram Moolenaar4f505882018-02-10 21:06:32 +01003114 l = list_alloc();
3115 if (l == NULL)
3116 return;
3117
3118 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3119 return;
3120 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3121
3122 for (i = 0; i < wp->w_jumplistlen; ++i)
3123 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003124 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3125 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003126 if ((d = dict_alloc()) == NULL)
3127 return;
3128 if (list_append_dict(l, d) == FAIL)
3129 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003130 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3131 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003132 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003133 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003134 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003135 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003136 }
3137#endif
3138}
3139
3140/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003141 * "getpid()" function
3142 */
3143 static void
3144f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3145{
3146 rettv->vval.v_number = mch_get_pid();
3147}
3148
3149 static void
3150getpos_both(
3151 typval_T *argvars,
3152 typval_T *rettv,
3153 int getcurpos)
3154{
3155 pos_T *fp;
3156 list_T *l;
3157 int fnum = -1;
3158
3159 if (rettv_list_alloc(rettv) == OK)
3160 {
3161 l = rettv->vval.v_list;
3162 if (getcurpos)
3163 fp = &curwin->w_cursor;
3164 else
3165 fp = var2fpos(&argvars[0], TRUE, &fnum);
3166 if (fnum != -1)
3167 list_append_number(l, (varnumber_T)fnum);
3168 else
3169 list_append_number(l, (varnumber_T)0);
3170 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3171 : (varnumber_T)0);
3172 list_append_number(l, (fp != NULL)
3173 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3174 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003175 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003176 (varnumber_T)0);
3177 if (getcurpos)
3178 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003179 int save_set_curswant = curwin->w_set_curswant;
3180 colnr_T save_curswant = curwin->w_curswant;
3181 colnr_T save_virtcol = curwin->w_virtcol;
3182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003183 update_curswant();
3184 list_append_number(l, curwin->w_curswant == MAXCOL ?
3185 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003186
3187 // Do not change "curswant", as it is unexpected that a get
3188 // function has a side effect.
3189 if (save_set_curswant)
3190 {
3191 curwin->w_set_curswant = save_set_curswant;
3192 curwin->w_curswant = save_curswant;
3193 curwin->w_virtcol = save_virtcol;
3194 curwin->w_valid &= ~VALID_VIRTCOL;
3195 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003196 }
3197 }
3198 else
3199 rettv->vval.v_number = FALSE;
3200}
3201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003202/*
3203 * "getcurpos()" function
3204 */
3205 static void
3206f_getcurpos(typval_T *argvars, typval_T *rettv)
3207{
3208 getpos_both(argvars, rettv, TRUE);
3209}
3210
3211/*
3212 * "getpos(string)" function
3213 */
3214 static void
3215f_getpos(typval_T *argvars, typval_T *rettv)
3216{
3217 getpos_both(argvars, rettv, FALSE);
3218}
3219
3220/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003221 * "getreg()" function
3222 */
3223 static void
3224f_getreg(typval_T *argvars, typval_T *rettv)
3225{
3226 char_u *strregname;
3227 int regname;
3228 int arg2 = FALSE;
3229 int return_list = FALSE;
3230 int error = FALSE;
3231
3232 if (argvars[0].v_type != VAR_UNKNOWN)
3233 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003234 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003235 error = strregname == NULL;
3236 if (argvars[1].v_type != VAR_UNKNOWN)
3237 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003238 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003239 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003240 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003241 }
3242 }
3243 else
3244 strregname = get_vim_var_str(VV_REG);
3245
3246 if (error)
3247 return;
3248
3249 regname = (strregname == NULL ? '"' : *strregname);
3250 if (regname == 0)
3251 regname = '"';
3252
3253 if (return_list)
3254 {
3255 rettv->v_type = VAR_LIST;
3256 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3257 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3258 if (rettv->vval.v_list == NULL)
3259 (void)rettv_list_alloc(rettv);
3260 else
3261 ++rettv->vval.v_list->lv_refcount;
3262 }
3263 else
3264 {
3265 rettv->v_type = VAR_STRING;
3266 rettv->vval.v_string = get_reg_contents(regname,
3267 arg2 ? GREG_EXPR_SRC : 0);
3268 }
3269}
3270
3271/*
3272 * "getregtype()" function
3273 */
3274 static void
3275f_getregtype(typval_T *argvars, typval_T *rettv)
3276{
3277 char_u *strregname;
3278 int regname;
3279 char_u buf[NUMBUFLEN + 2];
3280 long reglen = 0;
3281
3282 if (argvars[0].v_type != VAR_UNKNOWN)
3283 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003284 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003285 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003286 {
3287 rettv->v_type = VAR_STRING;
3288 rettv->vval.v_string = NULL;
3289 return;
3290 }
3291 }
3292 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003293 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003294 strregname = get_vim_var_str(VV_REG);
3295
3296 regname = (strregname == NULL ? '"' : *strregname);
3297 if (regname == 0)
3298 regname = '"';
3299
3300 buf[0] = NUL;
3301 buf[1] = NUL;
3302 switch (get_reg_type(regname, &reglen))
3303 {
3304 case MLINE: buf[0] = 'V'; break;
3305 case MCHAR: buf[0] = 'v'; break;
3306 case MBLOCK:
3307 buf[0] = Ctrl_V;
3308 sprintf((char *)buf + 1, "%ld", reglen + 1);
3309 break;
3310 }
3311 rettv->v_type = VAR_STRING;
3312 rettv->vval.v_string = vim_strsave(buf);
3313}
3314
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003315/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003316 * "gettagstack()" function
3317 */
3318 static void
3319f_gettagstack(typval_T *argvars, typval_T *rettv)
3320{
3321 win_T *wp = curwin; // default is current window
3322
3323 if (rettv_dict_alloc(rettv) != OK)
3324 return;
3325
3326 if (argvars[0].v_type != VAR_UNKNOWN)
3327 {
3328 wp = find_win_by_nr_or_id(&argvars[0]);
3329 if (wp == NULL)
3330 return;
3331 }
3332
3333 get_tagstack(wp, rettv->vval.v_dict);
3334}
3335
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003336// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003337#include "version.h"
3338
3339/*
3340 * "has()" function
3341 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003342 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003343f_has(typval_T *argvars, typval_T *rettv)
3344{
3345 int i;
3346 char_u *name;
3347 int n = FALSE;
3348 static char *(has_list[]) =
3349 {
3350#ifdef AMIGA
3351 "amiga",
3352# ifdef FEAT_ARP
3353 "arp",
3354# endif
3355#endif
3356#ifdef __BEOS__
3357 "beos",
3358#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003359#ifdef __HAIKU__
3360 "haiku",
3361#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003362#if defined(BSD) && !defined(MACOS_X)
3363 "bsd",
3364#endif
3365#ifdef hpux
3366 "hpux",
3367#endif
3368#ifdef __linux__
3369 "linux",
3370#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003371#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003372 "mac", // Mac OS X (and, once, Mac OS Classic)
3373 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003374# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003375 "macunix", // Mac OS X, with the darwin feature
3376 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003377# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378#endif
3379#ifdef __QNX__
3380 "qnx",
3381#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003382#ifdef SUN_SYSTEM
3383 "sun",
3384#else
3385 "moon",
3386#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003387#ifdef UNIX
3388 "unix",
3389#endif
3390#ifdef VMS
3391 "vms",
3392#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003393#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003394 "win32",
3395#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003396#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003397 "win32unix",
3398#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003399#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400 "win64",
3401#endif
3402#ifdef EBCDIC
3403 "ebcdic",
3404#endif
3405#ifndef CASE_INSENSITIVE_FILENAME
3406 "fname_case",
3407#endif
3408#ifdef HAVE_ACL
3409 "acl",
3410#endif
3411#ifdef FEAT_ARABIC
3412 "arabic",
3413#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003415#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003416 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003417#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003418#ifdef FEAT_AUTOSERVERNAME
3419 "autoservername",
3420#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003421#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003423# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003424 "balloon_multiline",
3425# endif
3426#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003427#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003428 "balloon_eval_term",
3429#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003430#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3431 "builtin_terms",
3432# ifdef ALL_BUILTIN_TCAPS
3433 "all_builtin_terms",
3434# endif
3435#endif
3436#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003437 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003438 || defined(FEAT_GUI_MOTIF))
3439 "browsefilter",
3440#endif
3441#ifdef FEAT_BYTEOFF
3442 "byte_offset",
3443#endif
3444#ifdef FEAT_JOB_CHANNEL
3445 "channel",
3446#endif
3447#ifdef FEAT_CINDENT
3448 "cindent",
3449#endif
3450#ifdef FEAT_CLIENTSERVER
3451 "clientserver",
3452#endif
3453#ifdef FEAT_CLIPBOARD
3454 "clipboard",
3455#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003456 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003458 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003459#ifdef FEAT_CONCEAL
3460 "conceal",
3461#endif
3462#ifdef FEAT_CRYPT
3463 "cryptv",
3464 "crypt-blowfish",
3465 "crypt-blowfish2",
3466#endif
3467#ifdef FEAT_CSCOPE
3468 "cscope",
3469#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471#ifdef CURSOR_SHAPE
3472 "cursorshape",
3473#endif
3474#ifdef DEBUG
3475 "debug",
3476#endif
3477#ifdef FEAT_CON_DIALOG
3478 "dialog_con",
3479#endif
3480#ifdef FEAT_GUI_DIALOG
3481 "dialog_gui",
3482#endif
3483#ifdef FEAT_DIFF
3484 "diff",
3485#endif
3486#ifdef FEAT_DIGRAPHS
3487 "digraphs",
3488#endif
3489#ifdef FEAT_DIRECTX
3490 "directx",
3491#endif
3492#ifdef FEAT_DND
3493 "dnd",
3494#endif
3495#ifdef FEAT_EMACS_TAGS
3496 "emacs_tags",
3497#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003498 "eval", // always present, of course!
3499 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500#ifdef FEAT_SEARCH_EXTRA
3501 "extra_search",
3502#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003503#ifdef FEAT_SEARCHPATH
3504 "file_in_path",
3505#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003506#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003507 "filterpipe",
3508#endif
3509#ifdef FEAT_FIND_ID
3510 "find_in_path",
3511#endif
3512#ifdef FEAT_FLOAT
3513 "float",
3514#endif
3515#ifdef FEAT_FOLDING
3516 "folding",
3517#endif
3518#ifdef FEAT_FOOTER
3519 "footer",
3520#endif
3521#if !defined(USE_SYSTEM) && defined(UNIX)
3522 "fork",
3523#endif
3524#ifdef FEAT_GETTEXT
3525 "gettext",
3526#endif
3527#ifdef FEAT_GUI
3528 "gui",
3529#endif
3530#ifdef FEAT_GUI_ATHENA
3531# ifdef FEAT_GUI_NEXTAW
3532 "gui_neXtaw",
3533# else
3534 "gui_athena",
3535# endif
3536#endif
3537#ifdef FEAT_GUI_GTK
3538 "gui_gtk",
3539# ifdef USE_GTK3
3540 "gui_gtk3",
3541# else
3542 "gui_gtk2",
3543# endif
3544#endif
3545#ifdef FEAT_GUI_GNOME
3546 "gui_gnome",
3547#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003548#ifdef FEAT_GUI_HAIKU
3549 "gui_haiku",
3550#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003551#ifdef FEAT_GUI_MAC
3552 "gui_mac",
3553#endif
3554#ifdef FEAT_GUI_MOTIF
3555 "gui_motif",
3556#endif
3557#ifdef FEAT_GUI_PHOTON
3558 "gui_photon",
3559#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003560#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561 "gui_win32",
3562#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003563#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3564 "iconv",
3565#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003566 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003567#ifdef FEAT_JOB_CHANNEL
3568 "job",
3569#endif
3570#ifdef FEAT_JUMPLIST
3571 "jumplist",
3572#endif
3573#ifdef FEAT_KEYMAP
3574 "keymap",
3575#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003576 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003577#ifdef FEAT_LANGMAP
3578 "langmap",
3579#endif
3580#ifdef FEAT_LIBCALL
3581 "libcall",
3582#endif
3583#ifdef FEAT_LINEBREAK
3584 "linebreak",
3585#endif
3586#ifdef FEAT_LISP
3587 "lispindent",
3588#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591#ifdef FEAT_LUA
3592# ifndef DYNAMIC_LUA
3593 "lua",
3594# endif
3595#endif
3596#ifdef FEAT_MENU
3597 "menu",
3598#endif
3599#ifdef FEAT_SESSION
3600 "mksession",
3601#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003604#ifdef FEAT_MOUSESHAPE
3605 "mouseshape",
3606#endif
3607#if defined(UNIX) || defined(VMS)
3608# ifdef FEAT_MOUSE_DEC
3609 "mouse_dec",
3610# endif
3611# ifdef FEAT_MOUSE_GPM
3612 "mouse_gpm",
3613# endif
3614# ifdef FEAT_MOUSE_JSB
3615 "mouse_jsbterm",
3616# endif
3617# ifdef FEAT_MOUSE_NET
3618 "mouse_netterm",
3619# endif
3620# ifdef FEAT_MOUSE_PTERM
3621 "mouse_pterm",
3622# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003623# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003624 "mouse_sgr",
3625# endif
3626# ifdef FEAT_SYSMOUSE
3627 "mouse_sysmouse",
3628# endif
3629# ifdef FEAT_MOUSE_URXVT
3630 "mouse_urxvt",
3631# endif
3632# ifdef FEAT_MOUSE_XTERM
3633 "mouse_xterm",
3634# endif
3635#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637#ifdef FEAT_MBYTE_IME
3638 "multi_byte_ime",
3639#endif
3640#ifdef FEAT_MULTI_LANG
3641 "multi_lang",
3642#endif
3643#ifdef FEAT_MZSCHEME
3644#ifndef DYNAMIC_MZSCHEME
3645 "mzscheme",
3646#endif
3647#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003648 "num64",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649#ifdef FEAT_OLE
3650 "ole",
3651#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003652#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003653 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003654#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003655#ifdef FEAT_PATH_EXTRA
3656 "path_extra",
3657#endif
3658#ifdef FEAT_PERL
3659#ifndef DYNAMIC_PERL
3660 "perl",
3661#endif
3662#endif
3663#ifdef FEAT_PERSISTENT_UNDO
3664 "persistent_undo",
3665#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003666#if defined(FEAT_PYTHON)
3667 "python_compiled",
3668# if defined(DYNAMIC_PYTHON)
3669 "python_dynamic",
3670# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003671 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003672 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003673# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003674#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003675#if defined(FEAT_PYTHON3)
3676 "python3_compiled",
3677# if defined(DYNAMIC_PYTHON3)
3678 "python3_dynamic",
3679# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003680 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003681 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003682# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003683#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003684#ifdef FEAT_PROP_POPUP
3685 "popupwin",
3686#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003687#ifdef FEAT_POSTSCRIPT
3688 "postscript",
3689#endif
3690#ifdef FEAT_PRINTER
3691 "printer",
3692#endif
3693#ifdef FEAT_PROFILE
3694 "profile",
3695#endif
3696#ifdef FEAT_RELTIME
3697 "reltime",
3698#endif
3699#ifdef FEAT_QUICKFIX
3700 "quickfix",
3701#endif
3702#ifdef FEAT_RIGHTLEFT
3703 "rightleft",
3704#endif
3705#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3706 "ruby",
3707#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003708 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003709#ifdef FEAT_CMDL_INFO
3710 "showcmd",
3711 "cmdline_info",
3712#endif
3713#ifdef FEAT_SIGNS
3714 "signs",
3715#endif
3716#ifdef FEAT_SMARTINDENT
3717 "smartindent",
3718#endif
3719#ifdef STARTUPTIME
3720 "startuptime",
3721#endif
3722#ifdef FEAT_STL_OPT
3723 "statusline",
3724#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003725#ifdef FEAT_NETBEANS_INTG
3726 "netbeans_intg",
3727#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003728#ifdef FEAT_SOUND
3729 "sound",
3730#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003731#ifdef FEAT_SPELL
3732 "spell",
3733#endif
3734#ifdef FEAT_SYN_HL
3735 "syntax",
3736#endif
3737#if defined(USE_SYSTEM) || !defined(UNIX)
3738 "system",
3739#endif
3740#ifdef FEAT_TAG_BINS
3741 "tag_binary",
3742#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003743#ifdef FEAT_TCL
3744# ifndef DYNAMIC_TCL
3745 "tcl",
3746# endif
3747#endif
3748#ifdef FEAT_TERMGUICOLORS
3749 "termguicolors",
3750#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003751#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003752 "terminal",
3753#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003754#ifdef TERMINFO
3755 "terminfo",
3756#endif
3757#ifdef FEAT_TERMRESPONSE
3758 "termresponse",
3759#endif
3760#ifdef FEAT_TEXTOBJ
3761 "textobjects",
3762#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003763#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003764 "textprop",
3765#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003766#ifdef HAVE_TGETENT
3767 "tgetent",
3768#endif
3769#ifdef FEAT_TIMERS
3770 "timers",
3771#endif
3772#ifdef FEAT_TITLE
3773 "title",
3774#endif
3775#ifdef FEAT_TOOLBAR
3776 "toolbar",
3777#endif
3778#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3779 "unnamedplus",
3780#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003781 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003782 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003783#ifdef FEAT_VARTABS
3784 "vartabs",
3785#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003786 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787#ifdef FEAT_VIMINFO
3788 "viminfo",
3789#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003790 "vimscript-1",
3791 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003792 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003793 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003794 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003795 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003796 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003797 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003798#ifdef FEAT_VTP
3799 "vtp",
3800#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003801#ifdef FEAT_WILDIGN
3802 "wildignore",
3803#endif
3804#ifdef FEAT_WILDMENU
3805 "wildmenu",
3806#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003807 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808#ifdef FEAT_WAK
3809 "winaltkeys",
3810#endif
3811#ifdef FEAT_WRITEBACKUP
3812 "writebackup",
3813#endif
3814#ifdef FEAT_XIM
3815 "xim",
3816#endif
3817#ifdef FEAT_XFONTSET
3818 "xfontset",
3819#endif
3820#ifdef FEAT_XPM_W32
3821 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003822 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003823#else
3824# if defined(HAVE_XPM)
3825 "xpm",
3826# endif
3827#endif
3828#ifdef USE_XSMP
3829 "xsmp",
3830#endif
3831#ifdef USE_XSMP_INTERACT
3832 "xsmp_interact",
3833#endif
3834#ifdef FEAT_XCLIPBOARD
3835 "xterm_clipboard",
3836#endif
3837#ifdef FEAT_XTERM_SAVE
3838 "xterm_save",
3839#endif
3840#if defined(UNIX) && defined(FEAT_X11)
3841 "X11",
3842#endif
3843 NULL
3844 };
3845
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003846 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003847 for (i = 0; has_list[i] != NULL; ++i)
3848 if (STRICMP(name, has_list[i]) == 0)
3849 {
3850 n = TRUE;
3851 break;
3852 }
3853
3854 if (n == FALSE)
3855 {
3856 if (STRNICMP(name, "patch", 5) == 0)
3857 {
3858 if (name[5] == '-'
3859 && STRLEN(name) >= 11
3860 && vim_isdigit(name[6])
3861 && vim_isdigit(name[8])
3862 && vim_isdigit(name[10]))
3863 {
3864 int major = atoi((char *)name + 6);
3865 int minor = atoi((char *)name + 8);
3866
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003867 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003868 n = (major < VIM_VERSION_MAJOR
3869 || (major == VIM_VERSION_MAJOR
3870 && (minor < VIM_VERSION_MINOR
3871 || (minor == VIM_VERSION_MINOR
3872 && has_patch(atoi((char *)name + 10))))));
3873 }
3874 else
3875 n = has_patch(atoi((char *)name + 5));
3876 }
3877 else if (STRICMP(name, "vim_starting") == 0)
3878 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003879 else if (STRICMP(name, "ttyin") == 0)
3880 n = mch_input_isatty();
3881 else if (STRICMP(name, "ttyout") == 0)
3882 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003883 else if (STRICMP(name, "multi_byte_encoding") == 0)
3884 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003885#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003886 else if (STRICMP(name, "balloon_multiline") == 0)
3887 n = multiline_balloon_available();
3888#endif
3889#ifdef DYNAMIC_TCL
3890 else if (STRICMP(name, "tcl") == 0)
3891 n = tcl_enabled(FALSE);
3892#endif
3893#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3894 else if (STRICMP(name, "iconv") == 0)
3895 n = iconv_enabled(FALSE);
3896#endif
3897#ifdef DYNAMIC_LUA
3898 else if (STRICMP(name, "lua") == 0)
3899 n = lua_enabled(FALSE);
3900#endif
3901#ifdef DYNAMIC_MZSCHEME
3902 else if (STRICMP(name, "mzscheme") == 0)
3903 n = mzscheme_enabled(FALSE);
3904#endif
3905#ifdef DYNAMIC_RUBY
3906 else if (STRICMP(name, "ruby") == 0)
3907 n = ruby_enabled(FALSE);
3908#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909#ifdef DYNAMIC_PYTHON
3910 else if (STRICMP(name, "python") == 0)
3911 n = python_enabled(FALSE);
3912#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003913#ifdef DYNAMIC_PYTHON3
3914 else if (STRICMP(name, "python3") == 0)
3915 n = python3_enabled(FALSE);
3916#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003917#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3918 else if (STRICMP(name, "pythonx") == 0)
3919 {
3920# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3921 if (p_pyx == 0)
3922 n = python3_enabled(FALSE) || python_enabled(FALSE);
3923 else if (p_pyx == 3)
3924 n = python3_enabled(FALSE);
3925 else if (p_pyx == 2)
3926 n = python_enabled(FALSE);
3927# elif defined(DYNAMIC_PYTHON)
3928 n = python_enabled(FALSE);
3929# elif defined(DYNAMIC_PYTHON3)
3930 n = python3_enabled(FALSE);
3931# endif
3932 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933#endif
3934#ifdef DYNAMIC_PERL
3935 else if (STRICMP(name, "perl") == 0)
3936 n = perl_enabled(FALSE);
3937#endif
3938#ifdef FEAT_GUI
3939 else if (STRICMP(name, "gui_running") == 0)
3940 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941# ifdef FEAT_BROWSE
3942 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003943 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944# endif
3945#endif
3946#ifdef FEAT_SYN_HL
3947 else if (STRICMP(name, "syntax_items") == 0)
3948 n = syntax_present(curwin);
3949#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003950#ifdef FEAT_VTP
3951 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003952 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953#endif
3954#ifdef FEAT_NETBEANS_INTG
3955 else if (STRICMP(name, "netbeans_enabled") == 0)
3956 n = netbeans_active();
3957#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003958#ifdef FEAT_MOUSE_GPM
3959 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3960 n = gpm_enabled();
3961#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003962#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003963 else if (STRICMP(name, "terminal") == 0)
3964 n = terminal_enabled();
3965#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003966#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003967 else if (STRICMP(name, "conpty") == 0)
3968 n = use_conpty();
3969#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003970#ifdef FEAT_CLIPBOARD
3971 else if (STRICMP(name, "clipboard_working") == 0)
3972 n = clip_star.available;
3973#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003974#ifdef VIMDLL
3975 else if (STRICMP(name, "filterpipe") == 0)
3976 n = gui.in_use || gui.starting;
3977#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003978 }
3979
3980 rettv->vval.v_number = n;
3981}
3982
3983/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 * "haslocaldir()" function
3985 */
3986 static void
3987f_haslocaldir(typval_T *argvars, typval_T *rettv)
3988{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003989 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003990 win_T *wp = NULL;
3991
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003992 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3993
3994 // Check for window-local and tab-local directories
3995 if (wp != NULL && wp->w_localdir != NULL)
3996 rettv->vval.v_number = 1;
3997 else if (tp != NULL && tp->tp_localdir != NULL)
3998 rettv->vval.v_number = 2;
3999 else
4000 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004001}
4002
4003/*
4004 * "hasmapto()" function
4005 */
4006 static void
4007f_hasmapto(typval_T *argvars, typval_T *rettv)
4008{
4009 char_u *name;
4010 char_u *mode;
4011 char_u buf[NUMBUFLEN];
4012 int abbr = FALSE;
4013
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004014 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004015 if (argvars[1].v_type == VAR_UNKNOWN)
4016 mode = (char_u *)"nvo";
4017 else
4018 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004019 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004021 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004022 }
4023
4024 if (map_to_exists(name, mode, abbr))
4025 rettv->vval.v_number = TRUE;
4026 else
4027 rettv->vval.v_number = FALSE;
4028}
4029
4030/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004031 * "highlightID(name)" function
4032 */
4033 static void
4034f_hlID(typval_T *argvars, typval_T *rettv)
4035{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004036 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004037}
4038
4039/*
4040 * "highlight_exists()" function
4041 */
4042 static void
4043f_hlexists(typval_T *argvars, typval_T *rettv)
4044{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004045 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004046}
4047
4048/*
4049 * "hostname()" function
4050 */
4051 static void
4052f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4053{
4054 char_u hostname[256];
4055
4056 mch_get_host_name(hostname, 256);
4057 rettv->v_type = VAR_STRING;
4058 rettv->vval.v_string = vim_strsave(hostname);
4059}
4060
4061/*
4062 * iconv() function
4063 */
4064 static void
4065f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4066{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004067 char_u buf1[NUMBUFLEN];
4068 char_u buf2[NUMBUFLEN];
4069 char_u *from, *to, *str;
4070 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004071
4072 rettv->v_type = VAR_STRING;
4073 rettv->vval.v_string = NULL;
4074
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004075 str = tv_get_string(&argvars[0]);
4076 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4077 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078 vimconv.vc_type = CONV_NONE;
4079 convert_setup(&vimconv, from, to);
4080
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004081 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004082 if (vimconv.vc_type == CONV_NONE)
4083 rettv->vval.v_string = vim_strsave(str);
4084 else
4085 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4086
4087 convert_setup(&vimconv, NULL, NULL);
4088 vim_free(from);
4089 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004090}
4091
4092/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004093 * "index()" function
4094 */
4095 static void
4096f_index(typval_T *argvars, typval_T *rettv)
4097{
4098 list_T *l;
4099 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004100 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004101 long idx = 0;
4102 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004103 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004104
4105 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004106 if (argvars[0].v_type == VAR_BLOB)
4107 {
4108 typval_T tv;
4109 int start = 0;
4110
4111 if (argvars[2].v_type != VAR_UNKNOWN)
4112 {
4113 start = tv_get_number_chk(&argvars[2], &error);
4114 if (error)
4115 return;
4116 }
4117 b = argvars[0].vval.v_blob;
4118 if (b == NULL)
4119 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004120 if (start < 0)
4121 {
4122 start = blob_len(b) + start;
4123 if (start < 0)
4124 start = 0;
4125 }
4126
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004127 for (idx = start; idx < blob_len(b); ++idx)
4128 {
4129 tv.v_type = VAR_NUMBER;
4130 tv.vval.v_number = blob_get(b, idx);
4131 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4132 {
4133 rettv->vval.v_number = idx;
4134 return;
4135 }
4136 }
4137 return;
4138 }
4139 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004140 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004141 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004142 return;
4143 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004144
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004145 l = argvars[0].vval.v_list;
4146 if (l != NULL)
4147 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004148 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004149 item = l->lv_first;
4150 if (argvars[2].v_type != VAR_UNKNOWN)
4151 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004152 // Start at specified item. Use the cached index that list_find()
4153 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004154 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004155 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004157 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158 if (error)
4159 item = NULL;
4160 }
4161
4162 for ( ; item != NULL; item = item->li_next, ++idx)
4163 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4164 {
4165 rettv->vval.v_number = idx;
4166 break;
4167 }
4168 }
4169}
4170
4171static int inputsecret_flag = 0;
4172
4173/*
4174 * "input()" function
4175 * Also handles inputsecret() when inputsecret is set.
4176 */
4177 static void
4178f_input(typval_T *argvars, typval_T *rettv)
4179{
4180 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4181}
4182
4183/*
4184 * "inputdialog()" function
4185 */
4186 static void
4187f_inputdialog(typval_T *argvars, typval_T *rettv)
4188{
4189#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004190 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004191 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4192 {
4193 char_u *message;
4194 char_u buf[NUMBUFLEN];
4195 char_u *defstr = (char_u *)"";
4196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004197 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004198 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004199 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004200 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4201 else
4202 IObuff[0] = NUL;
4203 if (message != NULL && defstr != NULL
4204 && do_dialog(VIM_QUESTION, NULL, message,
4205 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4206 rettv->vval.v_string = vim_strsave(IObuff);
4207 else
4208 {
4209 if (message != NULL && defstr != NULL
4210 && argvars[1].v_type != VAR_UNKNOWN
4211 && argvars[2].v_type != VAR_UNKNOWN)
4212 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004213 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004214 else
4215 rettv->vval.v_string = NULL;
4216 }
4217 rettv->v_type = VAR_STRING;
4218 }
4219 else
4220#endif
4221 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4222}
4223
4224/*
4225 * "inputlist()" function
4226 */
4227 static void
4228f_inputlist(typval_T *argvars, typval_T *rettv)
4229{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004230 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004231 listitem_T *li;
4232 int selected;
4233 int mouse_used;
4234
4235#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004236 // While starting up, there is no place to enter text. When running tests
4237 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004238 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004239 return;
4240#endif
4241 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4242 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004243 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004244 return;
4245 }
4246
4247 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004248 msg_row = Rows - 1; // for when 'cmdheight' > 1
4249 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004250 msg_scroll = TRUE;
4251 msg_clr_eos();
4252
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004253 l = argvars[0].vval.v_list;
4254 range_list_materialize(l);
4255 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004256 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004257 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004258 msg_putchar('\n');
4259 }
4260
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004261 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004262 selected = prompt_for_number(&mouse_used);
4263 if (mouse_used)
4264 selected -= lines_left;
4265
4266 rettv->vval.v_number = selected;
4267}
4268
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004269static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4270
4271/*
4272 * "inputrestore()" function
4273 */
4274 static void
4275f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4276{
4277 if (ga_userinput.ga_len > 0)
4278 {
4279 --ga_userinput.ga_len;
4280 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4281 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004282 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004283 }
4284 else if (p_verbose > 1)
4285 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004286 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004287 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004288 }
4289}
4290
4291/*
4292 * "inputsave()" function
4293 */
4294 static void
4295f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4296{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004297 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298 if (ga_grow(&ga_userinput, 1) == OK)
4299 {
4300 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4301 + ga_userinput.ga_len);
4302 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004303 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004304 }
4305 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004306 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307}
4308
4309/*
4310 * "inputsecret()" function
4311 */
4312 static void
4313f_inputsecret(typval_T *argvars, typval_T *rettv)
4314{
4315 ++cmdline_star;
4316 ++inputsecret_flag;
4317 f_input(argvars, rettv);
4318 --cmdline_star;
4319 --inputsecret_flag;
4320}
4321
4322/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004323 * "interrupt()" function
4324 */
4325 static void
4326f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4327{
4328 got_int = TRUE;
4329}
4330
4331/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004332 * "invert(expr)" function
4333 */
4334 static void
4335f_invert(typval_T *argvars, typval_T *rettv)
4336{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004337 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004338}
4339
4340/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004341 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4342 * or it refers to a List or Dictionary that is locked.
4343 */
4344 static int
4345tv_islocked(typval_T *tv)
4346{
4347 return (tv->v_lock & VAR_LOCKED)
4348 || (tv->v_type == VAR_LIST
4349 && tv->vval.v_list != NULL
4350 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4351 || (tv->v_type == VAR_DICT
4352 && tv->vval.v_dict != NULL
4353 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4354}
4355
4356/*
4357 * "islocked()" function
4358 */
4359 static void
4360f_islocked(typval_T *argvars, typval_T *rettv)
4361{
4362 lval_T lv;
4363 char_u *end;
4364 dictitem_T *di;
4365
4366 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004367 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004368 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004369 if (end != NULL && lv.ll_name != NULL)
4370 {
4371 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004372 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004373 else
4374 {
4375 if (lv.ll_tv == NULL)
4376 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004377 di = find_var(lv.ll_name, NULL, TRUE);
4378 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004379 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004380 // Consider a variable locked when:
4381 // 1. the variable itself is locked
4382 // 2. the value of the variable is locked.
4383 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004384 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4385 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004386 }
4387 }
4388 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004389 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004390 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004391 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004392 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004393 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004394 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4395 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004396 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4398 }
4399 }
4400
4401 clear_lval(&lv);
4402}
4403
4404#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4405/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004406 * "isinf()" function
4407 */
4408 static void
4409f_isinf(typval_T *argvars, typval_T *rettv)
4410{
4411 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4412 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4413}
4414
4415/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416 * "isnan()" function
4417 */
4418 static void
4419f_isnan(typval_T *argvars, typval_T *rettv)
4420{
4421 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4422 && isnan(argvars[0].vval.v_float);
4423}
4424#endif
4425
4426/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004427 * "last_buffer_nr()" function.
4428 */
4429 static void
4430f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4431{
4432 int n = 0;
4433 buf_T *buf;
4434
Bram Moolenaar29323592016-07-24 22:04:11 +02004435 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004436 if (n < buf->b_fnum)
4437 n = buf->b_fnum;
4438
4439 rettv->vval.v_number = n;
4440}
4441
4442/*
4443 * "len()" function
4444 */
4445 static void
4446f_len(typval_T *argvars, typval_T *rettv)
4447{
4448 switch (argvars[0].v_type)
4449 {
4450 case VAR_STRING:
4451 case VAR_NUMBER:
4452 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004453 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004454 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004455 case VAR_BLOB:
4456 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4457 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004458 case VAR_LIST:
4459 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4460 break;
4461 case VAR_DICT:
4462 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4463 break;
4464 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004465 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004466 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004467 case VAR_SPECIAL:
4468 case VAR_FLOAT:
4469 case VAR_FUNC:
4470 case VAR_PARTIAL:
4471 case VAR_JOB:
4472 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004473 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474 break;
4475 }
4476}
4477
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004478 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004479libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004480{
4481#ifdef FEAT_LIBCALL
4482 char_u *string_in;
4483 char_u **string_result;
4484 int nr_result;
4485#endif
4486
4487 rettv->v_type = type;
4488 if (type != VAR_NUMBER)
4489 rettv->vval.v_string = NULL;
4490
4491 if (check_restricted() || check_secure())
4492 return;
4493
4494#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004495 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004496 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4497 {
4498 string_in = NULL;
4499 if (argvars[2].v_type == VAR_STRING)
4500 string_in = argvars[2].vval.v_string;
4501 if (type == VAR_NUMBER)
4502 string_result = NULL;
4503 else
4504 string_result = &rettv->vval.v_string;
4505 if (mch_libcall(argvars[0].vval.v_string,
4506 argvars[1].vval.v_string,
4507 string_in,
4508 argvars[2].vval.v_number,
4509 string_result,
4510 &nr_result) == OK
4511 && type == VAR_NUMBER)
4512 rettv->vval.v_number = nr_result;
4513 }
4514#endif
4515}
4516
4517/*
4518 * "libcall()" function
4519 */
4520 static void
4521f_libcall(typval_T *argvars, typval_T *rettv)
4522{
4523 libcall_common(argvars, rettv, VAR_STRING);
4524}
4525
4526/*
4527 * "libcallnr()" function
4528 */
4529 static void
4530f_libcallnr(typval_T *argvars, typval_T *rettv)
4531{
4532 libcall_common(argvars, rettv, VAR_NUMBER);
4533}
4534
4535/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004536 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004537 */
4538 static void
4539f_line(typval_T *argvars, typval_T *rettv)
4540{
4541 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004542 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004543 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004544 int id;
4545 tabpage_T *tp;
4546 win_T *wp;
4547 win_T *save_curwin;
4548 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004550 if (argvars[1].v_type != VAR_UNKNOWN)
4551 {
4552 // use window specified in the second argument
4553 id = (int)tv_get_number(&argvars[1]);
4554 wp = win_id2wp_tp(id, &tp);
4555 if (wp != NULL && tp != NULL)
4556 {
4557 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4558 == OK)
4559 {
4560 check_cursor();
4561 fp = var2fpos(&argvars[0], TRUE, &fnum);
4562 }
4563 restore_win_noblock(save_curwin, save_curtab, TRUE);
4564 }
4565 }
4566 else
4567 // use current window
4568 fp = var2fpos(&argvars[0], TRUE, &fnum);
4569
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004570 if (fp != NULL)
4571 lnum = fp->lnum;
4572 rettv->vval.v_number = lnum;
4573}
4574
4575/*
4576 * "line2byte(lnum)" function
4577 */
4578 static void
4579f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4580{
4581#ifndef FEAT_BYTEOFF
4582 rettv->vval.v_number = -1;
4583#else
4584 linenr_T lnum;
4585
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004586 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004587 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4588 rettv->vval.v_number = -1;
4589 else
4590 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4591 if (rettv->vval.v_number >= 0)
4592 ++rettv->vval.v_number;
4593#endif
4594}
4595
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004596#ifdef FEAT_FLOAT
4597/*
4598 * "log()" function
4599 */
4600 static void
4601f_log(typval_T *argvars, typval_T *rettv)
4602{
4603 float_T f = 0.0;
4604
4605 rettv->v_type = VAR_FLOAT;
4606 if (get_float_arg(argvars, &f) == OK)
4607 rettv->vval.v_float = log(f);
4608 else
4609 rettv->vval.v_float = 0.0;
4610}
4611
4612/*
4613 * "log10()" function
4614 */
4615 static void
4616f_log10(typval_T *argvars, typval_T *rettv)
4617{
4618 float_T f = 0.0;
4619
4620 rettv->v_type = VAR_FLOAT;
4621 if (get_float_arg(argvars, &f) == OK)
4622 rettv->vval.v_float = log10(f);
4623 else
4624 rettv->vval.v_float = 0.0;
4625}
4626#endif
4627
4628#ifdef FEAT_LUA
4629/*
4630 * "luaeval()" function
4631 */
4632 static void
4633f_luaeval(typval_T *argvars, typval_T *rettv)
4634{
4635 char_u *str;
4636 char_u buf[NUMBUFLEN];
4637
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004638 if (check_restricted() || check_secure())
4639 return;
4640
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004641 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004642 do_luaeval(str, argvars + 1, rettv);
4643}
4644#endif
4645
4646/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004647 * "maparg()" function
4648 */
4649 static void
4650f_maparg(typval_T *argvars, typval_T *rettv)
4651{
4652 get_maparg(argvars, rettv, TRUE);
4653}
4654
4655/*
4656 * "mapcheck()" function
4657 */
4658 static void
4659f_mapcheck(typval_T *argvars, typval_T *rettv)
4660{
4661 get_maparg(argvars, rettv, FALSE);
4662}
4663
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004664typedef enum
4665{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004666 MATCH_END, // matchend()
4667 MATCH_MATCH, // match()
4668 MATCH_STR, // matchstr()
4669 MATCH_LIST, // matchlist()
4670 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004671} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004672
4673 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004674find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675{
4676 char_u *str = NULL;
4677 long len = 0;
4678 char_u *expr = NULL;
4679 char_u *pat;
4680 regmatch_T regmatch;
4681 char_u patbuf[NUMBUFLEN];
4682 char_u strbuf[NUMBUFLEN];
4683 char_u *save_cpo;
4684 long start = 0;
4685 long nth = 1;
4686 colnr_T startcol = 0;
4687 int match = 0;
4688 list_T *l = NULL;
4689 listitem_T *li = NULL;
4690 long idx = 0;
4691 char_u *tofree = NULL;
4692
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004693 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004694 save_cpo = p_cpo;
4695 p_cpo = (char_u *)"";
4696
4697 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004698 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004699 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004700 // type MATCH_LIST: return empty list when there are no matches.
4701 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702 if (rettv_list_alloc(rettv) == FAIL)
4703 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004704 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 && (list_append_string(rettv->vval.v_list,
4706 (char_u *)"", 0) == FAIL
4707 || list_append_number(rettv->vval.v_list,
4708 (varnumber_T)-1) == FAIL
4709 || list_append_number(rettv->vval.v_list,
4710 (varnumber_T)-1) == FAIL
4711 || list_append_number(rettv->vval.v_list,
4712 (varnumber_T)-1) == FAIL))
4713 {
4714 list_free(rettv->vval.v_list);
4715 rettv->vval.v_list = NULL;
4716 goto theend;
4717 }
4718 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004719 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004720 {
4721 rettv->v_type = VAR_STRING;
4722 rettv->vval.v_string = NULL;
4723 }
4724
4725 if (argvars[0].v_type == VAR_LIST)
4726 {
4727 if ((l = argvars[0].vval.v_list) == NULL)
4728 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004729 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004730 li = l->lv_first;
4731 }
4732 else
4733 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004734 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735 len = (long)STRLEN(str);
4736 }
4737
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004738 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004739 if (pat == NULL)
4740 goto theend;
4741
4742 if (argvars[2].v_type != VAR_UNKNOWN)
4743 {
4744 int error = FALSE;
4745
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004746 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004747 if (error)
4748 goto theend;
4749 if (l != NULL)
4750 {
4751 li = list_find(l, start);
4752 if (li == NULL)
4753 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004754 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004755 }
4756 else
4757 {
4758 if (start < 0)
4759 start = 0;
4760 if (start > len)
4761 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004762 // When "count" argument is there ignore matches before "start",
4763 // otherwise skip part of the string. Differs when pattern is "^"
4764 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004765 if (argvars[3].v_type != VAR_UNKNOWN)
4766 startcol = start;
4767 else
4768 {
4769 str += start;
4770 len -= start;
4771 }
4772 }
4773
4774 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004775 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004776 if (error)
4777 goto theend;
4778 }
4779
4780 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4781 if (regmatch.regprog != NULL)
4782 {
4783 regmatch.rm_ic = p_ic;
4784
4785 for (;;)
4786 {
4787 if (l != NULL)
4788 {
4789 if (li == NULL)
4790 {
4791 match = FALSE;
4792 break;
4793 }
4794 vim_free(tofree);
4795 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4796 if (str == NULL)
4797 break;
4798 }
4799
4800 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4801
4802 if (match && --nth <= 0)
4803 break;
4804 if (l == NULL && !match)
4805 break;
4806
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004807 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004808 if (l != NULL)
4809 {
4810 li = li->li_next;
4811 ++idx;
4812 }
4813 else
4814 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815 startcol = (colnr_T)(regmatch.startp[0]
4816 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004817 if (startcol > (colnr_T)len
4818 || str + startcol <= regmatch.startp[0])
4819 {
4820 match = FALSE;
4821 break;
4822 }
4823 }
4824 }
4825
4826 if (match)
4827 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004828 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004829 {
4830 listitem_T *li1 = rettv->vval.v_list->lv_first;
4831 listitem_T *li2 = li1->li_next;
4832 listitem_T *li3 = li2->li_next;
4833 listitem_T *li4 = li3->li_next;
4834
4835 vim_free(li1->li_tv.vval.v_string);
4836 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4837 (int)(regmatch.endp[0] - regmatch.startp[0]));
4838 li3->li_tv.vval.v_number =
4839 (varnumber_T)(regmatch.startp[0] - expr);
4840 li4->li_tv.vval.v_number =
4841 (varnumber_T)(regmatch.endp[0] - expr);
4842 if (l != NULL)
4843 li2->li_tv.vval.v_number = (varnumber_T)idx;
4844 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004845 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004846 {
4847 int i;
4848
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004849 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850 for (i = 0; i < NSUBEXP; ++i)
4851 {
4852 if (regmatch.endp[i] == NULL)
4853 {
4854 if (list_append_string(rettv->vval.v_list,
4855 (char_u *)"", 0) == FAIL)
4856 break;
4857 }
4858 else if (list_append_string(rettv->vval.v_list,
4859 regmatch.startp[i],
4860 (int)(regmatch.endp[i] - regmatch.startp[i]))
4861 == FAIL)
4862 break;
4863 }
4864 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004865 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004866 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004867 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004868 if (l != NULL)
4869 copy_tv(&li->li_tv, rettv);
4870 else
4871 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4872 (int)(regmatch.endp[0] - regmatch.startp[0]));
4873 }
4874 else if (l != NULL)
4875 rettv->vval.v_number = idx;
4876 else
4877 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004878 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004879 rettv->vval.v_number =
4880 (varnumber_T)(regmatch.startp[0] - str);
4881 else
4882 rettv->vval.v_number =
4883 (varnumber_T)(regmatch.endp[0] - str);
4884 rettv->vval.v_number += (varnumber_T)(str - expr);
4885 }
4886 }
4887 vim_regfree(regmatch.regprog);
4888 }
4889
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004890theend:
4891 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004892 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004893 listitem_remove(rettv->vval.v_list,
4894 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004895 vim_free(tofree);
4896 p_cpo = save_cpo;
4897}
4898
4899/*
4900 * "match()" function
4901 */
4902 static void
4903f_match(typval_T *argvars, typval_T *rettv)
4904{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004905 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906}
4907
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908/*
4909 * "matchend()" function
4910 */
4911 static void
4912f_matchend(typval_T *argvars, typval_T *rettv)
4913{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004914 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915}
4916
4917/*
4918 * "matchlist()" function
4919 */
4920 static void
4921f_matchlist(typval_T *argvars, typval_T *rettv)
4922{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004923 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004924}
4925
4926/*
4927 * "matchstr()" function
4928 */
4929 static void
4930f_matchstr(typval_T *argvars, typval_T *rettv)
4931{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004932 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933}
4934
4935/*
4936 * "matchstrpos()" function
4937 */
4938 static void
4939f_matchstrpos(typval_T *argvars, typval_T *rettv)
4940{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004941 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942}
4943
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004944 static void
4945max_min(typval_T *argvars, typval_T *rettv, int domax)
4946{
4947 varnumber_T n = 0;
4948 varnumber_T i;
4949 int error = FALSE;
4950
4951 if (argvars[0].v_type == VAR_LIST)
4952 {
4953 list_T *l;
4954 listitem_T *li;
4955
4956 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004957 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004959 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004960 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004961 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4962 n = l->lv_u.nonmat.lv_start;
4963 else
4964 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4965 * l->lv_u.nonmat.lv_stride;
4966 }
4967 else
4968 {
4969 li = l->lv_first;
4970 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004971 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004972 n = tv_get_number_chk(&li->li_tv, &error);
4973 for (;;)
4974 {
4975 li = li->li_next;
4976 if (li == NULL)
4977 break;
4978 i = tv_get_number_chk(&li->li_tv, &error);
4979 if (domax ? i > n : i < n)
4980 n = i;
4981 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004982 }
4983 }
4984 }
4985 }
4986 else if (argvars[0].v_type == VAR_DICT)
4987 {
4988 dict_T *d;
4989 int first = TRUE;
4990 hashitem_T *hi;
4991 int todo;
4992
4993 d = argvars[0].vval.v_dict;
4994 if (d != NULL)
4995 {
4996 todo = (int)d->dv_hashtab.ht_used;
4997 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4998 {
4999 if (!HASHITEM_EMPTY(hi))
5000 {
5001 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005002 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005003 if (first)
5004 {
5005 n = i;
5006 first = FALSE;
5007 }
5008 else if (domax ? i > n : i < n)
5009 n = i;
5010 }
5011 }
5012 }
5013 }
5014 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005015 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005016 rettv->vval.v_number = error ? 0 : n;
5017}
5018
5019/*
5020 * "max()" function
5021 */
5022 static void
5023f_max(typval_T *argvars, typval_T *rettv)
5024{
5025 max_min(argvars, rettv, TRUE);
5026}
5027
5028/*
5029 * "min()" function
5030 */
5031 static void
5032f_min(typval_T *argvars, typval_T *rettv)
5033{
5034 max_min(argvars, rettv, FALSE);
5035}
5036
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037#if defined(FEAT_MZSCHEME) || defined(PROTO)
5038/*
5039 * "mzeval()" function
5040 */
5041 static void
5042f_mzeval(typval_T *argvars, typval_T *rettv)
5043{
5044 char_u *str;
5045 char_u buf[NUMBUFLEN];
5046
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005047 if (check_restricted() || check_secure())
5048 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005049 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005050 do_mzeval(str, rettv);
5051}
5052
5053 void
5054mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5055{
5056 typval_T argvars[3];
5057
5058 argvars[0].v_type = VAR_STRING;
5059 argvars[0].vval.v_string = name;
5060 copy_tv(args, &argvars[1]);
5061 argvars[2].v_type = VAR_UNKNOWN;
5062 f_call(argvars, rettv);
5063 clear_tv(&argvars[1]);
5064}
5065#endif
5066
5067/*
5068 * "nextnonblank()" function
5069 */
5070 static void
5071f_nextnonblank(typval_T *argvars, typval_T *rettv)
5072{
5073 linenr_T lnum;
5074
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005075 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076 {
5077 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5078 {
5079 lnum = 0;
5080 break;
5081 }
5082 if (*skipwhite(ml_get(lnum)) != NUL)
5083 break;
5084 }
5085 rettv->vval.v_number = lnum;
5086}
5087
5088/*
5089 * "nr2char()" function
5090 */
5091 static void
5092f_nr2char(typval_T *argvars, typval_T *rettv)
5093{
5094 char_u buf[NUMBUFLEN];
5095
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096 if (has_mbyte)
5097 {
5098 int utf8 = 0;
5099
5100 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005101 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005103 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005105 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106 }
5107 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005109 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110 buf[1] = NUL;
5111 }
5112 rettv->v_type = VAR_STRING;
5113 rettv->vval.v_string = vim_strsave(buf);
5114}
5115
5116/*
5117 * "or(expr, expr)" function
5118 */
5119 static void
5120f_or(typval_T *argvars, typval_T *rettv)
5121{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005122 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5123 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005124}
5125
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005126#ifdef FEAT_PERL
5127/*
5128 * "perleval()" function
5129 */
5130 static void
5131f_perleval(typval_T *argvars, typval_T *rettv)
5132{
5133 char_u *str;
5134 char_u buf[NUMBUFLEN];
5135
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005136 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 do_perleval(str, rettv);
5138}
5139#endif
5140
5141#ifdef FEAT_FLOAT
5142/*
5143 * "pow()" function
5144 */
5145 static void
5146f_pow(typval_T *argvars, typval_T *rettv)
5147{
5148 float_T fx = 0.0, fy = 0.0;
5149
5150 rettv->v_type = VAR_FLOAT;
5151 if (get_float_arg(argvars, &fx) == OK
5152 && get_float_arg(&argvars[1], &fy) == OK)
5153 rettv->vval.v_float = pow(fx, fy);
5154 else
5155 rettv->vval.v_float = 0.0;
5156}
5157#endif
5158
5159/*
5160 * "prevnonblank()" function
5161 */
5162 static void
5163f_prevnonblank(typval_T *argvars, typval_T *rettv)
5164{
5165 linenr_T lnum;
5166
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005167 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005168 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5169 lnum = 0;
5170 else
5171 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5172 --lnum;
5173 rettv->vval.v_number = lnum;
5174}
5175
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005176// This dummy va_list is here because:
5177// - passing a NULL pointer doesn't work when va_list isn't a pointer
5178// - locally in the function results in a "used before set" warning
5179// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005180static va_list ap;
5181
5182/*
5183 * "printf()" function
5184 */
5185 static void
5186f_printf(typval_T *argvars, typval_T *rettv)
5187{
5188 char_u buf[NUMBUFLEN];
5189 int len;
5190 char_u *s;
5191 int saved_did_emsg = did_emsg;
5192 char *fmt;
5193
5194 rettv->v_type = VAR_STRING;
5195 rettv->vval.v_string = NULL;
5196
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005197 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005198 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005199 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005200 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 if (!did_emsg)
5202 {
5203 s = alloc(len + 1);
5204 if (s != NULL)
5205 {
5206 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005207 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5208 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 }
5210 }
5211 did_emsg |= saved_did_emsg;
5212}
5213
5214/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005215 * "pum_getpos()" function
5216 */
5217 static void
5218f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5219{
5220 if (rettv_dict_alloc(rettv) != OK)
5221 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005222 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005223}
5224
5225/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005226 * "pumvisible()" function
5227 */
5228 static void
5229f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5230{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005231 if (pum_visible())
5232 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005233}
5234
5235#ifdef FEAT_PYTHON3
5236/*
5237 * "py3eval()" function
5238 */
5239 static void
5240f_py3eval(typval_T *argvars, typval_T *rettv)
5241{
5242 char_u *str;
5243 char_u buf[NUMBUFLEN];
5244
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005245 if (check_restricted() || check_secure())
5246 return;
5247
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005248 if (p_pyx == 0)
5249 p_pyx = 3;
5250
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005251 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005252 do_py3eval(str, rettv);
5253}
5254#endif
5255
5256#ifdef FEAT_PYTHON
5257/*
5258 * "pyeval()" function
5259 */
5260 static void
5261f_pyeval(typval_T *argvars, typval_T *rettv)
5262{
5263 char_u *str;
5264 char_u buf[NUMBUFLEN];
5265
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005266 if (check_restricted() || check_secure())
5267 return;
5268
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005269 if (p_pyx == 0)
5270 p_pyx = 2;
5271
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005272 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005273 do_pyeval(str, rettv);
5274}
5275#endif
5276
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005277#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5278/*
5279 * "pyxeval()" function
5280 */
5281 static void
5282f_pyxeval(typval_T *argvars, typval_T *rettv)
5283{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005284 if (check_restricted() || check_secure())
5285 return;
5286
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005287# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5288 init_pyxversion();
5289 if (p_pyx == 2)
5290 f_pyeval(argvars, rettv);
5291 else
5292 f_py3eval(argvars, rettv);
5293# elif defined(FEAT_PYTHON)
5294 f_pyeval(argvars, rettv);
5295# elif defined(FEAT_PYTHON3)
5296 f_py3eval(argvars, rettv);
5297# endif
5298}
5299#endif
5300
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005301static UINT32_T srand_seed_for_testing = 0;
5302static int srand_seed_for_testing_is_used = FALSE;
5303
5304 static void
5305f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5306{
5307 if (argvars[0].v_type == VAR_UNKNOWN)
5308 srand_seed_for_testing_is_used = FALSE;
5309 else
5310 {
5311 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5312 srand_seed_for_testing_is_used = TRUE;
5313 }
5314}
5315
5316 static void
5317init_srand(UINT32_T *x)
5318{
5319#ifndef MSWIN
5320 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5321#endif
5322
5323 if (srand_seed_for_testing_is_used)
5324 {
5325 *x = srand_seed_for_testing;
5326 return;
5327 }
5328#ifndef MSWIN
5329 if (dev_urandom_state != FAIL)
5330 {
5331 int fd = open("/dev/urandom", O_RDONLY);
5332 struct {
5333 union {
5334 UINT32_T number;
5335 char bytes[sizeof(UINT32_T)];
5336 } contents;
5337 } buf;
5338
5339 // Attempt reading /dev/urandom.
5340 if (fd == -1)
5341 dev_urandom_state = FAIL;
5342 else
5343 {
5344 buf.contents.number = 0;
5345 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5346 != sizeof(UINT32_T))
5347 dev_urandom_state = FAIL;
5348 else
5349 {
5350 dev_urandom_state = OK;
5351 *x = buf.contents.number;
5352 }
5353 close(fd);
5354 }
5355 }
5356 if (dev_urandom_state != OK)
5357 // Reading /dev/urandom doesn't work, fall back to time().
5358#endif
5359 *x = vim_time();
5360}
5361
5362#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5363#define SPLITMIX32(x, z) ( \
5364 z = (x += 0x9e3779b9), \
5365 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5366 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5367 z ^ (z >> 16) \
5368 )
5369#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5370 result = ROTL(y * 5, 7) * 9; \
5371 t = y << 9; \
5372 z ^= x; \
5373 w ^= y; \
5374 y ^= z, x ^= w; \
5375 z ^= t; \
5376 w = ROTL(w, 11);
5377
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005378/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005379 * "rand()" function
5380 */
5381 static void
5382f_rand(typval_T *argvars, typval_T *rettv)
5383{
5384 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005385 static UINT32_T gx, gy, gz, gw;
5386 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005387 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005388 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005389
5390 if (argvars[0].v_type == VAR_UNKNOWN)
5391 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005392 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005393 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005394 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005395 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005396 init_srand(&x);
5397
5398 gx = SPLITMIX32(x, z);
5399 gy = SPLITMIX32(x, z);
5400 gz = SPLITMIX32(x, z);
5401 gw = SPLITMIX32(x, z);
5402 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005403 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005404
5405 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005406 }
5407 else if (argvars[0].v_type == VAR_LIST)
5408 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005409 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005410 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005411 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005412
5413 lx = list_find(l, 0L);
5414 ly = list_find(l, 1L);
5415 lz = list_find(l, 2L);
5416 lw = list_find(l, 3L);
5417 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5418 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5419 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5420 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5421 x = (UINT32_T)lx->li_tv.vval.v_number;
5422 y = (UINT32_T)ly->li_tv.vval.v_number;
5423 z = (UINT32_T)lz->li_tv.vval.v_number;
5424 w = (UINT32_T)lw->li_tv.vval.v_number;
5425
5426 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5427
5428 lx->li_tv.vval.v_number = (varnumber_T)x;
5429 ly->li_tv.vval.v_number = (varnumber_T)y;
5430 lz->li_tv.vval.v_number = (varnumber_T)z;
5431 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005432 }
5433 else
5434 goto theend;
5435
5436 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005437 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005438 return;
5439
5440theend:
5441 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005442 rettv->v_type = VAR_NUMBER;
5443 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005444}
5445
5446/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005447 * "srand()" function
5448 */
5449 static void
5450f_srand(typval_T *argvars, typval_T *rettv)
5451{
5452 UINT32_T x = 0, z;
5453
5454 if (rettv_list_alloc(rettv) == FAIL)
5455 return;
5456 if (argvars[0].v_type == VAR_UNKNOWN)
5457 {
5458 init_srand(&x);
5459 }
5460 else
5461 {
5462 int error = FALSE;
5463
5464 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5465 if (error)
5466 return;
5467 }
5468
5469 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5470 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5471 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5472 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5473}
5474
5475#undef ROTL
5476#undef SPLITMIX32
5477#undef SHUFFLE_XOSHIRO128STARSTAR
5478
5479/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005480 * "range()" function
5481 */
5482 static void
5483f_range(typval_T *argvars, typval_T *rettv)
5484{
5485 varnumber_T start;
5486 varnumber_T end;
5487 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005488 int error = FALSE;
5489
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005490 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491 if (argvars[1].v_type == VAR_UNKNOWN)
5492 {
5493 end = start - 1;
5494 start = 0;
5495 }
5496 else
5497 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005498 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005499 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005500 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005501 }
5502
5503 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005504 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005505 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005506 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005507 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005508 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005509 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005510 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005511 list_T *list = rettv->vval.v_list;
5512
5513 // Create a non-materialized list. This is much more efficient and
5514 // works with ":for". If used otherwise range_list_materialize() must
5515 // be called.
5516 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005517 list->lv_u.nonmat.lv_start = start;
5518 list->lv_u.nonmat.lv_end = end;
5519 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005520 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005521 }
5522}
5523
5524/*
5525 * If "list" is a non-materialized list then materialize it now.
5526 */
5527 void
5528range_list_materialize(list_T *list)
5529{
5530 if (list->lv_first == &range_list_item)
5531 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005532 varnumber_T start = list->lv_u.nonmat.lv_start;
5533 varnumber_T end = list->lv_u.nonmat.lv_end;
5534 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005535 varnumber_T i;
5536
5537 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005538 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005539 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005540 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005541 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5542 if (list_append_number(list, (varnumber_T)i) == FAIL)
5543 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544 }
5545}
5546
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005547 static void
5548return_register(int regname, typval_T *rettv)
5549{
5550 char_u buf[2] = {0, 0};
5551
5552 buf[0] = (char_u)regname;
5553 rettv->v_type = VAR_STRING;
5554 rettv->vval.v_string = vim_strsave(buf);
5555}
5556
5557/*
5558 * "reg_executing()" function
5559 */
5560 static void
5561f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5562{
5563 return_register(reg_executing, rettv);
5564}
5565
5566/*
5567 * "reg_recording()" function
5568 */
5569 static void
5570f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5571{
5572 return_register(reg_recording, rettv);
5573}
5574
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005575#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005576 static void
5577make_connection(void)
5578{
5579 if (X_DISPLAY == NULL
5580# ifdef FEAT_GUI
5581 && !gui.in_use
5582# endif
5583 )
5584 {
5585 x_force_connect = TRUE;
5586 setup_term_clip();
5587 x_force_connect = FALSE;
5588 }
5589}
5590
5591 static int
5592check_connection(void)
5593{
5594 make_connection();
5595 if (X_DISPLAY == NULL)
5596 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005597 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005598 return FAIL;
5599 }
5600 return OK;
5601}
5602#endif
5603
5604#ifdef FEAT_CLIENTSERVER
5605 static void
5606remote_common(typval_T *argvars, typval_T *rettv, int expr)
5607{
5608 char_u *server_name;
5609 char_u *keys;
5610 char_u *r = NULL;
5611 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005612 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005613# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005614 HWND w;
5615# else
5616 Window w;
5617# endif
5618
5619 if (check_restricted() || check_secure())
5620 return;
5621
5622# ifdef FEAT_X11
5623 if (check_connection() == FAIL)
5624 return;
5625# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005626 if (argvars[2].v_type != VAR_UNKNOWN
5627 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005628 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005629
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005630 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005632 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005633 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005634# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005635 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005636# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005637 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5638 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639# endif
5640 {
5641 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005642 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005643 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005644 vim_free(r);
5645 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005646 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005647 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005648 return;
5649 }
5650
5651 rettv->vval.v_string = r;
5652
5653 if (argvars[2].v_type != VAR_UNKNOWN)
5654 {
5655 dictitem_T v;
5656 char_u str[30];
5657 char_u *idvar;
5658
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005659 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005660 if (idvar != NULL && *idvar != NUL)
5661 {
5662 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5663 v.di_tv.v_type = VAR_STRING;
5664 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005665 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005666 vim_free(v.di_tv.vval.v_string);
5667 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005668 }
5669}
5670#endif
5671
5672/*
5673 * "remote_expr()" function
5674 */
5675 static void
5676f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5677{
5678 rettv->v_type = VAR_STRING;
5679 rettv->vval.v_string = NULL;
5680#ifdef FEAT_CLIENTSERVER
5681 remote_common(argvars, rettv, TRUE);
5682#endif
5683}
5684
5685/*
5686 * "remote_foreground()" function
5687 */
5688 static void
5689f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5690{
5691#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005692# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005693 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005694 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005695 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005696
5697 if (server_name != NULL)
5698 serverForeground(server_name);
5699 }
5700# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005701 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005702 argvars[1].v_type = VAR_STRING;
5703 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5704 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005705 rettv->v_type = VAR_STRING;
5706 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005707 remote_common(argvars, rettv, TRUE);
5708 vim_free(argvars[1].vval.v_string);
5709# endif
5710#endif
5711}
5712
5713 static void
5714f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5715{
5716#ifdef FEAT_CLIENTSERVER
5717 dictitem_T v;
5718 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005719# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005720 long_u n = 0;
5721# endif
5722 char_u *serverid;
5723
5724 if (check_restricted() || check_secure())
5725 {
5726 rettv->vval.v_number = -1;
5727 return;
5728 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005729 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005730 if (serverid == NULL)
5731 {
5732 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005733 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005735# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005736 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5737 if (n == 0)
5738 rettv->vval.v_number = -1;
5739 else
5740 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005741 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005742 rettv->vval.v_number = (s != NULL);
5743 }
5744# else
5745 if (check_connection() == FAIL)
5746 return;
5747
5748 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5749 serverStrToWin(serverid), &s);
5750# endif
5751
5752 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5753 {
5754 char_u *retvar;
5755
5756 v.di_tv.v_type = VAR_STRING;
5757 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005758 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005759 if (retvar != NULL)
5760 set_var(retvar, &v.di_tv, FALSE);
5761 vim_free(v.di_tv.vval.v_string);
5762 }
5763#else
5764 rettv->vval.v_number = -1;
5765#endif
5766}
5767
5768 static void
5769f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5770{
5771 char_u *r = NULL;
5772
5773#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005774 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005775
5776 if (serverid != NULL && !check_restricted() && !check_secure())
5777 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005778 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005779# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005780 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005781 long_u n = 0;
5782# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005783
5784 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005785 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005786
Bram Moolenaar4f974752019-02-17 17:44:42 +01005787# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005788 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5789 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005790 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005791 if (r == NULL)
5792# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005793 if (check_connection() == FAIL
5794 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5795 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005796# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005797 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005798 }
5799#endif
5800 rettv->v_type = VAR_STRING;
5801 rettv->vval.v_string = r;
5802}
5803
5804/*
5805 * "remote_send()" function
5806 */
5807 static void
5808f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5809{
5810 rettv->v_type = VAR_STRING;
5811 rettv->vval.v_string = NULL;
5812#ifdef FEAT_CLIENTSERVER
5813 remote_common(argvars, rettv, FALSE);
5814#endif
5815}
5816
5817/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005818 * "remote_startserver()" function
5819 */
5820 static void
5821f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5822{
5823#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005824 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005825
5826 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005827 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005828 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005829 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005830 else
5831 {
5832# ifdef FEAT_X11
5833 if (check_connection() == OK)
5834 serverRegisterName(X_DISPLAY, server);
5835# else
5836 serverSetName(server);
5837# endif
5838 }
5839#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005840 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005841#endif
5842}
5843
5844/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005845 * "rename({from}, {to})" function
5846 */
5847 static void
5848f_rename(typval_T *argvars, typval_T *rettv)
5849{
5850 char_u buf[NUMBUFLEN];
5851
5852 if (check_restricted() || check_secure())
5853 rettv->vval.v_number = -1;
5854 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005855 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5856 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005857}
5858
5859/*
5860 * "repeat()" function
5861 */
5862 static void
5863f_repeat(typval_T *argvars, typval_T *rettv)
5864{
5865 char_u *p;
5866 int n;
5867 int slen;
5868 int len;
5869 char_u *r;
5870 int i;
5871
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005872 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005873 if (argvars[0].v_type == VAR_LIST)
5874 {
5875 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5876 while (n-- > 0)
5877 if (list_extend(rettv->vval.v_list,
5878 argvars[0].vval.v_list, NULL) == FAIL)
5879 break;
5880 }
5881 else
5882 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005883 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005884 rettv->v_type = VAR_STRING;
5885 rettv->vval.v_string = NULL;
5886
5887 slen = (int)STRLEN(p);
5888 len = slen * n;
5889 if (len <= 0)
5890 return;
5891
5892 r = alloc(len + 1);
5893 if (r != NULL)
5894 {
5895 for (i = 0; i < n; i++)
5896 mch_memmove(r + i * slen, p, (size_t)slen);
5897 r[len] = NUL;
5898 }
5899
5900 rettv->vval.v_string = r;
5901 }
5902}
5903
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005904#define SP_NOMOVE 0x01 // don't move cursor
5905#define SP_REPEAT 0x02 // repeat to find outer pair
5906#define SP_RETCOUNT 0x04 // return matchcount
5907#define SP_SETPCMARK 0x08 // set previous context mark
5908#define SP_START 0x10 // accept match at start position
5909#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5910#define SP_END 0x40 // leave cursor at end of match
5911#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005913/*
5914 * Get flags for a search function.
5915 * Possibly sets "p_ws".
5916 * Returns BACKWARD, FORWARD or zero (for an error).
5917 */
5918 static int
5919get_search_arg(typval_T *varp, int *flagsp)
5920{
5921 int dir = FORWARD;
5922 char_u *flags;
5923 char_u nbuf[NUMBUFLEN];
5924 int mask;
5925
5926 if (varp->v_type != VAR_UNKNOWN)
5927 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005928 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005929 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005930 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005931 while (*flags != NUL)
5932 {
5933 switch (*flags)
5934 {
5935 case 'b': dir = BACKWARD; break;
5936 case 'w': p_ws = TRUE; break;
5937 case 'W': p_ws = FALSE; break;
5938 default: mask = 0;
5939 if (flagsp != NULL)
5940 switch (*flags)
5941 {
5942 case 'c': mask = SP_START; break;
5943 case 'e': mask = SP_END; break;
5944 case 'm': mask = SP_RETCOUNT; break;
5945 case 'n': mask = SP_NOMOVE; break;
5946 case 'p': mask = SP_SUBPAT; break;
5947 case 'r': mask = SP_REPEAT; break;
5948 case 's': mask = SP_SETPCMARK; break;
5949 case 'z': mask = SP_COLUMN; break;
5950 }
5951 if (mask == 0)
5952 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005953 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005954 dir = 0;
5955 }
5956 else
5957 *flagsp |= mask;
5958 }
5959 if (dir == 0)
5960 break;
5961 ++flags;
5962 }
5963 }
5964 return dir;
5965}
5966
5967/*
5968 * Shared by search() and searchpos() functions.
5969 */
5970 static int
5971search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5972{
5973 int flags;
5974 char_u *pat;
5975 pos_T pos;
5976 pos_T save_cursor;
5977 int save_p_ws = p_ws;
5978 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005979 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005980 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005981#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005982 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005983 long time_limit = 0;
5984#endif
5985 int options = SEARCH_KEEP;
5986 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005987 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005988
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005989 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005990 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005991 if (dir == 0)
5992 goto theend;
5993 flags = *flagsp;
5994 if (flags & SP_START)
5995 options |= SEARCH_START;
5996 if (flags & SP_END)
5997 options |= SEARCH_END;
5998 if (flags & SP_COLUMN)
5999 options |= SEARCH_COL;
6000
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006001 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006002 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6003 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006004 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006005 if (lnum_stop < 0)
6006 goto theend;
6007#ifdef FEAT_RELTIME
6008 if (argvars[3].v_type != VAR_UNKNOWN)
6009 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006010 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006011 if (time_limit < 0)
6012 goto theend;
6013 }
6014#endif
6015 }
6016
6017#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006018 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006019 profile_setlimit(time_limit, &tm);
6020#endif
6021
6022 /*
6023 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6024 * Check to make sure only those flags are set.
6025 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6026 * flags cannot be set. Check for that condition also.
6027 */
6028 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6029 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6030 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006031 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006032 goto theend;
6033 }
6034
6035 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006036 vim_memset(&sia, 0, sizeof(sia));
6037 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6038#ifdef FEAT_RELTIME
6039 sia.sa_tm = &tm;
6040#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006041 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006042 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006043 if (subpatnum != FAIL)
6044 {
6045 if (flags & SP_SUBPAT)
6046 retval = subpatnum;
6047 else
6048 retval = pos.lnum;
6049 if (flags & SP_SETPCMARK)
6050 setpcmark();
6051 curwin->w_cursor = pos;
6052 if (match_pos != NULL)
6053 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006054 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006055 match_pos->lnum = pos.lnum;
6056 match_pos->col = pos.col + 1;
6057 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006058 // "/$" will put the cursor after the end of the line, may need to
6059 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006060 check_cursor();
6061 }
6062
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006063 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006064 if (flags & SP_NOMOVE)
6065 curwin->w_cursor = save_cursor;
6066 else
6067 curwin->w_set_curswant = TRUE;
6068theend:
6069 p_ws = save_p_ws;
6070
6071 return retval;
6072}
6073
6074#ifdef FEAT_FLOAT
6075
6076/*
6077 * round() is not in C90, use ceil() or floor() instead.
6078 */
6079 float_T
6080vim_round(float_T f)
6081{
6082 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6083}
6084
6085/*
6086 * "round({float})" function
6087 */
6088 static void
6089f_round(typval_T *argvars, typval_T *rettv)
6090{
6091 float_T f = 0.0;
6092
6093 rettv->v_type = VAR_FLOAT;
6094 if (get_float_arg(argvars, &f) == OK)
6095 rettv->vval.v_float = vim_round(f);
6096 else
6097 rettv->vval.v_float = 0.0;
6098}
6099#endif
6100
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006101#ifdef FEAT_RUBY
6102/*
6103 * "rubyeval()" function
6104 */
6105 static void
6106f_rubyeval(typval_T *argvars, typval_T *rettv)
6107{
6108 char_u *str;
6109 char_u buf[NUMBUFLEN];
6110
6111 str = tv_get_string_buf(&argvars[0], buf);
6112 do_rubyeval(str, rettv);
6113}
6114#endif
6115
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006116/*
6117 * "screenattr()" function
6118 */
6119 static void
6120f_screenattr(typval_T *argvars, typval_T *rettv)
6121{
6122 int row;
6123 int col;
6124 int c;
6125
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006126 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6127 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006128 if (row < 0 || row >= screen_Rows
6129 || col < 0 || col >= screen_Columns)
6130 c = -1;
6131 else
6132 c = ScreenAttrs[LineOffset[row] + col];
6133 rettv->vval.v_number = c;
6134}
6135
6136/*
6137 * "screenchar()" function
6138 */
6139 static void
6140f_screenchar(typval_T *argvars, typval_T *rettv)
6141{
6142 int row;
6143 int col;
6144 int off;
6145 int c;
6146
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006147 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6148 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006149 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006150 c = -1;
6151 else
6152 {
6153 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006154 if (enc_utf8 && ScreenLinesUC[off] != 0)
6155 c = ScreenLinesUC[off];
6156 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006157 c = ScreenLines[off];
6158 }
6159 rettv->vval.v_number = c;
6160}
6161
6162/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006163 * "screenchars()" function
6164 */
6165 static void
6166f_screenchars(typval_T *argvars, typval_T *rettv)
6167{
6168 int row;
6169 int col;
6170 int off;
6171 int c;
6172 int i;
6173
6174 if (rettv_list_alloc(rettv) == FAIL)
6175 return;
6176 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6177 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6178 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6179 return;
6180
6181 off = LineOffset[row] + col;
6182 if (enc_utf8 && ScreenLinesUC[off] != 0)
6183 c = ScreenLinesUC[off];
6184 else
6185 c = ScreenLines[off];
6186 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6187
6188 if (enc_utf8)
6189
6190 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6191 list_append_number(rettv->vval.v_list,
6192 (varnumber_T)ScreenLinesC[i][off]);
6193}
6194
6195/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 * "screencol()" function
6197 *
6198 * First column is 1 to be consistent with virtcol().
6199 */
6200 static void
6201f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6202{
6203 rettv->vval.v_number = screen_screencol() + 1;
6204}
6205
6206/*
6207 * "screenrow()" function
6208 */
6209 static void
6210f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6211{
6212 rettv->vval.v_number = screen_screenrow() + 1;
6213}
6214
6215/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006216 * "screenstring()" function
6217 */
6218 static void
6219f_screenstring(typval_T *argvars, typval_T *rettv)
6220{
6221 int row;
6222 int col;
6223 int off;
6224 int c;
6225 int i;
6226 char_u buf[MB_MAXBYTES + 1];
6227 int buflen = 0;
6228
6229 rettv->vval.v_string = NULL;
6230 rettv->v_type = VAR_STRING;
6231
6232 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6233 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6234 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6235 return;
6236
6237 off = LineOffset[row] + col;
6238 if (enc_utf8 && ScreenLinesUC[off] != 0)
6239 c = ScreenLinesUC[off];
6240 else
6241 c = ScreenLines[off];
6242 buflen += mb_char2bytes(c, buf);
6243
6244 if (enc_utf8)
6245 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6246 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6247
6248 buf[buflen] = NUL;
6249 rettv->vval.v_string = vim_strsave(buf);
6250}
6251
6252/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006253 * "search()" function
6254 */
6255 static void
6256f_search(typval_T *argvars, typval_T *rettv)
6257{
6258 int flags = 0;
6259
6260 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6261}
6262
6263/*
6264 * "searchdecl()" function
6265 */
6266 static void
6267f_searchdecl(typval_T *argvars, typval_T *rettv)
6268{
6269 int locally = 1;
6270 int thisblock = 0;
6271 int error = FALSE;
6272 char_u *name;
6273
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006274 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006275
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006276 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006277 if (argvars[1].v_type != VAR_UNKNOWN)
6278 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006279 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006280 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006281 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006282 }
6283 if (!error && name != NULL)
6284 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6285 locally, thisblock, SEARCH_KEEP) == FAIL;
6286}
6287
6288/*
6289 * Used by searchpair() and searchpairpos()
6290 */
6291 static int
6292searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6293{
6294 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006295 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006296 int save_p_ws = p_ws;
6297 int dir;
6298 int flags = 0;
6299 char_u nbuf1[NUMBUFLEN];
6300 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006301 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006302 long lnum_stop = 0;
6303 long time_limit = 0;
6304
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006305 // Get the three pattern arguments: start, middle, end. Will result in an
6306 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006307 spat = tv_get_string_chk(&argvars[0]);
6308 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6309 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006310 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006311 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006312
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006313 // Handle the optional fourth argument: flags
6314 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315 if (dir == 0)
6316 goto theend;
6317
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006318 // Don't accept SP_END or SP_SUBPAT.
6319 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006320 if ((flags & (SP_END | SP_SUBPAT)) != 0
6321 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6322 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006323 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006324 goto theend;
6325 }
6326
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006327 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006328 if (flags & SP_REPEAT)
6329 p_ws = FALSE;
6330
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006331 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006332 if (argvars[3].v_type == VAR_UNKNOWN
6333 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006334 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335 else
6336 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006337 skip = &argvars[4];
6338 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6339 && skip->v_type != VAR_STRING)
6340 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006341 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006342 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006343 goto theend;
6344 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345 if (argvars[5].v_type != VAR_UNKNOWN)
6346 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006347 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006348 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006349 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006350 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006352 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353#ifdef FEAT_RELTIME
6354 if (argvars[6].v_type != VAR_UNKNOWN)
6355 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006356 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006357 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006358 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006359 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006360 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006361 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006362 }
6363#endif
6364 }
6365 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366
6367 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6368 match_pos, lnum_stop, time_limit);
6369
6370theend:
6371 p_ws = save_p_ws;
6372
6373 return retval;
6374}
6375
6376/*
6377 * "searchpair()" function
6378 */
6379 static void
6380f_searchpair(typval_T *argvars, typval_T *rettv)
6381{
6382 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6383}
6384
6385/*
6386 * "searchpairpos()" function
6387 */
6388 static void
6389f_searchpairpos(typval_T *argvars, typval_T *rettv)
6390{
6391 pos_T match_pos;
6392 int lnum = 0;
6393 int col = 0;
6394
6395 if (rettv_list_alloc(rettv) == FAIL)
6396 return;
6397
6398 if (searchpair_cmn(argvars, &match_pos) > 0)
6399 {
6400 lnum = match_pos.lnum;
6401 col = match_pos.col;
6402 }
6403
6404 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6405 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6406}
6407
6408/*
6409 * Search for a start/middle/end thing.
6410 * Used by searchpair(), see its documentation for the details.
6411 * Returns 0 or -1 for no match,
6412 */
6413 long
6414do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006415 char_u *spat, // start pattern
6416 char_u *mpat, // middle pattern
6417 char_u *epat, // end pattern
6418 int dir, // BACKWARD or FORWARD
6419 typval_T *skip, // skip expression
6420 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006422 linenr_T lnum_stop, // stop at this line if not zero
6423 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006424{
6425 char_u *save_cpo;
6426 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6427 long retval = 0;
6428 pos_T pos;
6429 pos_T firstpos;
6430 pos_T foundpos;
6431 pos_T save_cursor;
6432 pos_T save_pos;
6433 int n;
6434 int r;
6435 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006436 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006437 int err;
6438 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006439#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006440 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006441#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006443 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006444 save_cpo = p_cpo;
6445 p_cpo = empty_option;
6446
6447#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006448 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006449 profile_setlimit(time_limit, &tm);
6450#endif
6451
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006452 // Make two search patterns: start/end (pat2, for in nested pairs) and
6453 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006454 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6455 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006456 if (pat2 == NULL || pat3 == NULL)
6457 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006458 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006459 if (*mpat == NUL)
6460 STRCPY(pat3, pat2);
6461 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006462 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006463 spat, epat, mpat);
6464 if (flags & SP_START)
6465 options |= SEARCH_START;
6466
Bram Moolenaar48570482017-10-30 21:48:41 +01006467 if (skip != NULL)
6468 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006469 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006470 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6471 use_skip = skip->vval.v_string != NULL
6472 && *skip->vval.v_string != NUL;
6473 }
6474
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 save_cursor = curwin->w_cursor;
6476 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006477 CLEAR_POS(&firstpos);
6478 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006479 pat = pat3;
6480 for (;;)
6481 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006482 searchit_arg_T sia;
6483
6484 vim_memset(&sia, 0, sizeof(sia));
6485 sia.sa_stop_lnum = lnum_stop;
6486#ifdef FEAT_RELTIME
6487 sia.sa_tm = &tm;
6488#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006489 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006490 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006491 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006492 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006493 break;
6494
6495 if (firstpos.lnum == 0)
6496 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006497 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006498 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006499 // Found the same position again. Can happen with a pattern that
6500 // has "\zs" at the end and searching backwards. Advance one
6501 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502 if (dir == BACKWARD)
6503 decl(&pos);
6504 else
6505 incl(&pos);
6506 }
6507 foundpos = pos;
6508
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006509 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006510 options &= ~SEARCH_START;
6511
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006512 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006513 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006514 {
6515 save_pos = curwin->w_cursor;
6516 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006517 err = FALSE;
6518 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006519 curwin->w_cursor = save_pos;
6520 if (err)
6521 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006522 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006523 curwin->w_cursor = save_cursor;
6524 retval = -1;
6525 break;
6526 }
6527 if (r)
6528 continue;
6529 }
6530
6531 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6532 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006533 // Found end when searching backwards or start when searching
6534 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006535 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006536 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537 }
6538 else
6539 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006540 // Found end when searching forward or start when searching
6541 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006542 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006543 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006544 }
6545
6546 if (nest == 0)
6547 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006548 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006549 if (flags & SP_RETCOUNT)
6550 ++retval;
6551 else
6552 retval = pos.lnum;
6553 if (flags & SP_SETPCMARK)
6554 setpcmark();
6555 curwin->w_cursor = pos;
6556 if (!(flags & SP_REPEAT))
6557 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006558 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006559 }
6560 }
6561
6562 if (match_pos != NULL)
6563 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006564 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006565 match_pos->lnum = curwin->w_cursor.lnum;
6566 match_pos->col = curwin->w_cursor.col + 1;
6567 }
6568
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006569 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 if ((flags & SP_NOMOVE) || retval == 0)
6571 curwin->w_cursor = save_cursor;
6572
6573theend:
6574 vim_free(pat2);
6575 vim_free(pat3);
6576 if (p_cpo == empty_option)
6577 p_cpo = save_cpo;
6578 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006579 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006580 free_string_option(save_cpo);
6581
6582 return retval;
6583}
6584
6585/*
6586 * "searchpos()" function
6587 */
6588 static void
6589f_searchpos(typval_T *argvars, typval_T *rettv)
6590{
6591 pos_T match_pos;
6592 int lnum = 0;
6593 int col = 0;
6594 int n;
6595 int flags = 0;
6596
6597 if (rettv_list_alloc(rettv) == FAIL)
6598 return;
6599
6600 n = search_cmn(argvars, &match_pos, &flags);
6601 if (n > 0)
6602 {
6603 lnum = match_pos.lnum;
6604 col = match_pos.col;
6605 }
6606
6607 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6608 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6609 if (flags & SP_SUBPAT)
6610 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6611}
6612
6613 static void
6614f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6615{
6616#ifdef FEAT_CLIENTSERVER
6617 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006618 char_u *server = tv_get_string_chk(&argvars[0]);
6619 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620
6621 rettv->vval.v_number = -1;
6622 if (server == NULL || reply == NULL)
6623 return;
6624 if (check_restricted() || check_secure())
6625 return;
6626# ifdef FEAT_X11
6627 if (check_connection() == FAIL)
6628 return;
6629# endif
6630
6631 if (serverSendReply(server, reply) < 0)
6632 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006633 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006634 return;
6635 }
6636 rettv->vval.v_number = 0;
6637#else
6638 rettv->vval.v_number = -1;
6639#endif
6640}
6641
6642 static void
6643f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6644{
6645 char_u *r = NULL;
6646
6647#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006648# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006649 r = serverGetVimNames();
6650# else
6651 make_connection();
6652 if (X_DISPLAY != NULL)
6653 r = serverGetVimNames(X_DISPLAY);
6654# endif
6655#endif
6656 rettv->v_type = VAR_STRING;
6657 rettv->vval.v_string = r;
6658}
6659
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006660 static void
6661f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6662{
6663 dict_T *d;
6664 dictitem_T *di;
6665 char_u *csearch;
6666
6667 if (argvars[0].v_type != VAR_DICT)
6668 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006669 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006670 return;
6671 }
6672
6673 if ((d = argvars[0].vval.v_dict) != NULL)
6674 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006675 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006676 if (csearch != NULL)
6677 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006678 if (enc_utf8)
6679 {
6680 int pcc[MAX_MCO];
6681 int c = utfc_ptr2char(csearch, pcc);
6682
6683 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6684 }
6685 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006687 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688 }
6689
6690 di = dict_find(d, (char_u *)"forward", -1);
6691 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006692 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693 ? FORWARD : BACKWARD);
6694
6695 di = dict_find(d, (char_u *)"until", -1);
6696 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006697 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006698 }
6699}
6700
6701/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006702 * "setenv()" function
6703 */
6704 static void
6705f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6706{
6707 char_u namebuf[NUMBUFLEN];
6708 char_u valbuf[NUMBUFLEN];
6709 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6710
6711 if (argvars[1].v_type == VAR_SPECIAL
6712 && argvars[1].vval.v_number == VVAL_NULL)
6713 vim_unsetenv(name);
6714 else
6715 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6716}
6717
6718/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006719 * "setfperm({fname}, {mode})" function
6720 */
6721 static void
6722f_setfperm(typval_T *argvars, typval_T *rettv)
6723{
6724 char_u *fname;
6725 char_u modebuf[NUMBUFLEN];
6726 char_u *mode_str;
6727 int i;
6728 int mask;
6729 int mode = 0;
6730
6731 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006732 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006733 if (fname == NULL)
6734 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006735 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006736 if (mode_str == NULL)
6737 return;
6738 if (STRLEN(mode_str) != 9)
6739 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006740 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741 return;
6742 }
6743
6744 mask = 1;
6745 for (i = 8; i >= 0; --i)
6746 {
6747 if (mode_str[i] != '-')
6748 mode |= mask;
6749 mask = mask << 1;
6750 }
6751 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6752}
6753
6754/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006755 * "setpos()" function
6756 */
6757 static void
6758f_setpos(typval_T *argvars, typval_T *rettv)
6759{
6760 pos_T pos;
6761 int fnum;
6762 char_u *name;
6763 colnr_T curswant = -1;
6764
6765 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006766 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006767 if (name != NULL)
6768 {
6769 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6770 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006771 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006772 pos.col = 0;
6773 if (name[0] == '.' && name[1] == NUL)
6774 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006775 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006776 curwin->w_cursor = pos;
6777 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006778 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006779 curwin->w_curswant = curswant - 1;
6780 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006781 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006782 check_cursor();
6783 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006784 }
6785 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6786 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006787 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006788 if (setmark_pos(name[1], &pos, fnum) == OK)
6789 rettv->vval.v_number = 0;
6790 }
6791 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006792 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006793 }
6794 }
6795}
6796
6797/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006798 * "setreg()" function
6799 */
6800 static void
6801f_setreg(typval_T *argvars, typval_T *rettv)
6802{
6803 int regname;
6804 char_u *strregname;
6805 char_u *stropt;
6806 char_u *strval;
6807 int append;
6808 char_u yank_type;
6809 long block_len;
6810
6811 block_len = -1;
6812 yank_type = MAUTO;
6813 append = FALSE;
6814
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006815 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006816 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006817
6818 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006819 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006820 regname = *strregname;
6821 if (regname == 0 || regname == '@')
6822 regname = '"';
6823
6824 if (argvars[2].v_type != VAR_UNKNOWN)
6825 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006826 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006827 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006828 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006829 for (; *stropt != NUL; ++stropt)
6830 switch (*stropt)
6831 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006832 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006833 append = TRUE;
6834 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006835 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836 yank_type = MCHAR;
6837 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006838 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006839 yank_type = MLINE;
6840 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006841 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842 yank_type = MBLOCK;
6843 if (VIM_ISDIGIT(stropt[1]))
6844 {
6845 ++stropt;
6846 block_len = getdigits(&stropt) - 1;
6847 --stropt;
6848 }
6849 break;
6850 }
6851 }
6852
6853 if (argvars[1].v_type == VAR_LIST)
6854 {
6855 char_u **lstval;
6856 char_u **allocval;
6857 char_u buf[NUMBUFLEN];
6858 char_u **curval;
6859 char_u **curallocval;
6860 list_T *ll = argvars[1].vval.v_list;
6861 listitem_T *li;
6862 int len;
6863
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006864 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865 len = ll == NULL ? 0 : ll->lv_len;
6866
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006867 // First half: use for pointers to result lines; second half: use for
6868 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006869 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870 if (lstval == NULL)
6871 return;
6872 curval = lstval;
6873 allocval = lstval + len + 2;
6874 curallocval = allocval;
6875
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006876 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006878 range_list_materialize(ll);
6879 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006881 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882 if (strval == NULL)
6883 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006884 if (strval == buf)
6885 {
6886 // Need to make a copy, next tv_get_string_buf_chk() will
6887 // overwrite the string.
6888 strval = vim_strsave(buf);
6889 if (strval == NULL)
6890 goto free_lstval;
6891 *curallocval++ = strval;
6892 }
6893 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006894 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006895 }
6896 *curval++ = NULL;
6897
6898 write_reg_contents_lst(regname, lstval, -1,
6899 append, yank_type, block_len);
6900free_lstval:
6901 while (curallocval > allocval)
6902 vim_free(*--curallocval);
6903 vim_free(lstval);
6904 }
6905 else
6906 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006907 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 if (strval == NULL)
6909 return;
6910 write_reg_contents_ex(regname, strval, -1,
6911 append, yank_type, block_len);
6912 }
6913 rettv->vval.v_number = 0;
6914}
6915
6916/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006917 * "settagstack()" function
6918 */
6919 static void
6920f_settagstack(typval_T *argvars, typval_T *rettv)
6921{
6922 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6923 win_T *wp;
6924 dict_T *d;
6925 int action = 'r';
6926
6927 rettv->vval.v_number = -1;
6928
6929 // first argument: window number or id
6930 wp = find_win_by_nr_or_id(&argvars[0]);
6931 if (wp == NULL)
6932 return;
6933
6934 // second argument: dict with items to set in the tag stack
6935 if (argvars[1].v_type != VAR_DICT)
6936 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006937 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006938 return;
6939 }
6940 d = argvars[1].vval.v_dict;
6941 if (d == NULL)
6942 return;
6943
6944 // third argument: action - 'a' for append and 'r' for replace.
6945 // default is to replace the stack.
6946 if (argvars[2].v_type == VAR_UNKNOWN)
6947 action = 'r';
6948 else if (argvars[2].v_type == VAR_STRING)
6949 {
6950 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006951 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006952 if (actstr == NULL)
6953 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006954 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6955 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006956 action = *actstr;
6957 else
6958 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006959 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006960 return;
6961 }
6962 }
6963 else
6964 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006965 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006966 return;
6967 }
6968
6969 if (set_tagstack(wp, d, action) == OK)
6970 rettv->vval.v_number = 0;
6971}
6972
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006973#ifdef FEAT_CRYPT
6974/*
6975 * "sha256({string})" function
6976 */
6977 static void
6978f_sha256(typval_T *argvars, typval_T *rettv)
6979{
6980 char_u *p;
6981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006982 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006983 rettv->vval.v_string = vim_strsave(
6984 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6985 rettv->v_type = VAR_STRING;
6986}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006987#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006988
6989/*
6990 * "shellescape({string})" function
6991 */
6992 static void
6993f_shellescape(typval_T *argvars, typval_T *rettv)
6994{
Bram Moolenaar20615522017-06-05 18:46:26 +02006995 int do_special = non_zero_arg(&argvars[1]);
6996
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006997 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006998 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006999 rettv->v_type = VAR_STRING;
7000}
7001
7002/*
7003 * shiftwidth() function
7004 */
7005 static void
7006f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7007{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007008 rettv->vval.v_number = 0;
7009
7010 if (argvars[0].v_type != VAR_UNKNOWN)
7011 {
7012 long col;
7013
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007014 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007015 if (col < 0)
7016 return; // type error; errmsg already given
7017#ifdef FEAT_VARTABS
7018 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7019 return;
7020#endif
7021 }
7022
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007023 rettv->vval.v_number = get_sw_value(curbuf);
7024}
7025
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007026#ifdef FEAT_FLOAT
7027/*
7028 * "sin()" function
7029 */
7030 static void
7031f_sin(typval_T *argvars, typval_T *rettv)
7032{
7033 float_T f = 0.0;
7034
7035 rettv->v_type = VAR_FLOAT;
7036 if (get_float_arg(argvars, &f) == OK)
7037 rettv->vval.v_float = sin(f);
7038 else
7039 rettv->vval.v_float = 0.0;
7040}
7041
7042/*
7043 * "sinh()" function
7044 */
7045 static void
7046f_sinh(typval_T *argvars, typval_T *rettv)
7047{
7048 float_T f = 0.0;
7049
7050 rettv->v_type = VAR_FLOAT;
7051 if (get_float_arg(argvars, &f) == OK)
7052 rettv->vval.v_float = sinh(f);
7053 else
7054 rettv->vval.v_float = 0.0;
7055}
7056#endif
7057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007058/*
7059 * "soundfold({word})" function
7060 */
7061 static void
7062f_soundfold(typval_T *argvars, typval_T *rettv)
7063{
7064 char_u *s;
7065
7066 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007067 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068#ifdef FEAT_SPELL
7069 rettv->vval.v_string = eval_soundfold(s);
7070#else
7071 rettv->vval.v_string = vim_strsave(s);
7072#endif
7073}
7074
7075/*
7076 * "spellbadword()" function
7077 */
7078 static void
7079f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7080{
7081 char_u *word = (char_u *)"";
7082 hlf_T attr = HLF_COUNT;
7083 int len = 0;
7084
7085 if (rettv_list_alloc(rettv) == FAIL)
7086 return;
7087
7088#ifdef FEAT_SPELL
7089 if (argvars[0].v_type == VAR_UNKNOWN)
7090 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007091 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7093 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007094 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007095 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007096 curwin->w_set_curswant = TRUE;
7097 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007098 }
7099 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7100 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007101 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007102 int capcol = -1;
7103
7104 if (str != NULL)
7105 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007106 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007107 while (*str != NUL)
7108 {
7109 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7110 if (attr != HLF_COUNT)
7111 {
7112 word = str;
7113 break;
7114 }
7115 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007116 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007117 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 }
7119 }
7120 }
7121#endif
7122
7123 list_append_string(rettv->vval.v_list, word, len);
7124 list_append_string(rettv->vval.v_list, (char_u *)(
7125 attr == HLF_SPB ? "bad" :
7126 attr == HLF_SPR ? "rare" :
7127 attr == HLF_SPL ? "local" :
7128 attr == HLF_SPC ? "caps" :
7129 ""), -1);
7130}
7131
7132/*
7133 * "spellsuggest()" function
7134 */
7135 static void
7136f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7137{
7138#ifdef FEAT_SPELL
7139 char_u *str;
7140 int typeerr = FALSE;
7141 int maxcount;
7142 garray_T ga;
7143 int i;
7144 listitem_T *li;
7145 int need_capital = FALSE;
7146#endif
7147
7148 if (rettv_list_alloc(rettv) == FAIL)
7149 return;
7150
7151#ifdef FEAT_SPELL
7152 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7153 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007154 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007155 if (argvars[1].v_type != VAR_UNKNOWN)
7156 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007157 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007158 if (maxcount <= 0)
7159 return;
7160 if (argvars[2].v_type != VAR_UNKNOWN)
7161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007162 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007163 if (typeerr)
7164 return;
7165 }
7166 }
7167 else
7168 maxcount = 25;
7169
7170 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7171
7172 for (i = 0; i < ga.ga_len; ++i)
7173 {
7174 str = ((char_u **)ga.ga_data)[i];
7175
7176 li = listitem_alloc();
7177 if (li == NULL)
7178 vim_free(str);
7179 else
7180 {
7181 li->li_tv.v_type = VAR_STRING;
7182 li->li_tv.v_lock = 0;
7183 li->li_tv.vval.v_string = str;
7184 list_append(rettv->vval.v_list, li);
7185 }
7186 }
7187 ga_clear(&ga);
7188 }
7189#endif
7190}
7191
7192 static void
7193f_split(typval_T *argvars, typval_T *rettv)
7194{
7195 char_u *str;
7196 char_u *end;
7197 char_u *pat = NULL;
7198 regmatch_T regmatch;
7199 char_u patbuf[NUMBUFLEN];
7200 char_u *save_cpo;
7201 int match;
7202 colnr_T col = 0;
7203 int keepempty = FALSE;
7204 int typeerr = FALSE;
7205
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007206 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007207 save_cpo = p_cpo;
7208 p_cpo = (char_u *)"";
7209
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007210 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007211 if (argvars[1].v_type != VAR_UNKNOWN)
7212 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007213 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007214 if (pat == NULL)
7215 typeerr = TRUE;
7216 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007217 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218 }
7219 if (pat == NULL || *pat == NUL)
7220 pat = (char_u *)"[\\x01- ]\\+";
7221
7222 if (rettv_list_alloc(rettv) == FAIL)
7223 return;
7224 if (typeerr)
7225 return;
7226
7227 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7228 if (regmatch.regprog != NULL)
7229 {
7230 regmatch.rm_ic = FALSE;
7231 while (*str != NUL || keepempty)
7232 {
7233 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007234 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007235 else
7236 match = vim_regexec_nl(&regmatch, str, col);
7237 if (match)
7238 end = regmatch.startp[0];
7239 else
7240 end = str + STRLEN(str);
7241 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7242 && *str != NUL && match && end < regmatch.endp[0]))
7243 {
7244 if (list_append_string(rettv->vval.v_list, str,
7245 (int)(end - str)) == FAIL)
7246 break;
7247 }
7248 if (!match)
7249 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007250 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007251 if (regmatch.endp[0] > str)
7252 col = 0;
7253 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007254 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007256 str = regmatch.endp[0];
7257 }
7258
7259 vim_regfree(regmatch.regprog);
7260 }
7261
7262 p_cpo = save_cpo;
7263}
7264
7265#ifdef FEAT_FLOAT
7266/*
7267 * "sqrt()" function
7268 */
7269 static void
7270f_sqrt(typval_T *argvars, typval_T *rettv)
7271{
7272 float_T f = 0.0;
7273
7274 rettv->v_type = VAR_FLOAT;
7275 if (get_float_arg(argvars, &f) == OK)
7276 rettv->vval.v_float = sqrt(f);
7277 else
7278 rettv->vval.v_float = 0.0;
7279}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007280#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007281
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007282#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007283/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007284 * "str2float()" function
7285 */
7286 static void
7287f_str2float(typval_T *argvars, typval_T *rettv)
7288{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007289 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007290 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007291
Bram Moolenaar08243d22017-01-10 16:12:29 +01007292 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007293 p = skipwhite(p + 1);
7294 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007295 if (isneg)
7296 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007297 rettv->v_type = VAR_FLOAT;
7298}
7299#endif
7300
7301/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007302 * "str2list()" function
7303 */
7304 static void
7305f_str2list(typval_T *argvars, typval_T *rettv)
7306{
7307 char_u *p;
7308 int utf8 = FALSE;
7309
7310 if (rettv_list_alloc(rettv) == FAIL)
7311 return;
7312
7313 if (argvars[1].v_type != VAR_UNKNOWN)
7314 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7315
7316 p = tv_get_string(&argvars[0]);
7317
7318 if (has_mbyte || utf8)
7319 {
7320 int (*ptr2len)(char_u *);
7321 int (*ptr2char)(char_u *);
7322
7323 if (utf8 || enc_utf8)
7324 {
7325 ptr2len = utf_ptr2len;
7326 ptr2char = utf_ptr2char;
7327 }
7328 else
7329 {
7330 ptr2len = mb_ptr2len;
7331 ptr2char = mb_ptr2char;
7332 }
7333
7334 for ( ; *p != NUL; p += (*ptr2len)(p))
7335 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7336 }
7337 else
7338 for ( ; *p != NUL; ++p)
7339 list_append_number(rettv->vval.v_list, *p);
7340}
7341
7342/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007343 * "str2nr()" function
7344 */
7345 static void
7346f_str2nr(typval_T *argvars, typval_T *rettv)
7347{
7348 int base = 10;
7349 char_u *p;
7350 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007351 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007352 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007353
7354 if (argvars[1].v_type != VAR_UNKNOWN)
7355 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007356 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007357 if (base != 2 && base != 8 && base != 10 && base != 16)
7358 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007359 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007360 return;
7361 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007362 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7363 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364 }
7365
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007366 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007367 isneg = (*p == '-');
7368 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007369 p = skipwhite(p + 1);
7370 switch (base)
7371 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007372 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7373 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7374 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007375 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007376 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7377 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007378 if (isneg)
7379 rettv->vval.v_number = -n;
7380 else
7381 rettv->vval.v_number = n;
7382
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383}
7384
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007385/*
7386 * "strgetchar()" function
7387 */
7388 static void
7389f_strgetchar(typval_T *argvars, typval_T *rettv)
7390{
7391 char_u *str;
7392 int len;
7393 int error = FALSE;
7394 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007395 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396
7397 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007398 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007399 if (str == NULL)
7400 return;
7401 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007402 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403 if (error)
7404 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405
Bram Moolenaar13505972019-01-24 15:04:48 +01007406 while (charidx >= 0 && byteidx < len)
7407 {
7408 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007410 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7411 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007413 --charidx;
7414 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007415 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007416}
7417
7418/*
7419 * "stridx()" function
7420 */
7421 static void
7422f_stridx(typval_T *argvars, typval_T *rettv)
7423{
7424 char_u buf[NUMBUFLEN];
7425 char_u *needle;
7426 char_u *haystack;
7427 char_u *save_haystack;
7428 char_u *pos;
7429 int start_idx;
7430
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007431 needle = tv_get_string_chk(&argvars[1]);
7432 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433 rettv->vval.v_number = -1;
7434 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007435 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007436
7437 if (argvars[2].v_type != VAR_UNKNOWN)
7438 {
7439 int error = FALSE;
7440
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007441 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007442 if (error || start_idx >= (int)STRLEN(haystack))
7443 return;
7444 if (start_idx >= 0)
7445 haystack += start_idx;
7446 }
7447
7448 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7449 if (pos != NULL)
7450 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7451}
7452
7453/*
7454 * "string()" function
7455 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007456 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007457f_string(typval_T *argvars, typval_T *rettv)
7458{
7459 char_u *tofree;
7460 char_u numbuf[NUMBUFLEN];
7461
7462 rettv->v_type = VAR_STRING;
7463 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7464 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007465 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007466 if (rettv->vval.v_string != NULL && tofree == NULL)
7467 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7468}
7469
7470/*
7471 * "strlen()" function
7472 */
7473 static void
7474f_strlen(typval_T *argvars, typval_T *rettv)
7475{
7476 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007477 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478}
7479
7480/*
7481 * "strchars()" function
7482 */
7483 static void
7484f_strchars(typval_T *argvars, typval_T *rettv)
7485{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007486 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007487 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488 varnumber_T len = 0;
7489 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007490
7491 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007492 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007493 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007494 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 else
7496 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007497 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7498 while (*s != NUL)
7499 {
7500 func_mb_ptr2char_adv(&s);
7501 ++len;
7502 }
7503 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 }
7505}
7506
7507/*
7508 * "strdisplaywidth()" function
7509 */
7510 static void
7511f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7512{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007513 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007514 int col = 0;
7515
7516 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007517 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518
7519 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7520}
7521
7522/*
7523 * "strwidth()" function
7524 */
7525 static void
7526f_strwidth(typval_T *argvars, typval_T *rettv)
7527{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007528 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529
Bram Moolenaar13505972019-01-24 15:04:48 +01007530 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531}
7532
7533/*
7534 * "strcharpart()" function
7535 */
7536 static void
7537f_strcharpart(typval_T *argvars, typval_T *rettv)
7538{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007539 char_u *p;
7540 int nchar;
7541 int nbyte = 0;
7542 int charlen;
7543 int len = 0;
7544 int slen;
7545 int error = FALSE;
7546
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007547 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007548 slen = (int)STRLEN(p);
7549
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007550 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007551 if (!error)
7552 {
7553 if (nchar > 0)
7554 while (nchar > 0 && nbyte < slen)
7555 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007556 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007557 --nchar;
7558 }
7559 else
7560 nbyte = nchar;
7561 if (argvars[2].v_type != VAR_UNKNOWN)
7562 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007563 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007564 while (charlen > 0 && nbyte + len < slen)
7565 {
7566 int off = nbyte + len;
7567
7568 if (off < 0)
7569 len += 1;
7570 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007571 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007572 --charlen;
7573 }
7574 }
7575 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007576 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 }
7578
7579 /*
7580 * Only return the overlap between the specified part and the actual
7581 * string.
7582 */
7583 if (nbyte < 0)
7584 {
7585 len += nbyte;
7586 nbyte = 0;
7587 }
7588 else if (nbyte > slen)
7589 nbyte = slen;
7590 if (len < 0)
7591 len = 0;
7592 else if (nbyte + len > slen)
7593 len = slen - nbyte;
7594
7595 rettv->v_type = VAR_STRING;
7596 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007597}
7598
7599/*
7600 * "strpart()" function
7601 */
7602 static void
7603f_strpart(typval_T *argvars, typval_T *rettv)
7604{
7605 char_u *p;
7606 int n;
7607 int len;
7608 int slen;
7609 int error = FALSE;
7610
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007611 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007612 slen = (int)STRLEN(p);
7613
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007614 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007615 if (error)
7616 len = 0;
7617 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007618 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007620 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007621
7622 /*
7623 * Only return the overlap between the specified part and the actual
7624 * string.
7625 */
7626 if (n < 0)
7627 {
7628 len += n;
7629 n = 0;
7630 }
7631 else if (n > slen)
7632 n = slen;
7633 if (len < 0)
7634 len = 0;
7635 else if (n + len > slen)
7636 len = slen - n;
7637
7638 rettv->v_type = VAR_STRING;
7639 rettv->vval.v_string = vim_strnsave(p + n, len);
7640}
7641
7642/*
7643 * "strridx()" function
7644 */
7645 static void
7646f_strridx(typval_T *argvars, typval_T *rettv)
7647{
7648 char_u buf[NUMBUFLEN];
7649 char_u *needle;
7650 char_u *haystack;
7651 char_u *rest;
7652 char_u *lastmatch = NULL;
7653 int haystack_len, end_idx;
7654
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007655 needle = tv_get_string_chk(&argvars[1]);
7656 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657
7658 rettv->vval.v_number = -1;
7659 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007660 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007661
7662 haystack_len = (int)STRLEN(haystack);
7663 if (argvars[2].v_type != VAR_UNKNOWN)
7664 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007665 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007666 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007668 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007669 }
7670 else
7671 end_idx = haystack_len;
7672
7673 if (*needle == NUL)
7674 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007675 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007676 lastmatch = haystack + end_idx;
7677 }
7678 else
7679 {
7680 for (rest = haystack; *rest != '\0'; ++rest)
7681 {
7682 rest = (char_u *)strstr((char *)rest, (char *)needle);
7683 if (rest == NULL || rest > haystack + end_idx)
7684 break;
7685 lastmatch = rest;
7686 }
7687 }
7688
7689 if (lastmatch == NULL)
7690 rettv->vval.v_number = -1;
7691 else
7692 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7693}
7694
7695/*
7696 * "strtrans()" function
7697 */
7698 static void
7699f_strtrans(typval_T *argvars, typval_T *rettv)
7700{
7701 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007702 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007703}
7704
7705/*
7706 * "submatch()" function
7707 */
7708 static void
7709f_submatch(typval_T *argvars, typval_T *rettv)
7710{
7711 int error = FALSE;
7712 int no;
7713 int retList = 0;
7714
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007715 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716 if (error)
7717 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007718 if (no < 0 || no >= NSUBEXP)
7719 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007720 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007721 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007722 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007723 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007724 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725 if (error)
7726 return;
7727
7728 if (retList == 0)
7729 {
7730 rettv->v_type = VAR_STRING;
7731 rettv->vval.v_string = reg_submatch(no);
7732 }
7733 else
7734 {
7735 rettv->v_type = VAR_LIST;
7736 rettv->vval.v_list = reg_submatch_list(no);
7737 }
7738}
7739
7740/*
7741 * "substitute()" function
7742 */
7743 static void
7744f_substitute(typval_T *argvars, typval_T *rettv)
7745{
7746 char_u patbuf[NUMBUFLEN];
7747 char_u subbuf[NUMBUFLEN];
7748 char_u flagsbuf[NUMBUFLEN];
7749
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007750 char_u *str = tv_get_string_chk(&argvars[0]);
7751 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007752 char_u *sub = NULL;
7753 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007754 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007755
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007756 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7757 expr = &argvars[2];
7758 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007759 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007760
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007761 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007762 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7763 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007764 rettv->vval.v_string = NULL;
7765 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007766 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767}
7768
7769/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007770 * "swapinfo(swap_filename)" function
7771 */
7772 static void
7773f_swapinfo(typval_T *argvars, typval_T *rettv)
7774{
7775 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007776 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007777}
7778
7779/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007780 * "swapname(expr)" function
7781 */
7782 static void
7783f_swapname(typval_T *argvars, typval_T *rettv)
7784{
7785 buf_T *buf;
7786
7787 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007788 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007789 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7790 || buf->b_ml.ml_mfp->mf_fname == NULL)
7791 rettv->vval.v_string = NULL;
7792 else
7793 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7794}
7795
7796/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007797 * "synID(lnum, col, trans)" function
7798 */
7799 static void
7800f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7801{
7802 int id = 0;
7803#ifdef FEAT_SYN_HL
7804 linenr_T lnum;
7805 colnr_T col;
7806 int trans;
7807 int transerr = FALSE;
7808
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007809 lnum = tv_get_lnum(argvars); // -1 on type error
7810 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007811 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007812
7813 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7814 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7815 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7816#endif
7817
7818 rettv->vval.v_number = id;
7819}
7820
7821/*
7822 * "synIDattr(id, what [, mode])" function
7823 */
7824 static void
7825f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7826{
7827 char_u *p = NULL;
7828#ifdef FEAT_SYN_HL
7829 int id;
7830 char_u *what;
7831 char_u *mode;
7832 char_u modebuf[NUMBUFLEN];
7833 int modec;
7834
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007835 id = (int)tv_get_number(&argvars[0]);
7836 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007837 if (argvars[2].v_type != VAR_UNKNOWN)
7838 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007839 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 modec = TOLOWER_ASC(mode[0]);
7841 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007842 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007843 }
7844 else
7845 {
7846#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7847 if (USE_24BIT)
7848 modec = 'g';
7849 else
7850#endif
7851 if (t_colors > 1)
7852 modec = 'c';
7853 else
7854 modec = 't';
7855 }
7856
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857 switch (TOLOWER_ASC(what[0]))
7858 {
7859 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007860 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007862 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007863 p = highlight_has_attr(id, HL_BOLD, modec);
7864 break;
7865
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007866 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867 p = highlight_color(id, what, modec);
7868 break;
7869
7870 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007871 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007872 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007873 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 p = highlight_has_attr(id, HL_ITALIC, modec);
7875 break;
7876
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007877 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007878 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007879 break;
7880
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007881 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882 p = highlight_has_attr(id, HL_INVERSE, modec);
7883 break;
7884
7885 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007886 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007888 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007889 else if (TOLOWER_ASC(what[1]) == 't' &&
7890 TOLOWER_ASC(what[2]) == 'r')
7891 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007892 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 p = highlight_has_attr(id, HL_STANDOUT, modec);
7894 break;
7895
7896 case 'u':
7897 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007898 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007899 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7900 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007901 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007902 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7903 break;
7904 }
7905
7906 if (p != NULL)
7907 p = vim_strsave(p);
7908#endif
7909 rettv->v_type = VAR_STRING;
7910 rettv->vval.v_string = p;
7911}
7912
7913/*
7914 * "synIDtrans(id)" function
7915 */
7916 static void
7917f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7918{
7919 int id;
7920
7921#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007922 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007923
7924 if (id > 0)
7925 id = syn_get_final_id(id);
7926 else
7927#endif
7928 id = 0;
7929
7930 rettv->vval.v_number = id;
7931}
7932
7933/*
7934 * "synconcealed(lnum, col)" function
7935 */
7936 static void
7937f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7938{
7939#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7940 linenr_T lnum;
7941 colnr_T col;
7942 int syntax_flags = 0;
7943 int cchar;
7944 int matchid = 0;
7945 char_u str[NUMBUFLEN];
7946#endif
7947
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007948 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007949
7950#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007951 lnum = tv_get_lnum(argvars); // -1 on type error
7952 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007953
7954 vim_memset(str, NUL, sizeof(str));
7955
7956 if (rettv_list_alloc(rettv) != FAIL)
7957 {
7958 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7959 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7960 && curwin->w_p_cole > 0)
7961 {
7962 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7963 syntax_flags = get_syntax_info(&matchid);
7964
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007965 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007966 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7967 {
7968 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007969 if (cchar == NUL && curwin->w_p_cole == 1)
7970 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007971 if (cchar != NUL)
7972 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007973 if (has_mbyte)
7974 (*mb_char2bytes)(cchar, str);
7975 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976 str[0] = cchar;
7977 }
7978 }
7979 }
7980
7981 list_append_number(rettv->vval.v_list,
7982 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007983 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984 list_append_string(rettv->vval.v_list, str, -1);
7985 list_append_number(rettv->vval.v_list, matchid);
7986 }
7987#endif
7988}
7989
7990/*
7991 * "synstack(lnum, col)" function
7992 */
7993 static void
7994f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7995{
7996#ifdef FEAT_SYN_HL
7997 linenr_T lnum;
7998 colnr_T col;
7999 int i;
8000 int id;
8001#endif
8002
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008003 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004
8005#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008006 lnum = tv_get_lnum(argvars); // -1 on type error
8007 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008
8009 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8010 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8011 && rettv_list_alloc(rettv) != FAIL)
8012 {
8013 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8014 for (i = 0; ; ++i)
8015 {
8016 id = syn_get_stack_item(i);
8017 if (id < 0)
8018 break;
8019 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8020 break;
8021 }
8022 }
8023#endif
8024}
8025
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008026/*
8027 * "tabpagebuflist()" function
8028 */
8029 static void
8030f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8031{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008032 tabpage_T *tp;
8033 win_T *wp = NULL;
8034
8035 if (argvars[0].v_type == VAR_UNKNOWN)
8036 wp = firstwin;
8037 else
8038 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008039 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008040 if (tp != NULL)
8041 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8042 }
8043 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8044 {
8045 for (; wp != NULL; wp = wp->w_next)
8046 if (list_append_number(rettv->vval.v_list,
8047 wp->w_buffer->b_fnum) == FAIL)
8048 break;
8049 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050}
8051
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008052/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053 * "tagfiles()" function
8054 */
8055 static void
8056f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8057{
8058 char_u *fname;
8059 tagname_T tn;
8060 int first;
8061
8062 if (rettv_list_alloc(rettv) == FAIL)
8063 return;
8064 fname = alloc(MAXPATHL);
8065 if (fname == NULL)
8066 return;
8067
8068 for (first = TRUE; ; first = FALSE)
8069 if (get_tagfname(&tn, first, fname) == FAIL
8070 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8071 break;
8072 tagname_free(&tn);
8073 vim_free(fname);
8074}
8075
8076/*
8077 * "taglist()" function
8078 */
8079 static void
8080f_taglist(typval_T *argvars, typval_T *rettv)
8081{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008082 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083 char_u *tag_pattern;
8084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008085 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086
8087 rettv->vval.v_number = FALSE;
8088 if (*tag_pattern == NUL)
8089 return;
8090
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008091 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008092 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008093 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008094 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095}
8096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008097#ifdef FEAT_FLOAT
8098/*
8099 * "tan()" function
8100 */
8101 static void
8102f_tan(typval_T *argvars, typval_T *rettv)
8103{
8104 float_T f = 0.0;
8105
8106 rettv->v_type = VAR_FLOAT;
8107 if (get_float_arg(argvars, &f) == OK)
8108 rettv->vval.v_float = tan(f);
8109 else
8110 rettv->vval.v_float = 0.0;
8111}
8112
8113/*
8114 * "tanh()" function
8115 */
8116 static void
8117f_tanh(typval_T *argvars, typval_T *rettv)
8118{
8119 float_T f = 0.0;
8120
8121 rettv->v_type = VAR_FLOAT;
8122 if (get_float_arg(argvars, &f) == OK)
8123 rettv->vval.v_float = tanh(f);
8124 else
8125 rettv->vval.v_float = 0.0;
8126}
8127#endif
8128
8129/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 * "tolower(string)" function
8131 */
8132 static void
8133f_tolower(typval_T *argvars, typval_T *rettv)
8134{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008135 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008136 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137}
8138
8139/*
8140 * "toupper(string)" function
8141 */
8142 static void
8143f_toupper(typval_T *argvars, typval_T *rettv)
8144{
8145 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008146 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008147}
8148
8149/*
8150 * "tr(string, fromstr, tostr)" function
8151 */
8152 static void
8153f_tr(typval_T *argvars, typval_T *rettv)
8154{
8155 char_u *in_str;
8156 char_u *fromstr;
8157 char_u *tostr;
8158 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 int inlen;
8160 int fromlen;
8161 int tolen;
8162 int idx;
8163 char_u *cpstr;
8164 int cplen;
8165 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008166 char_u buf[NUMBUFLEN];
8167 char_u buf2[NUMBUFLEN];
8168 garray_T ga;
8169
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008170 in_str = tv_get_string(&argvars[0]);
8171 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8172 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008173
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008174 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008175 rettv->v_type = VAR_STRING;
8176 rettv->vval.v_string = NULL;
8177 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008178 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 ga_init2(&ga, (int)sizeof(char), 80);
8180
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008181 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008182 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008183 if (STRLEN(fromstr) != STRLEN(tostr))
8184 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008185error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008186 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008187 ga_clear(&ga);
8188 return;
8189 }
8190
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008191 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192 while (*in_str != NUL)
8193 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008194 if (has_mbyte)
8195 {
8196 inlen = (*mb_ptr2len)(in_str);
8197 cpstr = in_str;
8198 cplen = inlen;
8199 idx = 0;
8200 for (p = fromstr; *p != NUL; p += fromlen)
8201 {
8202 fromlen = (*mb_ptr2len)(p);
8203 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8204 {
8205 for (p = tostr; *p != NUL; p += tolen)
8206 {
8207 tolen = (*mb_ptr2len)(p);
8208 if (idx-- == 0)
8209 {
8210 cplen = tolen;
8211 cpstr = p;
8212 break;
8213 }
8214 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008215 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008216 goto error;
8217 break;
8218 }
8219 ++idx;
8220 }
8221
8222 if (first && cpstr == in_str)
8223 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008224 // Check that fromstr and tostr have the same number of
8225 // (multi-byte) characters. Done only once when a character
8226 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008227 first = FALSE;
8228 for (p = tostr; *p != NUL; p += tolen)
8229 {
8230 tolen = (*mb_ptr2len)(p);
8231 --idx;
8232 }
8233 if (idx != 0)
8234 goto error;
8235 }
8236
8237 (void)ga_grow(&ga, cplen);
8238 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8239 ga.ga_len += cplen;
8240
8241 in_str += inlen;
8242 }
8243 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008244 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008245 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008246 p = vim_strchr(fromstr, *in_str);
8247 if (p != NULL)
8248 ga_append(&ga, tostr[p - fromstr]);
8249 else
8250 ga_append(&ga, *in_str);
8251 ++in_str;
8252 }
8253 }
8254
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008255 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008256 (void)ga_grow(&ga, 1);
8257 ga_append(&ga, NUL);
8258
8259 rettv->vval.v_string = ga.ga_data;
8260}
8261
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008262/*
8263 * "trim({expr})" function
8264 */
8265 static void
8266f_trim(typval_T *argvars, typval_T *rettv)
8267{
8268 char_u buf1[NUMBUFLEN];
8269 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008270 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008271 char_u *mask = NULL;
8272 char_u *tail;
8273 char_u *prev;
8274 char_u *p;
8275 int c1;
8276
8277 rettv->v_type = VAR_STRING;
8278 if (head == NULL)
8279 {
8280 rettv->vval.v_string = NULL;
8281 return;
8282 }
8283
8284 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008285 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008286
8287 while (*head != NUL)
8288 {
8289 c1 = PTR2CHAR(head);
8290 if (mask == NULL)
8291 {
8292 if (c1 > ' ' && c1 != 0xa0)
8293 break;
8294 }
8295 else
8296 {
8297 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8298 if (c1 == PTR2CHAR(p))
8299 break;
8300 if (*p == NUL)
8301 break;
8302 }
8303 MB_PTR_ADV(head);
8304 }
8305
8306 for (tail = head + STRLEN(head); tail > head; tail = prev)
8307 {
8308 prev = tail;
8309 MB_PTR_BACK(head, prev);
8310 c1 = PTR2CHAR(prev);
8311 if (mask == NULL)
8312 {
8313 if (c1 > ' ' && c1 != 0xa0)
8314 break;
8315 }
8316 else
8317 {
8318 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8319 if (c1 == PTR2CHAR(p))
8320 break;
8321 if (*p == NUL)
8322 break;
8323 }
8324 }
8325 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8326}
8327
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008328#ifdef FEAT_FLOAT
8329/*
8330 * "trunc({float})" function
8331 */
8332 static void
8333f_trunc(typval_T *argvars, typval_T *rettv)
8334{
8335 float_T f = 0.0;
8336
8337 rettv->v_type = VAR_FLOAT;
8338 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008339 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008340 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8341 else
8342 rettv->vval.v_float = 0.0;
8343}
8344#endif
8345
8346/*
8347 * "type(expr)" function
8348 */
8349 static void
8350f_type(typval_T *argvars, typval_T *rettv)
8351{
8352 int n = -1;
8353
8354 switch (argvars[0].v_type)
8355 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008356 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8357 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008358 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008359 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8360 case VAR_LIST: n = VAR_TYPE_LIST; break;
8361 case VAR_DICT: n = VAR_TYPE_DICT; break;
8362 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8363 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8364 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008365 case VAR_JOB: n = VAR_TYPE_JOB; break;
8366 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008367 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008368 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008369 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008370 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371 n = -1;
8372 break;
8373 }
8374 rettv->vval.v_number = n;
8375}
8376
8377/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008378 * "virtcol(string)" function
8379 */
8380 static void
8381f_virtcol(typval_T *argvars, typval_T *rettv)
8382{
8383 colnr_T vcol = 0;
8384 pos_T *fp;
8385 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008386 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008387
8388 fp = var2fpos(&argvars[0], FALSE, &fnum);
8389 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8390 && fnum == curbuf->b_fnum)
8391 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008392 // Limit the column to a valid value, getvvcol() doesn't check.
8393 if (fp->col < 0)
8394 fp->col = 0;
8395 else
8396 {
8397 len = (int)STRLEN(ml_get(fp->lnum));
8398 if (fp->col > len)
8399 fp->col = len;
8400 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008401 getvvcol(curwin, fp, NULL, NULL, &vcol);
8402 ++vcol;
8403 }
8404
8405 rettv->vval.v_number = vcol;
8406}
8407
8408/*
8409 * "visualmode()" function
8410 */
8411 static void
8412f_visualmode(typval_T *argvars, typval_T *rettv)
8413{
8414 char_u str[2];
8415
8416 rettv->v_type = VAR_STRING;
8417 str[0] = curbuf->b_visual_mode_eval;
8418 str[1] = NUL;
8419 rettv->vval.v_string = vim_strsave(str);
8420
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008421 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008422 if (non_zero_arg(&argvars[0]))
8423 curbuf->b_visual_mode_eval = NUL;
8424}
8425
8426/*
8427 * "wildmenumode()" function
8428 */
8429 static void
8430f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8431{
8432#ifdef FEAT_WILDMENU
8433 if (wild_menu_showing)
8434 rettv->vval.v_number = 1;
8435#endif
8436}
8437
8438/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008439 * "windowsversion()" function
8440 */
8441 static void
8442f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8443{
8444 rettv->v_type = VAR_STRING;
8445 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8446}
8447
8448/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008449 * "wordcount()" function
8450 */
8451 static void
8452f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8453{
8454 if (rettv_dict_alloc(rettv) == FAIL)
8455 return;
8456 cursor_pos_info(rettv->vval.v_dict);
8457}
8458
8459/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008460 * "xor(expr, expr)" function
8461 */
8462 static void
8463f_xor(typval_T *argvars, typval_T *rettv)
8464{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008465 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8466 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008467}
8468
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008469#endif // FEAT_EVAL