blob: fdfdc0a06e9b9c1009aa5cbff9683c402da1f3d4 [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},
Bram Moolenaar0eabd4d2020-03-15 16:13:53 +0100649 {"menu_info", 1, 2, FEARG_1, ret_dict_any, f_menu_info},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100650 {"min", 1, 1, FEARG_1, ret_any, f_min},
651 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
652 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653#ifdef FEAT_MZSCHEME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100654 {"mzeval", 1, 1, FEARG_1, ret_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100656 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
657 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
658 {"or", 2, 2, FEARG_1, ret_number, f_or},
659 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200660#ifdef FEAT_PERL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100661 {"perleval", 1, 1, FEARG_1, ret_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100663#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100664 {"popup_atcursor", 2, 2, FEARG_1, ret_number, f_popup_atcursor},
665 {"popup_beval", 2, 2, FEARG_1, ret_number, f_popup_beval},
666 {"popup_clear", 0, 0, 0, ret_void, f_popup_clear},
667 {"popup_close", 1, 2, FEARG_1, ret_void, f_popup_close},
668 {"popup_create", 2, 2, FEARG_1, ret_number, f_popup_create},
669 {"popup_dialog", 2, 2, FEARG_1, ret_number, f_popup_dialog},
670 {"popup_filter_menu", 2, 2, 0, ret_number, f_popup_filter_menu},
671 {"popup_filter_yesno", 2, 2, 0, ret_number, f_popup_filter_yesno},
672 {"popup_findinfo", 0, 0, 0, ret_number, f_popup_findinfo},
673 {"popup_findpreview", 0, 0, 0, ret_number, f_popup_findpreview},
674 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, f_popup_getoptions},
675 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, f_popup_getpos},
676 {"popup_hide", 1, 1, FEARG_1, ret_void, f_popup_hide},
677 {"popup_locate", 2, 2, 0, ret_number, f_popup_locate},
678 {"popup_menu", 2, 2, FEARG_1, ret_number, f_popup_menu},
679 {"popup_move", 2, 2, FEARG_1, ret_void, f_popup_move},
680 {"popup_notification", 2, 2, FEARG_1, ret_number, f_popup_notification},
681 {"popup_setoptions", 2, 2, FEARG_1, ret_void, f_popup_setoptions},
682 {"popup_settext", 2, 2, FEARG_1, ret_void, f_popup_settext},
683 {"popup_show", 1, 1, FEARG_1, ret_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200684#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100686 {"pow", 2, 2, FEARG_1, ret_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200687#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100688 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
689 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200690#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100691 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, f_prompt_setcallback},
692 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, f_prompt_setinterrupt},
693 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200694#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100695#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100696 {"prop_add", 3, 3, FEARG_1, ret_void, f_prop_add},
697 {"prop_clear", 1, 3, FEARG_1, ret_void, f_prop_clear},
698 {"prop_find", 1, 2, FEARG_1, ret_dict_any, f_prop_find},
699 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, f_prop_list},
700 {"prop_remove", 1, 3, FEARG_1, ret_number, f_prop_remove},
701 {"prop_type_add", 2, 2, FEARG_1, ret_void, f_prop_type_add},
702 {"prop_type_change", 2, 2, FEARG_1, ret_void, f_prop_type_change},
703 {"prop_type_delete", 1, 2, FEARG_1, ret_void, f_prop_type_delete},
704 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, f_prop_type_get},
705 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100706#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100707 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
708 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200709#ifdef FEAT_PYTHON3
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100710 {"py3eval", 1, 1, FEARG_1, ret_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200711#endif
712#ifdef FEAT_PYTHON
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100713 {"pyeval", 1, 1, FEARG_1, ret_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200714#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100715#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100716 {"pyxeval", 1, 1, FEARG_1, ret_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100717#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100718 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
719 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
720 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
721 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
722 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
723 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
724 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200725#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100726 {"reltimefloat", 1, 1, FEARG_1, ret_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100728 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
729 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
730 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
731 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
732 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
733 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
734 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
735 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
736 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
737 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
738 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
739 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200740#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100741 {"round", 1, 1, FEARG_1, ret_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200742#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100743#ifdef FEAT_RUBY
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100744 {"rubyeval", 1, 1, FEARG_1, ret_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100745#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100746 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
747 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
748 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
749 {"screencol", 0, 0, 0, ret_number, f_screencol},
750 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
751 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
752 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
753 {"search", 1, 4, FEARG_1, ret_number, f_search},
754 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
755 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
756 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
757 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
758 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
759 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
760 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
761 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
762 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
763 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
764 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
765 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
766 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
767 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
768 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
769 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
770 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
771 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
772 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
773 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
774 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
775 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200776#ifdef FEAT_CRYPT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100777 {"sha256", 1, 1, FEARG_1, ret_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100779 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
780 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100781#ifdef FEAT_SIGNS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100782 {"sign_define", 1, 2, FEARG_1, ret_any, f_sign_define},
783 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, f_sign_getdefined},
784 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, f_sign_getplaced},
785 {"sign_jump", 3, 3, FEARG_1, ret_number, f_sign_jump},
786 {"sign_place", 4, 5, FEARG_1, ret_number, f_sign_place},
787 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, f_sign_placelist},
788 {"sign_undefine", 0, 1, FEARG_1, ret_number, f_sign_undefine},
789 {"sign_unplace", 1, 2, FEARG_1, ret_number, f_sign_unplace},
790 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100791#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100792 {"simplify", 1, 1, 0, ret_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100794 {"sin", 1, 1, FEARG_1, ret_float, f_sin},
795 {"sinh", 1, 1, FEARG_1, ret_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200796#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100797 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200798#ifdef FEAT_SOUND
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100799 {"sound_clear", 0, 0, 0, ret_void, f_sound_clear},
800 {"sound_playevent", 1, 2, FEARG_1, ret_number, f_sound_playevent},
801 {"sound_playfile", 1, 2, FEARG_1, ret_number, f_sound_playfile},
802 {"sound_stop", 1, 1, FEARG_1, ret_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200803#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100804 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
805 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
806 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
807 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100809 {"sqrt", 1, 1, FEARG_1, ret_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200810#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100811 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
812 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200813#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100814 {"str2float", 1, 1, FEARG_1, ret_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200815#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100816 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
817 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
818 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
819 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
820 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#ifdef HAVE_STRFTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100822 {"strftime", 1, 2, FEARG_1, ret_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100824 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
825 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
826 {"string", 1, 1, FEARG_1, ret_string, f_string},
827 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
828 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100829#ifdef HAVE_STRPTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100830 {"strptime", 2, 2, FEARG_1, ret_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100831#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100832 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
833 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
834 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
835 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
836 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
837 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
838 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
839 {"synID", 3, 3, 0, ret_number, f_synID},
840 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
841 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
842 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
843 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
844 {"system", 1, 2, FEARG_1, ret_string, f_system},
845 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
846 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
847 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
848 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
849 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
850 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100852 {"tan", 1, 1, FEARG_1, ret_float, f_tan},
853 {"tanh", 1, 1, FEARG_1, ret_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200854#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100855 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200856#ifdef FEAT_TERMINAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100857 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, f_term_dumpdiff},
858 {"term_dumpload", 1, 2, FEARG_1, ret_number, f_term_dumpload},
859 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, f_term_dumpwrite},
860 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200861# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100862 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200863# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100864 {"term_getattr", 2, 2, FEARG_1, ret_number, f_term_getattr},
865 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, f_term_getcursor},
866 {"term_getjob", 1, 1, FEARG_1, ret_job, f_term_getjob},
867 {"term_getline", 2, 2, FEARG_1, ret_string, f_term_getline},
868 {"term_getscrolled", 1, 1, FEARG_1, ret_number, f_term_getscrolled},
869 {"term_getsize", 1, 1, FEARG_1, ret_list_number, f_term_getsize},
870 {"term_getstatus", 1, 1, FEARG_1, ret_string, f_term_getstatus},
871 {"term_gettitle", 1, 1, FEARG_1, ret_string, f_term_gettitle},
872 {"term_gettty", 1, 2, FEARG_1, ret_string, f_term_gettty},
873 {"term_list", 0, 0, 0, ret_list_number, f_term_list},
874 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, f_term_scrape},
875 {"term_sendkeys", 2, 2, FEARG_1, ret_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200876# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100877 {"term_setansicolors", 2, 2, FEARG_1, ret_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200878# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100879 {"term_setapi", 2, 2, FEARG_1, ret_void, f_term_setapi},
880 {"term_setkill", 2, 2, FEARG_1, ret_void, f_term_setkill},
881 {"term_setrestore", 2, 2, FEARG_1, ret_void, f_term_setrestore},
882 {"term_setsize", 3, 3, FEARG_1, ret_void, f_term_setsize},
883 {"term_start", 1, 2, FEARG_1, ret_number, f_term_start},
884 {"term_wait", 1, 2, FEARG_1, ret_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200885#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100886 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
887 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
888 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
889 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
890 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
891 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
892 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
893 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200894#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100895 {"test_null_channel", 0, 0, 0, ret_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200896#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100897 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200898#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100899 {"test_null_job", 0, 0, 0, ret_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200900#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100901 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
902 {"test_null_partial", 0, 0, 0, ret_partial_void, f_test_null_partial},
903 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
904 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
905 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
906 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200907#ifdef FEAT_GUI
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100908 {"test_scrollbar", 3, 3, FEARG_2, ret_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200909#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100910 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
911 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
912 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
913 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
914 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200915#ifdef FEAT_TIMERS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100916 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, f_timer_info},
917 {"timer_pause", 2, 2, FEARG_1, ret_void, f_timer_pause},
918 {"timer_start", 2, 3, FEARG_1, ret_number, f_timer_start},
919 {"timer_stop", 1, 1, FEARG_1, ret_void, f_timer_stop},
920 {"timer_stopall", 0, 0, 0, ret_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200921#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100922 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
923 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
924 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
925 {"trim", 1, 2, FEARG_1, ret_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100927 {"trunc", 1, 1, FEARG_1, ret_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100929 {"type", 1, 1, FEARG_1, ret_number, f_type},
930 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
931 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
932 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
933 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
934 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
935 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
936 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
937 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
938 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
939 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
940 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
941 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
942 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
943 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
944 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
945 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
946 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
947 {"wincol", 0, 0, 0, ret_number, f_wincol},
948 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
949 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
950 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
951 {"winline", 0, 0, 0, ret_number, f_winline},
952 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
953 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
954 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
955 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
956 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
957 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
958 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
959 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200960};
961
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200962/*
963 * Function given to ExpandGeneric() to obtain the list of internal
964 * or user defined function names.
965 */
966 char_u *
967get_function_name(expand_T *xp, int idx)
968{
969 static int intidx = -1;
970 char_u *name;
971
972 if (idx == 0)
973 intidx = -1;
974 if (intidx < 0)
975 {
976 name = get_user_func_name(xp, idx);
977 if (name != NULL)
978 return name;
979 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200980 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200981 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200982 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200983 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200984 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200985 STRCAT(IObuff, ")");
986 return IObuff;
987 }
988
989 return NULL;
990}
991
992/*
993 * Function given to ExpandGeneric() to obtain the list of internal or
994 * user defined variable or function names.
995 */
996 char_u *
997get_expr_name(expand_T *xp, int idx)
998{
999 static int intidx = -1;
1000 char_u *name;
1001
1002 if (idx == 0)
1003 intidx = -1;
1004 if (intidx < 0)
1005 {
1006 name = get_function_name(xp, idx);
1007 if (name != NULL)
1008 return name;
1009 }
1010 return get_user_var_name(xp, ++intidx);
1011}
1012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001013/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001014 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001015 * Return index, or -1 if not found
1016 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001017 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001018find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019{
1020 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001021 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001022 int cmp;
1023 int x;
1024
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001025 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001026
1027 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001028 while (first <= last)
1029 {
1030 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001031 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001032 if (cmp < 0)
1033 last = x - 1;
1034 else if (cmp > 0)
1035 first = x + 1;
1036 else
1037 return x;
1038 }
1039 return -1;
1040}
1041
1042 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001043has_internal_func(char_u *name)
1044{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001045 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001046}
1047
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001048 char *
1049internal_func_name(int idx)
1050{
1051 return global_functions[idx].f_name;
1052}
1053
1054 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001055internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001056{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001057 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001058}
1059
1060/*
1061 * Check the argument count to use for internal function "idx".
1062 * Returns OK or FAIL;
1063 */
1064 int
1065check_internal_func(int idx, int argcount)
1066{
1067 int res;
1068 char *name;
1069
1070 if (argcount < global_functions[idx].f_min_argc)
1071 res = FCERR_TOOFEW;
1072 else if (argcount > global_functions[idx].f_max_argc)
1073 res = FCERR_TOOMANY;
1074 else
1075 return OK;
1076
1077 name = internal_func_name(idx);
1078 if (res == FCERR_TOOMANY)
1079 semsg(_(e_toomanyarg), name);
1080 else
1081 semsg(_(e_toofewarg), name);
1082 return FAIL;
1083}
1084
Bram Moolenaarac92e252019-08-03 21:58:38 +02001085 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001086call_internal_func(
1087 char_u *name,
1088 int argcount,
1089 typval_T *argvars,
1090 typval_T *rettv)
1091{
1092 int i;
1093
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001094 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001095 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001096 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001097 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001098 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001099 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001100 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001101 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001102 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001103 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001104}
1105
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001106 void
1107call_internal_func_by_idx(
1108 int idx,
1109 typval_T *argvars,
1110 typval_T *rettv)
1111{
1112 global_functions[idx].f_func(argvars, rettv);
1113}
1114
Bram Moolenaarac92e252019-08-03 21:58:38 +02001115/*
1116 * Invoke a method for base->method().
1117 */
1118 int
1119call_internal_method(
1120 char_u *name,
1121 int argcount,
1122 typval_T *argvars,
1123 typval_T *rettv,
1124 typval_T *basetv)
1125{
1126 int i;
1127 int fi;
1128 typval_T argv[MAX_FUNC_ARGS + 1];
1129
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001130 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001131 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001132 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001133 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001134 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001135 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001136 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001137 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001138 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001139
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001140 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001141 {
1142 // base value goes last
1143 for (i = 0; i < argcount; ++i)
1144 argv[i] = argvars[i];
1145 argv[argcount] = *basetv;
1146 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001147 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001148 {
1149 // base value goes second
1150 argv[0] = argvars[0];
1151 argv[1] = *basetv;
1152 for (i = 1; i < argcount; ++i)
1153 argv[i + 1] = argvars[i];
1154 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001155 else if (global_functions[fi].f_argtype == FEARG_3)
1156 {
1157 // base value goes third
1158 argv[0] = argvars[0];
1159 argv[1] = argvars[1];
1160 argv[2] = *basetv;
1161 for (i = 2; i < argcount; ++i)
1162 argv[i + 1] = argvars[i];
1163 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001164 else if (global_functions[fi].f_argtype == FEARG_4)
1165 {
1166 // base value goes fourth
1167 argv[0] = argvars[0];
1168 argv[1] = argvars[1];
1169 argv[2] = argvars[2];
1170 argv[3] = *basetv;
1171 for (i = 3; i < argcount; ++i)
1172 argv[i + 1] = argvars[i];
1173 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001174 else
1175 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001176 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001177 argv[0] = *basetv;
1178 for (i = 0; i < argcount; ++i)
1179 argv[i + 1] = argvars[i];
1180 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001181 argv[argcount + 1].v_type = VAR_UNKNOWN;
1182
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001183 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001184 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001185}
1186
1187/*
1188 * Return TRUE for a non-zero Number and a non-empty String.
1189 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001190 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001191non_zero_arg(typval_T *argvars)
1192{
1193 return ((argvars[0].v_type == VAR_NUMBER
1194 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001195 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001196 && argvars[0].vval.v_number == VVAL_TRUE)
1197 || (argvars[0].v_type == VAR_STRING
1198 && argvars[0].vval.v_string != NULL
1199 && *argvars[0].vval.v_string != NUL));
1200}
1201
1202/*
1203 * Get the lnum from the first argument.
1204 * Also accepts ".", "$", etc., but that only works for the current buffer.
1205 * Returns -1 on error.
1206 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001207 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001208tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001209{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001210 linenr_T lnum;
1211
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001212 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001213 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001214 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001215 int fnum;
1216 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1217
1218 if (fp != NULL)
1219 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001220 }
1221 return lnum;
1222}
1223
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001224/*
1225 * Get the lnum from the first argument.
1226 * Also accepts "$", then "buf" is used.
1227 * Returns 0 on error.
1228 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001229 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001230tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1231{
1232 if (argvars[0].v_type == VAR_STRING
1233 && argvars[0].vval.v_string != NULL
1234 && argvars[0].vval.v_string[0] == '$'
1235 && buf != NULL)
1236 return buf->b_ml.ml_line_count;
1237 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1238}
1239
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001240#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001241/*
1242 * Get the float value of "argvars[0]" into "f".
1243 * Returns FAIL when the argument is not a Number or Float.
1244 */
1245 static int
1246get_float_arg(typval_T *argvars, float_T *f)
1247{
1248 if (argvars[0].v_type == VAR_FLOAT)
1249 {
1250 *f = argvars[0].vval.v_float;
1251 return OK;
1252 }
1253 if (argvars[0].v_type == VAR_NUMBER)
1254 {
1255 *f = (float_T)argvars[0].vval.v_number;
1256 return OK;
1257 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001258 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001259 return FAIL;
1260}
1261
1262/*
1263 * "abs(expr)" function
1264 */
1265 static void
1266f_abs(typval_T *argvars, typval_T *rettv)
1267{
1268 if (argvars[0].v_type == VAR_FLOAT)
1269 {
1270 rettv->v_type = VAR_FLOAT;
1271 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1272 }
1273 else
1274 {
1275 varnumber_T n;
1276 int error = FALSE;
1277
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001278 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001279 if (error)
1280 rettv->vval.v_number = -1;
1281 else if (n > 0)
1282 rettv->vval.v_number = n;
1283 else
1284 rettv->vval.v_number = -n;
1285 }
1286}
1287
1288/*
1289 * "acos()" function
1290 */
1291 static void
1292f_acos(typval_T *argvars, typval_T *rettv)
1293{
1294 float_T f = 0.0;
1295
1296 rettv->v_type = VAR_FLOAT;
1297 if (get_float_arg(argvars, &f) == OK)
1298 rettv->vval.v_float = acos(f);
1299 else
1300 rettv->vval.v_float = 0.0;
1301}
1302#endif
1303
1304/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001305 * "and(expr, expr)" function
1306 */
1307 static void
1308f_and(typval_T *argvars, typval_T *rettv)
1309{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001310 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1311 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001312}
1313
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001314#ifdef FEAT_FLOAT
1315/*
1316 * "asin()" function
1317 */
1318 static void
1319f_asin(typval_T *argvars, typval_T *rettv)
1320{
1321 float_T f = 0.0;
1322
1323 rettv->v_type = VAR_FLOAT;
1324 if (get_float_arg(argvars, &f) == OK)
1325 rettv->vval.v_float = asin(f);
1326 else
1327 rettv->vval.v_float = 0.0;
1328}
1329
1330/*
1331 * "atan()" function
1332 */
1333 static void
1334f_atan(typval_T *argvars, typval_T *rettv)
1335{
1336 float_T f = 0.0;
1337
1338 rettv->v_type = VAR_FLOAT;
1339 if (get_float_arg(argvars, &f) == OK)
1340 rettv->vval.v_float = atan(f);
1341 else
1342 rettv->vval.v_float = 0.0;
1343}
1344
1345/*
1346 * "atan2()" function
1347 */
1348 static void
1349f_atan2(typval_T *argvars, typval_T *rettv)
1350{
1351 float_T fx = 0.0, fy = 0.0;
1352
1353 rettv->v_type = VAR_FLOAT;
1354 if (get_float_arg(argvars, &fx) == OK
1355 && get_float_arg(&argvars[1], &fy) == OK)
1356 rettv->vval.v_float = atan2(fx, fy);
1357 else
1358 rettv->vval.v_float = 0.0;
1359}
1360#endif
1361
1362/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001363 * "balloon_show()" function
1364 */
1365#ifdef FEAT_BEVAL
1366 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001367f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1368{
1369 rettv->v_type = VAR_STRING;
1370 if (balloonEval != NULL)
1371 {
1372 if (balloonEval->msg == NULL)
1373 rettv->vval.v_string = NULL;
1374 else
1375 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1376 }
1377}
1378
1379 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001380f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1381{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001382 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001383 {
1384 if (argvars[0].v_type == VAR_LIST
1385# ifdef FEAT_GUI
1386 && !gui.in_use
1387# endif
1388 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001389 {
1390 list_T *l = argvars[0].vval.v_list;
1391
1392 // empty list removes the balloon
1393 post_balloon(balloonEval, NULL,
1394 l == NULL || l->lv_len == 0 ? NULL : l);
1395 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001396 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001397 {
1398 char_u *mesg = tv_get_string_chk(&argvars[0]);
1399
1400 if (mesg != NULL)
1401 // empty string removes the balloon
1402 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1403 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001404 }
1405}
1406
Bram Moolenaar669a8282017-11-19 20:13:05 +01001407# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001408 static void
1409f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1410{
1411 if (rettv_list_alloc(rettv) == OK)
1412 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001413 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001414
1415 if (msg != NULL)
1416 {
1417 pumitem_T *array;
1418 int size = split_message(msg, &array);
1419 int i;
1420
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001421 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001422 for (i = 1; i < size - 1; ++i)
1423 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001424 while (size > 0)
1425 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001426 vim_free(array);
1427 }
1428 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001429}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001430# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001431#endif
1432
1433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 * Get buffer by number or pattern.
1435 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001436 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001437tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001438{
1439 char_u *name = tv->vval.v_string;
1440 buf_T *buf;
1441
1442 if (tv->v_type == VAR_NUMBER)
1443 return buflist_findnr((int)tv->vval.v_number);
1444 if (tv->v_type != VAR_STRING)
1445 return NULL;
1446 if (name == NULL || *name == NUL)
1447 return curbuf;
1448 if (name[0] == '$' && name[1] == NUL)
1449 return lastbuf;
1450
1451 buf = buflist_find_by_name(name, curtab_only);
1452
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001453 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001454 if (buf == NULL)
1455 buf = find_buffer(tv);
1456
1457 return buf;
1458}
1459
1460/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001461 * Get the buffer from "arg" and give an error and return NULL if it is not
1462 * valid.
1463 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001464 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001465get_buf_arg(typval_T *arg)
1466{
1467 buf_T *buf;
1468
1469 ++emsg_off;
1470 buf = tv_get_buf(arg, FALSE);
1471 --emsg_off;
1472 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001473 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001474 return buf;
1475}
1476
1477/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001478 * "byte2line(byte)" function
1479 */
1480 static void
1481f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1482{
1483#ifndef FEAT_BYTEOFF
1484 rettv->vval.v_number = -1;
1485#else
1486 long boff = 0;
1487
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001488 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001489 if (boff < 0)
1490 rettv->vval.v_number = -1;
1491 else
1492 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1493 (linenr_T)0, &boff);
1494#endif
1495}
1496
1497 static void
1498byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1499{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001500 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 char_u *str;
1502 varnumber_T idx;
1503
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001504 str = tv_get_string_chk(&argvars[0]);
1505 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506 rettv->vval.v_number = -1;
1507 if (str == NULL || idx < 0)
1508 return;
1509
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001510 t = str;
1511 for ( ; idx > 0; idx--)
1512 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001513 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001514 return;
1515 if (enc_utf8 && comp)
1516 t += utf_ptr2len(t);
1517 else
1518 t += (*mb_ptr2len)(t);
1519 }
1520 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001521}
1522
1523/*
1524 * "byteidx()" function
1525 */
1526 static void
1527f_byteidx(typval_T *argvars, typval_T *rettv)
1528{
1529 byteidx(argvars, rettv, FALSE);
1530}
1531
1532/*
1533 * "byteidxcomp()" function
1534 */
1535 static void
1536f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1537{
1538 byteidx(argvars, rettv, TRUE);
1539}
1540
1541/*
1542 * "call(func, arglist [, dict])" function
1543 */
1544 static void
1545f_call(typval_T *argvars, typval_T *rettv)
1546{
1547 char_u *func;
1548 partial_T *partial = NULL;
1549 dict_T *selfdict = NULL;
1550
1551 if (argvars[1].v_type != VAR_LIST)
1552 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001553 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001554 return;
1555 }
1556 if (argvars[1].vval.v_list == NULL)
1557 return;
1558
1559 if (argvars[0].v_type == VAR_FUNC)
1560 func = argvars[0].vval.v_string;
1561 else if (argvars[0].v_type == VAR_PARTIAL)
1562 {
1563 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001564 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001565 }
1566 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001567 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001568 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001569 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570
1571 if (argvars[2].v_type != VAR_UNKNOWN)
1572 {
1573 if (argvars[2].v_type != VAR_DICT)
1574 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001575 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 return;
1577 }
1578 selfdict = argvars[2].vval.v_dict;
1579 }
1580
1581 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1582}
1583
1584#ifdef FEAT_FLOAT
1585/*
1586 * "ceil({float})" function
1587 */
1588 static void
1589f_ceil(typval_T *argvars, typval_T *rettv)
1590{
1591 float_T f = 0.0;
1592
1593 rettv->v_type = VAR_FLOAT;
1594 if (get_float_arg(argvars, &f) == OK)
1595 rettv->vval.v_float = ceil(f);
1596 else
1597 rettv->vval.v_float = 0.0;
1598}
1599#endif
1600
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601/*
1602 * "changenr()" function
1603 */
1604 static void
1605f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1606{
1607 rettv->vval.v_number = curbuf->b_u_seq_cur;
1608}
1609
1610/*
1611 * "char2nr(string)" function
1612 */
1613 static void
1614f_char2nr(typval_T *argvars, typval_T *rettv)
1615{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616 if (has_mbyte)
1617 {
1618 int utf8 = 0;
1619
1620 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001621 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622
1623 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001624 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001626 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627 }
1628 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001629 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630}
1631
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001632 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001633get_optional_window(typval_T *argvars, int idx)
1634{
1635 win_T *win = curwin;
1636
1637 if (argvars[idx].v_type != VAR_UNKNOWN)
1638 {
1639 win = find_win_by_nr_or_id(&argvars[idx]);
1640 if (win == NULL)
1641 {
1642 emsg(_(e_invalwindow));
1643 return NULL;
1644 }
1645 }
1646 return win;
1647}
1648
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001650 * "col(string)" function
1651 */
1652 static void
1653f_col(typval_T *argvars, typval_T *rettv)
1654{
1655 colnr_T col = 0;
1656 pos_T *fp;
1657 int fnum = curbuf->b_fnum;
1658
1659 fp = var2fpos(&argvars[0], FALSE, &fnum);
1660 if (fp != NULL && fnum == curbuf->b_fnum)
1661 {
1662 if (fp->col == MAXCOL)
1663 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001664 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001665 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1666 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1667 else
1668 col = MAXCOL;
1669 }
1670 else
1671 {
1672 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001673 // col(".") when the cursor is on the NUL at the end of the line
1674 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 if (virtual_active() && fp == &curwin->w_cursor)
1676 {
1677 char_u *p = ml_get_cursor();
1678
1679 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1680 curwin->w_virtcol - curwin->w_cursor.coladd))
1681 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001682 int l;
1683
1684 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1685 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 }
1687 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 }
1689 }
1690 rettv->vval.v_number = col;
1691}
1692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693/*
1694 * "confirm(message, buttons[, default [, type]])" function
1695 */
1696 static void
1697f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1698{
1699#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1700 char_u *message;
1701 char_u *buttons = NULL;
1702 char_u buf[NUMBUFLEN];
1703 char_u buf2[NUMBUFLEN];
1704 int def = 1;
1705 int type = VIM_GENERIC;
1706 char_u *typestr;
1707 int error = FALSE;
1708
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001709 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001710 if (message == NULL)
1711 error = TRUE;
1712 if (argvars[1].v_type != VAR_UNKNOWN)
1713 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001714 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001715 if (buttons == NULL)
1716 error = TRUE;
1717 if (argvars[2].v_type != VAR_UNKNOWN)
1718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001719 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720 if (argvars[3].v_type != VAR_UNKNOWN)
1721 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001722 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001723 if (typestr == NULL)
1724 error = TRUE;
1725 else
1726 {
1727 switch (TOUPPER_ASC(*typestr))
1728 {
1729 case 'E': type = VIM_ERROR; break;
1730 case 'Q': type = VIM_QUESTION; break;
1731 case 'I': type = VIM_INFO; break;
1732 case 'W': type = VIM_WARNING; break;
1733 case 'G': type = VIM_GENERIC; break;
1734 }
1735 }
1736 }
1737 }
1738 }
1739
1740 if (buttons == NULL || *buttons == NUL)
1741 buttons = (char_u *)_("&Ok");
1742
1743 if (!error)
1744 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1745 def, NULL, FALSE);
1746#endif
1747}
1748
1749/*
1750 * "copy()" function
1751 */
1752 static void
1753f_copy(typval_T *argvars, typval_T *rettv)
1754{
1755 item_copy(&argvars[0], rettv, FALSE, 0);
1756}
1757
1758#ifdef FEAT_FLOAT
1759/*
1760 * "cos()" function
1761 */
1762 static void
1763f_cos(typval_T *argvars, typval_T *rettv)
1764{
1765 float_T f = 0.0;
1766
1767 rettv->v_type = VAR_FLOAT;
1768 if (get_float_arg(argvars, &f) == OK)
1769 rettv->vval.v_float = cos(f);
1770 else
1771 rettv->vval.v_float = 0.0;
1772}
1773
1774/*
1775 * "cosh()" function
1776 */
1777 static void
1778f_cosh(typval_T *argvars, typval_T *rettv)
1779{
1780 float_T f = 0.0;
1781
1782 rettv->v_type = VAR_FLOAT;
1783 if (get_float_arg(argvars, &f) == OK)
1784 rettv->vval.v_float = cosh(f);
1785 else
1786 rettv->vval.v_float = 0.0;
1787}
1788#endif
1789
1790/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001791 * "cursor(lnum, col)" function, or
1792 * "cursor(list)"
1793 *
1794 * Moves the cursor to the specified line and column.
1795 * Returns 0 when the position could be set, -1 otherwise.
1796 */
1797 static void
1798f_cursor(typval_T *argvars, typval_T *rettv)
1799{
1800 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001801 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001802 int set_curswant = TRUE;
1803
1804 rettv->vval.v_number = -1;
1805 if (argvars[1].v_type == VAR_UNKNOWN)
1806 {
1807 pos_T pos;
1808 colnr_T curswant = -1;
1809
1810 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1811 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001812 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 return;
1814 }
1815 line = pos.lnum;
1816 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001817 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001818 if (curswant >= 0)
1819 {
1820 curwin->w_curswant = curswant - 1;
1821 set_curswant = FALSE;
1822 }
1823 }
1824 else
1825 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001826 line = tv_get_lnum(argvars);
1827 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001829 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001831 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001832 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001833 if (line > 0)
1834 curwin->w_cursor.lnum = line;
1835 if (col > 0)
1836 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001837 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001838
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001839 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001841 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001842 if (has_mbyte)
1843 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844
1845 curwin->w_set_curswant = set_curswant;
1846 rettv->vval.v_number = 0;
1847}
1848
Bram Moolenaar4f974752019-02-17 17:44:42 +01001849#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001850/*
1851 * "debugbreak()" function
1852 */
1853 static void
1854f_debugbreak(typval_T *argvars, typval_T *rettv)
1855{
1856 int pid;
1857
1858 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001859 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001860 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001861 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001862 else
1863 {
1864 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1865
1866 if (hProcess != NULL)
1867 {
1868 DebugBreakProcess(hProcess);
1869 CloseHandle(hProcess);
1870 rettv->vval.v_number = OK;
1871 }
1872 }
1873}
1874#endif
1875
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001876/*
1877 * "deepcopy()" function
1878 */
1879 static void
1880f_deepcopy(typval_T *argvars, typval_T *rettv)
1881{
1882 int noref = 0;
1883 int copyID;
1884
1885 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001886 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001887 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001888 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 else
1890 {
1891 copyID = get_copyID();
1892 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1893 }
1894}
1895
1896/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001897 * "did_filetype()" function
1898 */
1899 static void
1900f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1901{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001903}
1904
1905/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001906 * "echoraw({expr})" function
1907 */
1908 static void
1909f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1910{
1911 char_u *str = tv_get_string_chk(&argvars[0]);
1912
1913 if (str != NULL && *str != NUL)
1914 {
1915 out_str(str);
1916 out_flush();
1917 }
1918}
1919
1920/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001921 * "empty({expr})" function
1922 */
1923 static void
1924f_empty(typval_T *argvars, typval_T *rettv)
1925{
1926 int n = FALSE;
1927
1928 switch (argvars[0].v_type)
1929 {
1930 case VAR_STRING:
1931 case VAR_FUNC:
1932 n = argvars[0].vval.v_string == NULL
1933 || *argvars[0].vval.v_string == NUL;
1934 break;
1935 case VAR_PARTIAL:
1936 n = FALSE;
1937 break;
1938 case VAR_NUMBER:
1939 n = argvars[0].vval.v_number == 0;
1940 break;
1941 case VAR_FLOAT:
1942#ifdef FEAT_FLOAT
1943 n = argvars[0].vval.v_float == 0.0;
1944 break;
1945#endif
1946 case VAR_LIST:
1947 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001948 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001949 break;
1950 case VAR_DICT:
1951 n = argvars[0].vval.v_dict == NULL
1952 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1953 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001954 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001955 case VAR_SPECIAL:
1956 n = argvars[0].vval.v_number != VVAL_TRUE;
1957 break;
1958
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001959 case VAR_BLOB:
1960 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001961 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1962 break;
1963
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001964 case VAR_JOB:
1965#ifdef FEAT_JOB_CHANNEL
1966 n = argvars[0].vval.v_job == NULL
1967 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1968 break;
1969#endif
1970 case VAR_CHANNEL:
1971#ifdef FEAT_JOB_CHANNEL
1972 n = argvars[0].vval.v_channel == NULL
1973 || !channel_is_open(argvars[0].vval.v_channel);
1974 break;
1975#endif
1976 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001977 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001978 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979 n = TRUE;
1980 break;
1981 }
1982
1983 rettv->vval.v_number = n;
1984}
1985
1986/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001987 * "environ()" function
1988 */
1989 static void
1990f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1991{
1992#if !defined(AMIGA)
1993 int i = 0;
1994 char_u *entry, *value;
1995# ifdef MSWIN
1996 extern wchar_t **_wenviron;
1997# else
1998 extern char **environ;
1999# endif
2000
2001 if (rettv_dict_alloc(rettv) != OK)
2002 return;
2003
2004# ifdef MSWIN
2005 if (*_wenviron == NULL)
2006 return;
2007# else
2008 if (*environ == NULL)
2009 return;
2010# endif
2011
2012 for (i = 0; ; ++i)
2013 {
2014# ifdef MSWIN
2015 short_u *p;
2016
2017 if ((p = (short_u *)_wenviron[i]) == NULL)
2018 return;
2019 entry = utf16_to_enc(p, NULL);
2020# else
2021 if ((entry = (char_u *)environ[i]) == NULL)
2022 return;
2023 entry = vim_strsave(entry);
2024# endif
2025 if (entry == NULL) // out of memory
2026 return;
2027 if ((value = vim_strchr(entry, '=')) == NULL)
2028 {
2029 vim_free(entry);
2030 continue;
2031 }
2032 *value++ = NUL;
2033 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2034 vim_free(entry);
2035 }
2036#endif
2037}
2038
2039/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002040 * "escape({string}, {chars})" function
2041 */
2042 static void
2043f_escape(typval_T *argvars, typval_T *rettv)
2044{
2045 char_u buf[NUMBUFLEN];
2046
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002047 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2048 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049 rettv->v_type = VAR_STRING;
2050}
2051
2052/*
2053 * "eval()" function
2054 */
2055 static void
2056f_eval(typval_T *argvars, typval_T *rettv)
2057{
2058 char_u *s, *p;
2059
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002060 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 if (s != NULL)
2062 s = skipwhite(s);
2063
2064 p = s;
2065 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2066 {
2067 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002068 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002069 need_clr_eos = FALSE;
2070 rettv->v_type = VAR_NUMBER;
2071 rettv->vval.v_number = 0;
2072 }
2073 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002074 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002075}
2076
2077/*
2078 * "eventhandler()" function
2079 */
2080 static void
2081f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2082{
2083 rettv->vval.v_number = vgetc_busy;
2084}
2085
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086static garray_T redir_execute_ga;
2087
2088/*
2089 * Append "value[value_len]" to the execute() output.
2090 */
2091 void
2092execute_redir_str(char_u *value, int value_len)
2093{
2094 int len;
2095
2096 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002097 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002099 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002100 if (ga_grow(&redir_execute_ga, len) == OK)
2101 {
2102 mch_memmove((char *)redir_execute_ga.ga_data
2103 + redir_execute_ga.ga_len, value, len);
2104 redir_execute_ga.ga_len += len;
2105 }
2106}
2107
2108/*
2109 * Get next line from a list.
2110 * Called by do_cmdline() to get the next line.
2111 * Returns allocated string, or NULL for end of function.
2112 */
2113
2114 static char_u *
2115get_list_line(
2116 int c UNUSED,
2117 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002118 int indent UNUSED,
2119 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120{
2121 listitem_T **p = (listitem_T **)cookie;
2122 listitem_T *item = *p;
2123 char_u buf[NUMBUFLEN];
2124 char_u *s;
2125
2126 if (item == NULL)
2127 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002128 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002129 *p = item->li_next;
2130 return s == NULL ? NULL : vim_strsave(s);
2131}
2132
2133/*
2134 * "execute()" function
2135 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002136 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002137execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138{
2139 char_u *cmd = NULL;
2140 list_T *list = NULL;
2141 int save_msg_silent = msg_silent;
2142 int save_emsg_silent = emsg_silent;
2143 int save_emsg_noredir = emsg_noredir;
2144 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002145 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002146 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002147 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002148 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002149
2150 rettv->vval.v_string = NULL;
2151 rettv->v_type = VAR_STRING;
2152
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002153 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002155 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002156 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002157 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 return;
2159 ++list->lv_refcount;
2160 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002161 else if (argvars[arg_off].v_type == VAR_JOB
2162 || argvars[arg_off].v_type == VAR_CHANNEL)
2163 {
2164 emsg(_(e_inval_string));
2165 return;
2166 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167 else
2168 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002169 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002170 if (cmd == NULL)
2171 return;
2172 }
2173
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002174 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 {
2176 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002177 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178
2179 if (s == NULL)
2180 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002181 if (*s == NUL)
2182 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002183 if (STRNCMP(s, "silent", 6) == 0)
2184 ++msg_silent;
2185 if (STRCMP(s, "silent!") == 0)
2186 {
2187 emsg_silent = TRUE;
2188 emsg_noredir = TRUE;
2189 }
2190 }
2191 else
2192 ++msg_silent;
2193
2194 if (redir_execute)
2195 save_ga = redir_execute_ga;
2196 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2197 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002198 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002199 if (!echo_output)
2200 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002201
2202 if (cmd != NULL)
2203 do_cmdline_cmd(cmd);
2204 else
2205 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002206 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002208 range_list_materialize(list);
2209 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210 do_cmdline(NULL, get_list_line, (void *)&item,
2211 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2212 --list->lv_refcount;
2213 }
2214
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002215 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002216 if (ga_grow(&redir_execute_ga, 1) == OK)
2217 {
2218 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2219 rettv->vval.v_string = redir_execute_ga.ga_data;
2220 }
2221 else
2222 {
2223 ga_clear(&redir_execute_ga);
2224 rettv->vval.v_string = NULL;
2225 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002226 msg_silent = save_msg_silent;
2227 emsg_silent = save_emsg_silent;
2228 emsg_noredir = save_emsg_noredir;
2229
2230 redir_execute = save_redir_execute;
2231 if (redir_execute)
2232 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002233 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002234
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002235 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002236 if (echo_output)
2237 // When not working silently: put it in column zero. A following
2238 // "echon" will overwrite the message, unavoidably.
2239 msg_col = 0;
2240 else
2241 // When working silently: Put it back where it was, since nothing
2242 // should have been written.
2243 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002244}
2245
2246/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002247 * "execute()" function
2248 */
2249 static void
2250f_execute(typval_T *argvars, typval_T *rettv)
2251{
2252 execute_common(argvars, rettv, 0);
2253}
2254
2255/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256 * "exists()" function
2257 */
2258 static void
2259f_exists(typval_T *argvars, typval_T *rettv)
2260{
2261 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002262 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002264 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002265 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002267 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 if (mch_getenv(p + 1) != NULL)
2269 n = TRUE;
2270 else
2271 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002272 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002273 p = expand_env_save(p);
2274 if (p != NULL && *p != '$')
2275 n = TRUE;
2276 vim_free(p);
2277 }
2278 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002279 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 {
2281 n = (get_option_tv(&p, NULL, TRUE) == OK);
2282 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002283 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002284 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002285 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002286 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002287 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002288 }
2289 else if (*p == ':')
2290 {
2291 n = cmd_exists(p + 1);
2292 }
2293 else if (*p == '#')
2294 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 if (p[1] == '#')
2296 n = autocmd_supported(p + 2);
2297 else
2298 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002299 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002300 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002302 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303 }
2304
2305 rettv->vval.v_number = n;
2306}
2307
2308#ifdef FEAT_FLOAT
2309/*
2310 * "exp()" function
2311 */
2312 static void
2313f_exp(typval_T *argvars, typval_T *rettv)
2314{
2315 float_T f = 0.0;
2316
2317 rettv->v_type = VAR_FLOAT;
2318 if (get_float_arg(argvars, &f) == OK)
2319 rettv->vval.v_float = exp(f);
2320 else
2321 rettv->vval.v_float = 0.0;
2322}
2323#endif
2324
2325/*
2326 * "expand()" function
2327 */
2328 static void
2329f_expand(typval_T *argvars, typval_T *rettv)
2330{
2331 char_u *s;
2332 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002333 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002334 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2335 expand_T xpc;
2336 int error = FALSE;
2337 char_u *result;
2338
2339 rettv->v_type = VAR_STRING;
2340 if (argvars[1].v_type != VAR_UNKNOWN
2341 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002342 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002344 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002346 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 if (*s == '%' || *s == '#' || *s == '<')
2348 {
2349 ++emsg_off;
2350 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2351 --emsg_off;
2352 if (rettv->v_type == VAR_LIST)
2353 {
2354 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2355 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002356 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002357 }
2358 else
2359 rettv->vval.v_string = result;
2360 }
2361 else
2362 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002363 // When the optional second argument is non-zero, don't remove matches
2364 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002366 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 options |= WILD_KEEP_ALL;
2368 if (!error)
2369 {
2370 ExpandInit(&xpc);
2371 xpc.xp_context = EXPAND_FILES;
2372 if (p_wic)
2373 options += WILD_ICASE;
2374 if (rettv->v_type == VAR_STRING)
2375 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2376 options, WILD_ALL);
2377 else if (rettv_list_alloc(rettv) != FAIL)
2378 {
2379 int i;
2380
2381 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2382 for (i = 0; i < xpc.xp_numfiles; i++)
2383 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2384 ExpandCleanup(&xpc);
2385 }
2386 }
2387 else
2388 rettv->vval.v_string = NULL;
2389 }
2390}
2391
2392/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002393 * "expandcmd()" function
2394 * Expand all the special characters in a command string.
2395 */
2396 static void
2397f_expandcmd(typval_T *argvars, typval_T *rettv)
2398{
2399 exarg_T eap;
2400 char_u *cmdstr;
2401 char *errormsg = NULL;
2402
2403 rettv->v_type = VAR_STRING;
2404 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2405
2406 memset(&eap, 0, sizeof(eap));
2407 eap.cmd = cmdstr;
2408 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002409 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002410 eap.usefilter = FALSE;
2411 eap.nextcmd = NULL;
2412 eap.cmdidx = CMD_USER;
2413
2414 expand_filename(&eap, &cmdstr, &errormsg);
2415 if (errormsg != NULL && *errormsg != NUL)
2416 emsg(errormsg);
2417
2418 rettv->vval.v_string = cmdstr;
2419}
2420
2421/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002422 * "feedkeys()" function
2423 */
2424 static void
2425f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2426{
2427 int remap = TRUE;
2428 int insert = FALSE;
2429 char_u *keys, *flags;
2430 char_u nbuf[NUMBUFLEN];
2431 int typed = FALSE;
2432 int execute = FALSE;
2433 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002434 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002435 char_u *keys_esc;
2436
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002437 // This is not allowed in the sandbox. If the commands would still be
2438 // executed in the sandbox it would be OK, but it probably happens later,
2439 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 if (check_secure())
2441 return;
2442
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002443 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002444
2445 if (argvars[1].v_type != VAR_UNKNOWN)
2446 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002447 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 for ( ; *flags != NUL; ++flags)
2449 {
2450 switch (*flags)
2451 {
2452 case 'n': remap = FALSE; break;
2453 case 'm': remap = TRUE; break;
2454 case 't': typed = TRUE; break;
2455 case 'i': insert = TRUE; break;
2456 case 'x': execute = TRUE; break;
2457 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002458 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 }
2460 }
2461 }
2462
2463 if (*keys != NUL || execute)
2464 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002465 // Need to escape K_SPECIAL and CSI before putting the string in the
2466 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467 keys_esc = vim_strsave_escape_csi(keys);
2468 if (keys_esc != NULL)
2469 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002470 if (lowlevel)
2471 {
2472#ifdef USE_INPUT_BUF
Bram Moolenaar0bdbc102020-03-15 16:51:40 +01002473 add_to_input_buf(keys, (int)STRLEN(keys));
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002474#else
2475 emsg(_("E980: lowlevel input not supported"));
2476#endif
2477 }
2478 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002479 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002480 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002481 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002482 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002483#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002484 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002485#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002486 )
2487 typebuf_was_filled = TRUE;
2488 }
2489 vim_free(keys_esc);
2490
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002491 if (execute)
2492 {
2493 int save_msg_scroll = msg_scroll;
2494
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002495 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496 msg_scroll = FALSE;
2497
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002498 if (!dangerous)
2499 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002500 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002501 if (!dangerous)
2502 --ex_normal_busy;
2503
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002504 msg_scroll |= save_msg_scroll;
2505 }
2506 }
2507 }
2508}
2509
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002510#ifdef FEAT_FLOAT
2511/*
2512 * "float2nr({float})" function
2513 */
2514 static void
2515f_float2nr(typval_T *argvars, typval_T *rettv)
2516{
2517 float_T f = 0.0;
2518
2519 if (get_float_arg(argvars, &f) == OK)
2520 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002521 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002522 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002523 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002524 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002525 else
2526 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002527 }
2528}
2529
2530/*
2531 * "floor({float})" function
2532 */
2533 static void
2534f_floor(typval_T *argvars, typval_T *rettv)
2535{
2536 float_T f = 0.0;
2537
2538 rettv->v_type = VAR_FLOAT;
2539 if (get_float_arg(argvars, &f) == OK)
2540 rettv->vval.v_float = floor(f);
2541 else
2542 rettv->vval.v_float = 0.0;
2543}
2544
2545/*
2546 * "fmod()" function
2547 */
2548 static void
2549f_fmod(typval_T *argvars, typval_T *rettv)
2550{
2551 float_T fx = 0.0, fy = 0.0;
2552
2553 rettv->v_type = VAR_FLOAT;
2554 if (get_float_arg(argvars, &fx) == OK
2555 && get_float_arg(&argvars[1], &fy) == OK)
2556 rettv->vval.v_float = fmod(fx, fy);
2557 else
2558 rettv->vval.v_float = 0.0;
2559}
2560#endif
2561
2562/*
2563 * "fnameescape({string})" function
2564 */
2565 static void
2566f_fnameescape(typval_T *argvars, typval_T *rettv)
2567{
2568 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002569 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002570 rettv->v_type = VAR_STRING;
2571}
2572
2573/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 * "foreground()" function
2575 */
2576 static void
2577f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2578{
2579#ifdef FEAT_GUI
2580 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002581 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002583 return;
2584 }
2585#endif
2586#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002588#endif
2589}
2590
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002592common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593{
2594 char_u *s;
2595 char_u *name;
2596 int use_string = FALSE;
2597 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002598 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002599
2600 if (argvars[0].v_type == VAR_FUNC)
2601 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002602 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603 s = argvars[0].vval.v_string;
2604 }
2605 else if (argvars[0].v_type == VAR_PARTIAL
2606 && argvars[0].vval.v_partial != NULL)
2607 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002608 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002610 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002611 }
2612 else
2613 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002614 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002615 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002616 use_string = TRUE;
2617 }
2618
Bram Moolenaar843b8842016-08-21 14:36:15 +02002619 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002620 {
2621 name = s;
2622 trans_name = trans_function_name(&name, FALSE,
2623 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2624 if (*name != NUL)
2625 s = NULL;
2626 }
2627
Bram Moolenaar843b8842016-08-21 14:36:15 +02002628 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2629 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002630 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002631 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002632 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002633 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002634 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002635 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002636 else
2637 {
2638 int dict_idx = 0;
2639 int arg_idx = 0;
2640 list_T *list = NULL;
2641
2642 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2643 {
2644 char sid_buf[25];
2645 int off = *s == 's' ? 2 : 5;
2646
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002647 // Expand s: and <SID> into <SNR>nr_, so that the function can
2648 // also be called from another script. Using trans_function_name()
2649 // would also work, but some plugins depend on the name being
2650 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002651 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002652 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 if (name != NULL)
2654 {
2655 STRCPY(name, sid_buf);
2656 STRCAT(name, s + off);
2657 }
2658 }
2659 else
2660 name = vim_strsave(s);
2661
2662 if (argvars[1].v_type != VAR_UNKNOWN)
2663 {
2664 if (argvars[2].v_type != VAR_UNKNOWN)
2665 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002666 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002667 arg_idx = 1;
2668 dict_idx = 2;
2669 }
2670 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002671 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002672 dict_idx = 1;
2673 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002674 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675 arg_idx = 1;
2676 if (dict_idx > 0)
2677 {
2678 if (argvars[dict_idx].v_type != VAR_DICT)
2679 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002680 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002681 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002682 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002683 }
2684 if (argvars[dict_idx].vval.v_dict == NULL)
2685 dict_idx = 0;
2686 }
2687 if (arg_idx > 0)
2688 {
2689 if (argvars[arg_idx].v_type != VAR_LIST)
2690 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002691 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002692 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002693 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694 }
2695 list = argvars[arg_idx].vval.v_list;
2696 if (list == NULL || list->lv_len == 0)
2697 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002698 else if (list->lv_len > MAX_FUNC_ARGS)
2699 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002700 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002701 vim_free(name);
2702 goto theend;
2703 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 }
2705 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002706 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002707 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002708 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002710 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711 if (pt == NULL)
2712 vim_free(name);
2713 else
2714 {
2715 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2716 {
2717 listitem_T *li;
2718 int i = 0;
2719 int arg_len = 0;
2720 int lv_len = 0;
2721
2722 if (arg_pt != NULL)
2723 arg_len = arg_pt->pt_argc;
2724 if (list != NULL)
2725 lv_len = list->lv_len;
2726 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002727 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 if (pt->pt_argv == NULL)
2729 {
2730 vim_free(pt);
2731 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002732 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002733 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002734 for (i = 0; i < arg_len; i++)
2735 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2736 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002737 {
2738 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002739 for (li = list->lv_first; li != NULL;
2740 li = li->li_next)
2741 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002742 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002743 }
2744
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002745 // For "function(dict.func, [], dict)" and "func" is a partial
2746 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002747 if (dict_idx > 0)
2748 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002749 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002750 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2751 ++pt->pt_dict->dv_refcount;
2752 }
2753 else if (arg_pt != NULL)
2754 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002755 // If the dict was bound automatically the result is also
2756 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002757 pt->pt_dict = arg_pt->pt_dict;
2758 pt->pt_auto = arg_pt->pt_auto;
2759 if (pt->pt_dict != NULL)
2760 ++pt->pt_dict->dv_refcount;
2761 }
2762
2763 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002764 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2765 {
2766 pt->pt_func = arg_pt->pt_func;
2767 func_ptr_ref(pt->pt_func);
2768 vim_free(name);
2769 }
2770 else if (is_funcref)
2771 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002772 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002773 func_ptr_ref(pt->pt_func);
2774 vim_free(name);
2775 }
2776 else
2777 {
2778 pt->pt_name = name;
2779 func_ref(name);
2780 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002781 }
2782 rettv->v_type = VAR_PARTIAL;
2783 rettv->vval.v_partial = pt;
2784 }
2785 else
2786 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002787 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002788 rettv->v_type = VAR_FUNC;
2789 rettv->vval.v_string = name;
2790 func_ref(name);
2791 }
2792 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002793theend:
2794 vim_free(trans_name);
2795}
2796
2797/*
2798 * "funcref()" function
2799 */
2800 static void
2801f_funcref(typval_T *argvars, typval_T *rettv)
2802{
2803 common_function(argvars, rettv, TRUE);
2804}
2805
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002806 static type_T *
2807ret_f_function(int argcount, type_T **argtypes UNUSED)
2808{
2809 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2810 return &t_func_any;
2811 return &t_partial_void;
2812}
2813
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002814/*
2815 * "function()" function
2816 */
2817 static void
2818f_function(typval_T *argvars, typval_T *rettv)
2819{
2820 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002821}
2822
2823/*
2824 * "garbagecollect()" function
2825 */
2826 static void
2827f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2828{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002829 // This is postponed until we are back at the toplevel, because we may be
2830 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002831 want_garbage_collect = TRUE;
2832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002833 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002834 garbage_collect_at_exit = TRUE;
2835}
2836
2837/*
2838 * "get()" function
2839 */
2840 static void
2841f_get(typval_T *argvars, typval_T *rettv)
2842{
2843 listitem_T *li;
2844 list_T *l;
2845 dictitem_T *di;
2846 dict_T *d;
2847 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002848 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002849
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002850 if (argvars[0].v_type == VAR_BLOB)
2851 {
2852 int error = FALSE;
2853 int idx = tv_get_number_chk(&argvars[1], &error);
2854
2855 if (!error)
2856 {
2857 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002858 if (idx < 0)
2859 idx = blob_len(argvars[0].vval.v_blob) + idx;
2860 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2861 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002862 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002863 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002864 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002865 tv = rettv;
2866 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002867 }
2868 }
2869 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002870 {
2871 if ((l = argvars[0].vval.v_list) != NULL)
2872 {
2873 int error = FALSE;
2874
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002875 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876 if (!error && li != NULL)
2877 tv = &li->li_tv;
2878 }
2879 }
2880 else if (argvars[0].v_type == VAR_DICT)
2881 {
2882 if ((d = argvars[0].vval.v_dict) != NULL)
2883 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002884 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002885 if (di != NULL)
2886 tv = &di->di_tv;
2887 }
2888 }
2889 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2890 {
2891 partial_T *pt;
2892 partial_T fref_pt;
2893
2894 if (argvars[0].v_type == VAR_PARTIAL)
2895 pt = argvars[0].vval.v_partial;
2896 else
2897 {
2898 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2899 fref_pt.pt_name = argvars[0].vval.v_string;
2900 pt = &fref_pt;
2901 }
2902
2903 if (pt != NULL)
2904 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002905 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002906 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002907
2908 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2909 {
2910 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002911 n = partial_name(pt);
2912 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002913 rettv->vval.v_string = NULL;
2914 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002915 {
2916 rettv->vval.v_string = vim_strsave(n);
2917 if (rettv->v_type == VAR_FUNC)
2918 func_ref(rettv->vval.v_string);
2919 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002920 }
2921 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002922 {
2923 what_is_dict = TRUE;
2924 if (pt->pt_dict != NULL)
2925 rettv_dict_set(rettv, pt->pt_dict);
2926 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002927 else if (STRCMP(what, "args") == 0)
2928 {
2929 rettv->v_type = VAR_LIST;
2930 if (rettv_list_alloc(rettv) == OK)
2931 {
2932 int i;
2933
2934 for (i = 0; i < pt->pt_argc; ++i)
2935 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2936 }
2937 }
2938 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002939 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002940
2941 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2942 // third argument
2943 if (!what_is_dict)
2944 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002945 }
2946 }
2947 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002948 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002949
2950 if (tv == NULL)
2951 {
2952 if (argvars[2].v_type != VAR_UNKNOWN)
2953 copy_tv(&argvars[2], rettv);
2954 }
2955 else
2956 copy_tv(tv, rettv);
2957}
2958
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002959/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002960 * "getchangelist()" function
2961 */
2962 static void
2963f_getchangelist(typval_T *argvars, typval_T *rettv)
2964{
2965#ifdef FEAT_JUMPLIST
2966 buf_T *buf;
2967 int i;
2968 list_T *l;
2969 dict_T *d;
2970#endif
2971
2972 if (rettv_list_alloc(rettv) != OK)
2973 return;
2974
2975#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002976 if (argvars[0].v_type == VAR_UNKNOWN)
2977 buf = curbuf;
2978 else
2979 {
2980 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2981 ++emsg_off;
2982 buf = tv_get_buf(&argvars[0], FALSE);
2983 --emsg_off;
2984 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002985 if (buf == NULL)
2986 return;
2987
2988 l = list_alloc();
2989 if (l == NULL)
2990 return;
2991
2992 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2993 return;
2994 /*
2995 * The current window change list index tracks only the position in the
2996 * current buffer change list. For other buffers, use the change list
2997 * length as the current index.
2998 */
2999 list_append_number(rettv->vval.v_list,
3000 (varnumber_T)((buf == curwin->w_buffer)
3001 ? curwin->w_changelistidx : buf->b_changelistlen));
3002
3003 for (i = 0; i < buf->b_changelistlen; ++i)
3004 {
3005 if (buf->b_changelist[i].lnum == 0)
3006 continue;
3007 if ((d = dict_alloc()) == NULL)
3008 return;
3009 if (list_append_dict(l, d) == FAIL)
3010 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003011 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3012 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003013 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003014 }
3015#endif
3016}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003017
3018/*
3019 * "getcharsearch()" function
3020 */
3021 static void
3022f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3023{
3024 if (rettv_dict_alloc(rettv) != FAIL)
3025 {
3026 dict_T *dict = rettv->vval.v_dict;
3027
Bram Moolenaare0be1672018-07-08 16:50:37 +02003028 dict_add_string(dict, "char", last_csearch());
3029 dict_add_number(dict, "forward", last_csearch_forward());
3030 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003031 }
3032}
3033
3034/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003035 * "getenv()" function
3036 */
3037 static void
3038f_getenv(typval_T *argvars, typval_T *rettv)
3039{
3040 int mustfree = FALSE;
3041 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3042
3043 if (p == NULL)
3044 {
3045 rettv->v_type = VAR_SPECIAL;
3046 rettv->vval.v_number = VVAL_NULL;
3047 return;
3048 }
3049 if (!mustfree)
3050 p = vim_strsave(p);
3051 rettv->vval.v_string = p;
3052 rettv->v_type = VAR_STRING;
3053}
3054
3055/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003056 * "getfontname()" function
3057 */
3058 static void
3059f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3060{
3061 rettv->v_type = VAR_STRING;
3062 rettv->vval.v_string = NULL;
3063#ifdef FEAT_GUI
3064 if (gui.in_use)
3065 {
3066 GuiFont font;
3067 char_u *name = NULL;
3068
3069 if (argvars[0].v_type == VAR_UNKNOWN)
3070 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003071 // Get the "Normal" font. Either the name saved by
3072 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 font = gui.norm_font;
3074 name = hl_get_font_name();
3075 }
3076 else
3077 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003078 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003079 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003080 return;
3081 font = gui_mch_get_font(name, FALSE);
3082 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003083 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003084 }
3085 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3086 if (argvars[0].v_type != VAR_UNKNOWN)
3087 gui_mch_free_font(font);
3088 }
3089#endif
3090}
3091
3092/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003093 * "getjumplist()" function
3094 */
3095 static void
3096f_getjumplist(typval_T *argvars, typval_T *rettv)
3097{
3098#ifdef FEAT_JUMPLIST
3099 win_T *wp;
3100 int i;
3101 list_T *l;
3102 dict_T *d;
3103#endif
3104
3105 if (rettv_list_alloc(rettv) != OK)
3106 return;
3107
3108#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003109 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003110 if (wp == NULL)
3111 return;
3112
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003113 cleanup_jumplist(wp, TRUE);
3114
Bram Moolenaar4f505882018-02-10 21:06:32 +01003115 l = list_alloc();
3116 if (l == NULL)
3117 return;
3118
3119 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3120 return;
3121 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3122
3123 for (i = 0; i < wp->w_jumplistlen; ++i)
3124 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003125 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3126 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003127 if ((d = dict_alloc()) == NULL)
3128 return;
3129 if (list_append_dict(l, d) == FAIL)
3130 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003131 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3132 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003133 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003134 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003135 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003136 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003137 }
3138#endif
3139}
3140
3141/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003142 * "getpid()" function
3143 */
3144 static void
3145f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3146{
3147 rettv->vval.v_number = mch_get_pid();
3148}
3149
3150 static void
3151getpos_both(
3152 typval_T *argvars,
3153 typval_T *rettv,
3154 int getcurpos)
3155{
3156 pos_T *fp;
3157 list_T *l;
3158 int fnum = -1;
3159
3160 if (rettv_list_alloc(rettv) == OK)
3161 {
3162 l = rettv->vval.v_list;
3163 if (getcurpos)
3164 fp = &curwin->w_cursor;
3165 else
3166 fp = var2fpos(&argvars[0], TRUE, &fnum);
3167 if (fnum != -1)
3168 list_append_number(l, (varnumber_T)fnum);
3169 else
3170 list_append_number(l, (varnumber_T)0);
3171 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3172 : (varnumber_T)0);
3173 list_append_number(l, (fp != NULL)
3174 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3175 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003176 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003177 (varnumber_T)0);
3178 if (getcurpos)
3179 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003180 int save_set_curswant = curwin->w_set_curswant;
3181 colnr_T save_curswant = curwin->w_curswant;
3182 colnr_T save_virtcol = curwin->w_virtcol;
3183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003184 update_curswant();
3185 list_append_number(l, curwin->w_curswant == MAXCOL ?
3186 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003187
3188 // Do not change "curswant", as it is unexpected that a get
3189 // function has a side effect.
3190 if (save_set_curswant)
3191 {
3192 curwin->w_set_curswant = save_set_curswant;
3193 curwin->w_curswant = save_curswant;
3194 curwin->w_virtcol = save_virtcol;
3195 curwin->w_valid &= ~VALID_VIRTCOL;
3196 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003197 }
3198 }
3199 else
3200 rettv->vval.v_number = FALSE;
3201}
3202
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003203/*
3204 * "getcurpos()" function
3205 */
3206 static void
3207f_getcurpos(typval_T *argvars, typval_T *rettv)
3208{
3209 getpos_both(argvars, rettv, TRUE);
3210}
3211
3212/*
3213 * "getpos(string)" function
3214 */
3215 static void
3216f_getpos(typval_T *argvars, typval_T *rettv)
3217{
3218 getpos_both(argvars, rettv, FALSE);
3219}
3220
3221/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003222 * "getreg()" function
3223 */
3224 static void
3225f_getreg(typval_T *argvars, typval_T *rettv)
3226{
3227 char_u *strregname;
3228 int regname;
3229 int arg2 = FALSE;
3230 int return_list = FALSE;
3231 int error = FALSE;
3232
3233 if (argvars[0].v_type != VAR_UNKNOWN)
3234 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003235 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003236 error = strregname == NULL;
3237 if (argvars[1].v_type != VAR_UNKNOWN)
3238 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003239 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003240 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003241 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003242 }
3243 }
3244 else
3245 strregname = get_vim_var_str(VV_REG);
3246
3247 if (error)
3248 return;
3249
3250 regname = (strregname == NULL ? '"' : *strregname);
3251 if (regname == 0)
3252 regname = '"';
3253
3254 if (return_list)
3255 {
3256 rettv->v_type = VAR_LIST;
3257 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3258 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3259 if (rettv->vval.v_list == NULL)
3260 (void)rettv_list_alloc(rettv);
3261 else
3262 ++rettv->vval.v_list->lv_refcount;
3263 }
3264 else
3265 {
3266 rettv->v_type = VAR_STRING;
3267 rettv->vval.v_string = get_reg_contents(regname,
3268 arg2 ? GREG_EXPR_SRC : 0);
3269 }
3270}
3271
3272/*
3273 * "getregtype()" function
3274 */
3275 static void
3276f_getregtype(typval_T *argvars, typval_T *rettv)
3277{
3278 char_u *strregname;
3279 int regname;
3280 char_u buf[NUMBUFLEN + 2];
3281 long reglen = 0;
3282
3283 if (argvars[0].v_type != VAR_UNKNOWN)
3284 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003285 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003286 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003287 {
3288 rettv->v_type = VAR_STRING;
3289 rettv->vval.v_string = NULL;
3290 return;
3291 }
3292 }
3293 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003294 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003295 strregname = get_vim_var_str(VV_REG);
3296
3297 regname = (strregname == NULL ? '"' : *strregname);
3298 if (regname == 0)
3299 regname = '"';
3300
3301 buf[0] = NUL;
3302 buf[1] = NUL;
3303 switch (get_reg_type(regname, &reglen))
3304 {
3305 case MLINE: buf[0] = 'V'; break;
3306 case MCHAR: buf[0] = 'v'; break;
3307 case MBLOCK:
3308 buf[0] = Ctrl_V;
3309 sprintf((char *)buf + 1, "%ld", reglen + 1);
3310 break;
3311 }
3312 rettv->v_type = VAR_STRING;
3313 rettv->vval.v_string = vim_strsave(buf);
3314}
3315
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003316/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003317 * "gettagstack()" function
3318 */
3319 static void
3320f_gettagstack(typval_T *argvars, typval_T *rettv)
3321{
3322 win_T *wp = curwin; // default is current window
3323
3324 if (rettv_dict_alloc(rettv) != OK)
3325 return;
3326
3327 if (argvars[0].v_type != VAR_UNKNOWN)
3328 {
3329 wp = find_win_by_nr_or_id(&argvars[0]);
3330 if (wp == NULL)
3331 return;
3332 }
3333
3334 get_tagstack(wp, rettv->vval.v_dict);
3335}
3336
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003337// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003338#include "version.h"
3339
3340/*
3341 * "has()" function
3342 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003343 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003344f_has(typval_T *argvars, typval_T *rettv)
3345{
3346 int i;
3347 char_u *name;
3348 int n = FALSE;
3349 static char *(has_list[]) =
3350 {
3351#ifdef AMIGA
3352 "amiga",
3353# ifdef FEAT_ARP
3354 "arp",
3355# endif
3356#endif
3357#ifdef __BEOS__
3358 "beos",
3359#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003360#ifdef __HAIKU__
3361 "haiku",
3362#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003363#if defined(BSD) && !defined(MACOS_X)
3364 "bsd",
3365#endif
3366#ifdef hpux
3367 "hpux",
3368#endif
3369#ifdef __linux__
3370 "linux",
3371#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003372#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003373 "mac", // Mac OS X (and, once, Mac OS Classic)
3374 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003375# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003376 "macunix", // Mac OS X, with the darwin feature
3377 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003378# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003379#endif
3380#ifdef __QNX__
3381 "qnx",
3382#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003383#ifdef SUN_SYSTEM
3384 "sun",
3385#else
3386 "moon",
3387#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003388#ifdef UNIX
3389 "unix",
3390#endif
3391#ifdef VMS
3392 "vms",
3393#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003394#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 "win32",
3396#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003397#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003398 "win32unix",
3399#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003400#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003401 "win64",
3402#endif
3403#ifdef EBCDIC
3404 "ebcdic",
3405#endif
3406#ifndef CASE_INSENSITIVE_FILENAME
3407 "fname_case",
3408#endif
3409#ifdef HAVE_ACL
3410 "acl",
3411#endif
3412#ifdef FEAT_ARABIC
3413 "arabic",
3414#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003415 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003416#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003417 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003418#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003419#ifdef FEAT_AUTOSERVERNAME
3420 "autoservername",
3421#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003422#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003423 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003424# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 "balloon_multiline",
3426# endif
3427#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003428#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003429 "balloon_eval_term",
3430#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003431#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3432 "builtin_terms",
3433# ifdef ALL_BUILTIN_TCAPS
3434 "all_builtin_terms",
3435# endif
3436#endif
3437#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003438 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003439 || defined(FEAT_GUI_MOTIF))
3440 "browsefilter",
3441#endif
3442#ifdef FEAT_BYTEOFF
3443 "byte_offset",
3444#endif
3445#ifdef FEAT_JOB_CHANNEL
3446 "channel",
3447#endif
3448#ifdef FEAT_CINDENT
3449 "cindent",
3450#endif
3451#ifdef FEAT_CLIENTSERVER
3452 "clientserver",
3453#endif
3454#ifdef FEAT_CLIPBOARD
3455 "clipboard",
3456#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003458 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003459 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003460#ifdef FEAT_CONCEAL
3461 "conceal",
3462#endif
3463#ifdef FEAT_CRYPT
3464 "cryptv",
3465 "crypt-blowfish",
3466 "crypt-blowfish2",
3467#endif
3468#ifdef FEAT_CSCOPE
3469 "cscope",
3470#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472#ifdef CURSOR_SHAPE
3473 "cursorshape",
3474#endif
3475#ifdef DEBUG
3476 "debug",
3477#endif
3478#ifdef FEAT_CON_DIALOG
3479 "dialog_con",
3480#endif
3481#ifdef FEAT_GUI_DIALOG
3482 "dialog_gui",
3483#endif
3484#ifdef FEAT_DIFF
3485 "diff",
3486#endif
3487#ifdef FEAT_DIGRAPHS
3488 "digraphs",
3489#endif
3490#ifdef FEAT_DIRECTX
3491 "directx",
3492#endif
3493#ifdef FEAT_DND
3494 "dnd",
3495#endif
3496#ifdef FEAT_EMACS_TAGS
3497 "emacs_tags",
3498#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003499 "eval", // always present, of course!
3500 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003501#ifdef FEAT_SEARCH_EXTRA
3502 "extra_search",
3503#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003504#ifdef FEAT_SEARCHPATH
3505 "file_in_path",
3506#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003507#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003508 "filterpipe",
3509#endif
3510#ifdef FEAT_FIND_ID
3511 "find_in_path",
3512#endif
3513#ifdef FEAT_FLOAT
3514 "float",
3515#endif
3516#ifdef FEAT_FOLDING
3517 "folding",
3518#endif
3519#ifdef FEAT_FOOTER
3520 "footer",
3521#endif
3522#if !defined(USE_SYSTEM) && defined(UNIX)
3523 "fork",
3524#endif
3525#ifdef FEAT_GETTEXT
3526 "gettext",
3527#endif
3528#ifdef FEAT_GUI
3529 "gui",
3530#endif
3531#ifdef FEAT_GUI_ATHENA
3532# ifdef FEAT_GUI_NEXTAW
3533 "gui_neXtaw",
3534# else
3535 "gui_athena",
3536# endif
3537#endif
3538#ifdef FEAT_GUI_GTK
3539 "gui_gtk",
3540# ifdef USE_GTK3
3541 "gui_gtk3",
3542# else
3543 "gui_gtk2",
3544# endif
3545#endif
3546#ifdef FEAT_GUI_GNOME
3547 "gui_gnome",
3548#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003549#ifdef FEAT_GUI_HAIKU
3550 "gui_haiku",
3551#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003552#ifdef FEAT_GUI_MAC
3553 "gui_mac",
3554#endif
3555#ifdef FEAT_GUI_MOTIF
3556 "gui_motif",
3557#endif
3558#ifdef FEAT_GUI_PHOTON
3559 "gui_photon",
3560#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003561#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003562 "gui_win32",
3563#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003564#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3565 "iconv",
3566#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003567 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568#ifdef FEAT_JOB_CHANNEL
3569 "job",
3570#endif
3571#ifdef FEAT_JUMPLIST
3572 "jumplist",
3573#endif
3574#ifdef FEAT_KEYMAP
3575 "keymap",
3576#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003577 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578#ifdef FEAT_LANGMAP
3579 "langmap",
3580#endif
3581#ifdef FEAT_LIBCALL
3582 "libcall",
3583#endif
3584#ifdef FEAT_LINEBREAK
3585 "linebreak",
3586#endif
3587#ifdef FEAT_LISP
3588 "lispindent",
3589#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003592#ifdef FEAT_LUA
3593# ifndef DYNAMIC_LUA
3594 "lua",
3595# endif
3596#endif
3597#ifdef FEAT_MENU
3598 "menu",
3599#endif
3600#ifdef FEAT_SESSION
3601 "mksession",
3602#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003604 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605#ifdef FEAT_MOUSESHAPE
3606 "mouseshape",
3607#endif
3608#if defined(UNIX) || defined(VMS)
3609# ifdef FEAT_MOUSE_DEC
3610 "mouse_dec",
3611# endif
3612# ifdef FEAT_MOUSE_GPM
3613 "mouse_gpm",
3614# endif
3615# ifdef FEAT_MOUSE_JSB
3616 "mouse_jsbterm",
3617# endif
3618# ifdef FEAT_MOUSE_NET
3619 "mouse_netterm",
3620# endif
3621# ifdef FEAT_MOUSE_PTERM
3622 "mouse_pterm",
3623# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003624# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003625 "mouse_sgr",
3626# endif
3627# ifdef FEAT_SYSMOUSE
3628 "mouse_sysmouse",
3629# endif
3630# ifdef FEAT_MOUSE_URXVT
3631 "mouse_urxvt",
3632# endif
3633# ifdef FEAT_MOUSE_XTERM
3634 "mouse_xterm",
3635# endif
3636#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638#ifdef FEAT_MBYTE_IME
3639 "multi_byte_ime",
3640#endif
3641#ifdef FEAT_MULTI_LANG
3642 "multi_lang",
3643#endif
3644#ifdef FEAT_MZSCHEME
3645#ifndef DYNAMIC_MZSCHEME
3646 "mzscheme",
3647#endif
3648#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649 "num64",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003650#ifdef FEAT_OLE
3651 "ole",
3652#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003653#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003655#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656#ifdef FEAT_PATH_EXTRA
3657 "path_extra",
3658#endif
3659#ifdef FEAT_PERL
3660#ifndef DYNAMIC_PERL
3661 "perl",
3662#endif
3663#endif
3664#ifdef FEAT_PERSISTENT_UNDO
3665 "persistent_undo",
3666#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003667#if defined(FEAT_PYTHON)
3668 "python_compiled",
3669# if defined(DYNAMIC_PYTHON)
3670 "python_dynamic",
3671# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003672 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003673 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003674# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003675#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003676#if defined(FEAT_PYTHON3)
3677 "python3_compiled",
3678# if defined(DYNAMIC_PYTHON3)
3679 "python3_dynamic",
3680# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003682 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003683# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003684#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003685#ifdef FEAT_PROP_POPUP
3686 "popupwin",
3687#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003688#ifdef FEAT_POSTSCRIPT
3689 "postscript",
3690#endif
3691#ifdef FEAT_PRINTER
3692 "printer",
3693#endif
3694#ifdef FEAT_PROFILE
3695 "profile",
3696#endif
3697#ifdef FEAT_RELTIME
3698 "reltime",
3699#endif
3700#ifdef FEAT_QUICKFIX
3701 "quickfix",
3702#endif
3703#ifdef FEAT_RIGHTLEFT
3704 "rightleft",
3705#endif
3706#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3707 "ruby",
3708#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003709 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003710#ifdef FEAT_CMDL_INFO
3711 "showcmd",
3712 "cmdline_info",
3713#endif
3714#ifdef FEAT_SIGNS
3715 "signs",
3716#endif
3717#ifdef FEAT_SMARTINDENT
3718 "smartindent",
3719#endif
3720#ifdef STARTUPTIME
3721 "startuptime",
3722#endif
3723#ifdef FEAT_STL_OPT
3724 "statusline",
3725#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003726#ifdef FEAT_NETBEANS_INTG
3727 "netbeans_intg",
3728#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003729#ifdef FEAT_SOUND
3730 "sound",
3731#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003732#ifdef FEAT_SPELL
3733 "spell",
3734#endif
3735#ifdef FEAT_SYN_HL
3736 "syntax",
3737#endif
3738#if defined(USE_SYSTEM) || !defined(UNIX)
3739 "system",
3740#endif
3741#ifdef FEAT_TAG_BINS
3742 "tag_binary",
3743#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003744#ifdef FEAT_TCL
3745# ifndef DYNAMIC_TCL
3746 "tcl",
3747# endif
3748#endif
3749#ifdef FEAT_TERMGUICOLORS
3750 "termguicolors",
3751#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003752#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003753 "terminal",
3754#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003755#ifdef TERMINFO
3756 "terminfo",
3757#endif
3758#ifdef FEAT_TERMRESPONSE
3759 "termresponse",
3760#endif
3761#ifdef FEAT_TEXTOBJ
3762 "textobjects",
3763#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003764#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003765 "textprop",
3766#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767#ifdef HAVE_TGETENT
3768 "tgetent",
3769#endif
3770#ifdef FEAT_TIMERS
3771 "timers",
3772#endif
3773#ifdef FEAT_TITLE
3774 "title",
3775#endif
3776#ifdef FEAT_TOOLBAR
3777 "toolbar",
3778#endif
3779#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3780 "unnamedplus",
3781#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003782 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003783 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003784#ifdef FEAT_VARTABS
3785 "vartabs",
3786#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003787 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003788#ifdef FEAT_VIMINFO
3789 "viminfo",
3790#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003791 "vimscript-1",
3792 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003793 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003794 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003795 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003796 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003797 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003798 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003799#ifdef FEAT_VTP
3800 "vtp",
3801#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003802#ifdef FEAT_WILDIGN
3803 "wildignore",
3804#endif
3805#ifdef FEAT_WILDMENU
3806 "wildmenu",
3807#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003809#ifdef FEAT_WAK
3810 "winaltkeys",
3811#endif
3812#ifdef FEAT_WRITEBACKUP
3813 "writebackup",
3814#endif
3815#ifdef FEAT_XIM
3816 "xim",
3817#endif
3818#ifdef FEAT_XFONTSET
3819 "xfontset",
3820#endif
3821#ifdef FEAT_XPM_W32
3822 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003823 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003824#else
3825# if defined(HAVE_XPM)
3826 "xpm",
3827# endif
3828#endif
3829#ifdef USE_XSMP
3830 "xsmp",
3831#endif
3832#ifdef USE_XSMP_INTERACT
3833 "xsmp_interact",
3834#endif
3835#ifdef FEAT_XCLIPBOARD
3836 "xterm_clipboard",
3837#endif
3838#ifdef FEAT_XTERM_SAVE
3839 "xterm_save",
3840#endif
3841#if defined(UNIX) && defined(FEAT_X11)
3842 "X11",
3843#endif
3844 NULL
3845 };
3846
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003847 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003848 for (i = 0; has_list[i] != NULL; ++i)
3849 if (STRICMP(name, has_list[i]) == 0)
3850 {
3851 n = TRUE;
3852 break;
3853 }
3854
3855 if (n == FALSE)
3856 {
3857 if (STRNICMP(name, "patch", 5) == 0)
3858 {
3859 if (name[5] == '-'
3860 && STRLEN(name) >= 11
3861 && vim_isdigit(name[6])
3862 && vim_isdigit(name[8])
3863 && vim_isdigit(name[10]))
3864 {
3865 int major = atoi((char *)name + 6);
3866 int minor = atoi((char *)name + 8);
3867
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003868 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003869 n = (major < VIM_VERSION_MAJOR
3870 || (major == VIM_VERSION_MAJOR
3871 && (minor < VIM_VERSION_MINOR
3872 || (minor == VIM_VERSION_MINOR
3873 && has_patch(atoi((char *)name + 10))))));
3874 }
3875 else
3876 n = has_patch(atoi((char *)name + 5));
3877 }
3878 else if (STRICMP(name, "vim_starting") == 0)
3879 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003880 else if (STRICMP(name, "ttyin") == 0)
3881 n = mch_input_isatty();
3882 else if (STRICMP(name, "ttyout") == 0)
3883 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003884 else if (STRICMP(name, "multi_byte_encoding") == 0)
3885 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003886#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003887 else if (STRICMP(name, "balloon_multiline") == 0)
3888 n = multiline_balloon_available();
3889#endif
3890#ifdef DYNAMIC_TCL
3891 else if (STRICMP(name, "tcl") == 0)
3892 n = tcl_enabled(FALSE);
3893#endif
3894#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3895 else if (STRICMP(name, "iconv") == 0)
3896 n = iconv_enabled(FALSE);
3897#endif
3898#ifdef DYNAMIC_LUA
3899 else if (STRICMP(name, "lua") == 0)
3900 n = lua_enabled(FALSE);
3901#endif
3902#ifdef DYNAMIC_MZSCHEME
3903 else if (STRICMP(name, "mzscheme") == 0)
3904 n = mzscheme_enabled(FALSE);
3905#endif
3906#ifdef DYNAMIC_RUBY
3907 else if (STRICMP(name, "ruby") == 0)
3908 n = ruby_enabled(FALSE);
3909#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003910#ifdef DYNAMIC_PYTHON
3911 else if (STRICMP(name, "python") == 0)
3912 n = python_enabled(FALSE);
3913#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003914#ifdef DYNAMIC_PYTHON3
3915 else if (STRICMP(name, "python3") == 0)
3916 n = python3_enabled(FALSE);
3917#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003918#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3919 else if (STRICMP(name, "pythonx") == 0)
3920 {
3921# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3922 if (p_pyx == 0)
3923 n = python3_enabled(FALSE) || python_enabled(FALSE);
3924 else if (p_pyx == 3)
3925 n = python3_enabled(FALSE);
3926 else if (p_pyx == 2)
3927 n = python_enabled(FALSE);
3928# elif defined(DYNAMIC_PYTHON)
3929 n = python_enabled(FALSE);
3930# elif defined(DYNAMIC_PYTHON3)
3931 n = python3_enabled(FALSE);
3932# endif
3933 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934#endif
3935#ifdef DYNAMIC_PERL
3936 else if (STRICMP(name, "perl") == 0)
3937 n = perl_enabled(FALSE);
3938#endif
3939#ifdef FEAT_GUI
3940 else if (STRICMP(name, "gui_running") == 0)
3941 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942# ifdef FEAT_BROWSE
3943 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003944 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003945# endif
3946#endif
3947#ifdef FEAT_SYN_HL
3948 else if (STRICMP(name, "syntax_items") == 0)
3949 n = syntax_present(curwin);
3950#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003951#ifdef FEAT_VTP
3952 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003953 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954#endif
3955#ifdef FEAT_NETBEANS_INTG
3956 else if (STRICMP(name, "netbeans_enabled") == 0)
3957 n = netbeans_active();
3958#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003959#ifdef FEAT_MOUSE_GPM
3960 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3961 n = gpm_enabled();
3962#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003963#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003964 else if (STRICMP(name, "terminal") == 0)
3965 n = terminal_enabled();
3966#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003967#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003968 else if (STRICMP(name, "conpty") == 0)
3969 n = use_conpty();
3970#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003971#ifdef FEAT_CLIPBOARD
3972 else if (STRICMP(name, "clipboard_working") == 0)
3973 n = clip_star.available;
3974#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003975#ifdef VIMDLL
3976 else if (STRICMP(name, "filterpipe") == 0)
3977 n = gui.in_use || gui.starting;
3978#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003979 }
3980
3981 rettv->vval.v_number = n;
3982}
3983
3984/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003985 * "haslocaldir()" function
3986 */
3987 static void
3988f_haslocaldir(typval_T *argvars, typval_T *rettv)
3989{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003990 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003991 win_T *wp = NULL;
3992
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003993 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3994
3995 // Check for window-local and tab-local directories
3996 if (wp != NULL && wp->w_localdir != NULL)
3997 rettv->vval.v_number = 1;
3998 else if (tp != NULL && tp->tp_localdir != NULL)
3999 rettv->vval.v_number = 2;
4000 else
4001 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004002}
4003
4004/*
4005 * "hasmapto()" function
4006 */
4007 static void
4008f_hasmapto(typval_T *argvars, typval_T *rettv)
4009{
4010 char_u *name;
4011 char_u *mode;
4012 char_u buf[NUMBUFLEN];
4013 int abbr = FALSE;
4014
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004015 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004016 if (argvars[1].v_type == VAR_UNKNOWN)
4017 mode = (char_u *)"nvo";
4018 else
4019 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004020 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004022 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023 }
4024
4025 if (map_to_exists(name, mode, abbr))
4026 rettv->vval.v_number = TRUE;
4027 else
4028 rettv->vval.v_number = FALSE;
4029}
4030
4031/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004032 * "highlightID(name)" function
4033 */
4034 static void
4035f_hlID(typval_T *argvars, typval_T *rettv)
4036{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004037 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004038}
4039
4040/*
4041 * "highlight_exists()" function
4042 */
4043 static void
4044f_hlexists(typval_T *argvars, typval_T *rettv)
4045{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004046 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004047}
4048
4049/*
4050 * "hostname()" function
4051 */
4052 static void
4053f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4054{
4055 char_u hostname[256];
4056
4057 mch_get_host_name(hostname, 256);
4058 rettv->v_type = VAR_STRING;
4059 rettv->vval.v_string = vim_strsave(hostname);
4060}
4061
4062/*
4063 * iconv() function
4064 */
4065 static void
4066f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4067{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004068 char_u buf1[NUMBUFLEN];
4069 char_u buf2[NUMBUFLEN];
4070 char_u *from, *to, *str;
4071 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072
4073 rettv->v_type = VAR_STRING;
4074 rettv->vval.v_string = NULL;
4075
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004076 str = tv_get_string(&argvars[0]);
4077 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4078 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004079 vimconv.vc_type = CONV_NONE;
4080 convert_setup(&vimconv, from, to);
4081
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004082 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004083 if (vimconv.vc_type == CONV_NONE)
4084 rettv->vval.v_string = vim_strsave(str);
4085 else
4086 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4087
4088 convert_setup(&vimconv, NULL, NULL);
4089 vim_free(from);
4090 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091}
4092
4093/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004094 * "index()" function
4095 */
4096 static void
4097f_index(typval_T *argvars, typval_T *rettv)
4098{
4099 list_T *l;
4100 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004101 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004102 long idx = 0;
4103 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004104 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004105
4106 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004107 if (argvars[0].v_type == VAR_BLOB)
4108 {
4109 typval_T tv;
4110 int start = 0;
4111
4112 if (argvars[2].v_type != VAR_UNKNOWN)
4113 {
4114 start = tv_get_number_chk(&argvars[2], &error);
4115 if (error)
4116 return;
4117 }
4118 b = argvars[0].vval.v_blob;
4119 if (b == NULL)
4120 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004121 if (start < 0)
4122 {
4123 start = blob_len(b) + start;
4124 if (start < 0)
4125 start = 0;
4126 }
4127
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004128 for (idx = start; idx < blob_len(b); ++idx)
4129 {
4130 tv.v_type = VAR_NUMBER;
4131 tv.vval.v_number = blob_get(b, idx);
4132 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4133 {
4134 rettv->vval.v_number = idx;
4135 return;
4136 }
4137 }
4138 return;
4139 }
4140 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004141 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004142 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004143 return;
4144 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004145
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004146 l = argvars[0].vval.v_list;
4147 if (l != NULL)
4148 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004149 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004150 item = l->lv_first;
4151 if (argvars[2].v_type != VAR_UNKNOWN)
4152 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004153 // Start at specified item. Use the cached index that list_find()
4154 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004155 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004156 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004157 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004158 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004159 if (error)
4160 item = NULL;
4161 }
4162
4163 for ( ; item != NULL; item = item->li_next, ++idx)
4164 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4165 {
4166 rettv->vval.v_number = idx;
4167 break;
4168 }
4169 }
4170}
4171
4172static int inputsecret_flag = 0;
4173
4174/*
4175 * "input()" function
4176 * Also handles inputsecret() when inputsecret is set.
4177 */
4178 static void
4179f_input(typval_T *argvars, typval_T *rettv)
4180{
4181 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4182}
4183
4184/*
4185 * "inputdialog()" function
4186 */
4187 static void
4188f_inputdialog(typval_T *argvars, typval_T *rettv)
4189{
4190#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004191 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004192 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4193 {
4194 char_u *message;
4195 char_u buf[NUMBUFLEN];
4196 char_u *defstr = (char_u *)"";
4197
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004198 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004199 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004200 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004201 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4202 else
4203 IObuff[0] = NUL;
4204 if (message != NULL && defstr != NULL
4205 && do_dialog(VIM_QUESTION, NULL, message,
4206 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4207 rettv->vval.v_string = vim_strsave(IObuff);
4208 else
4209 {
4210 if (message != NULL && defstr != NULL
4211 && argvars[1].v_type != VAR_UNKNOWN
4212 && argvars[2].v_type != VAR_UNKNOWN)
4213 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004214 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004215 else
4216 rettv->vval.v_string = NULL;
4217 }
4218 rettv->v_type = VAR_STRING;
4219 }
4220 else
4221#endif
4222 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4223}
4224
4225/*
4226 * "inputlist()" function
4227 */
4228 static void
4229f_inputlist(typval_T *argvars, typval_T *rettv)
4230{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004231 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004232 listitem_T *li;
4233 int selected;
4234 int mouse_used;
4235
4236#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004237 // While starting up, there is no place to enter text. When running tests
4238 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004239 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004240 return;
4241#endif
4242 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4243 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004244 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004245 return;
4246 }
4247
4248 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004249 msg_row = Rows - 1; // for when 'cmdheight' > 1
4250 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004251 msg_scroll = TRUE;
4252 msg_clr_eos();
4253
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004254 l = argvars[0].vval.v_list;
4255 range_list_materialize(l);
4256 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004257 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004258 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004259 msg_putchar('\n');
4260 }
4261
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004262 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004263 selected = prompt_for_number(&mouse_used);
4264 if (mouse_used)
4265 selected -= lines_left;
4266
4267 rettv->vval.v_number = selected;
4268}
4269
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004270static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4271
4272/*
4273 * "inputrestore()" function
4274 */
4275 static void
4276f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4277{
4278 if (ga_userinput.ga_len > 0)
4279 {
4280 --ga_userinput.ga_len;
4281 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4282 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004283 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004284 }
4285 else if (p_verbose > 1)
4286 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004287 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004288 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004289 }
4290}
4291
4292/*
4293 * "inputsave()" function
4294 */
4295 static void
4296f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4297{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004298 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004299 if (ga_grow(&ga_userinput, 1) == OK)
4300 {
4301 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4302 + ga_userinput.ga_len);
4303 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004304 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004305 }
4306 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004307 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004308}
4309
4310/*
4311 * "inputsecret()" function
4312 */
4313 static void
4314f_inputsecret(typval_T *argvars, typval_T *rettv)
4315{
4316 ++cmdline_star;
4317 ++inputsecret_flag;
4318 f_input(argvars, rettv);
4319 --cmdline_star;
4320 --inputsecret_flag;
4321}
4322
4323/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004324 * "interrupt()" function
4325 */
4326 static void
4327f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4328{
4329 got_int = TRUE;
4330}
4331
4332/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004333 * "invert(expr)" function
4334 */
4335 static void
4336f_invert(typval_T *argvars, typval_T *rettv)
4337{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004338 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004339}
4340
4341/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004342 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4343 * or it refers to a List or Dictionary that is locked.
4344 */
4345 static int
4346tv_islocked(typval_T *tv)
4347{
4348 return (tv->v_lock & VAR_LOCKED)
4349 || (tv->v_type == VAR_LIST
4350 && tv->vval.v_list != NULL
4351 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4352 || (tv->v_type == VAR_DICT
4353 && tv->vval.v_dict != NULL
4354 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4355}
4356
4357/*
4358 * "islocked()" function
4359 */
4360 static void
4361f_islocked(typval_T *argvars, typval_T *rettv)
4362{
4363 lval_T lv;
4364 char_u *end;
4365 dictitem_T *di;
4366
4367 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004368 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004369 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004370 if (end != NULL && lv.ll_name != NULL)
4371 {
4372 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004373 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004374 else
4375 {
4376 if (lv.ll_tv == NULL)
4377 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004378 di = find_var(lv.ll_name, NULL, TRUE);
4379 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004380 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004381 // Consider a variable locked when:
4382 // 1. the variable itself is locked
4383 // 2. the value of the variable is locked.
4384 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004385 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4386 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004387 }
4388 }
4389 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004390 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004391 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004392 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004393 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004394 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004395 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4396 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004397 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004398 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4399 }
4400 }
4401
4402 clear_lval(&lv);
4403}
4404
4405#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4406/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004407 * "isinf()" function
4408 */
4409 static void
4410f_isinf(typval_T *argvars, typval_T *rettv)
4411{
4412 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4413 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4414}
4415
4416/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004417 * "isnan()" function
4418 */
4419 static void
4420f_isnan(typval_T *argvars, typval_T *rettv)
4421{
4422 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4423 && isnan(argvars[0].vval.v_float);
4424}
4425#endif
4426
4427/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004428 * "last_buffer_nr()" function.
4429 */
4430 static void
4431f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4432{
4433 int n = 0;
4434 buf_T *buf;
4435
Bram Moolenaar29323592016-07-24 22:04:11 +02004436 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004437 if (n < buf->b_fnum)
4438 n = buf->b_fnum;
4439
4440 rettv->vval.v_number = n;
4441}
4442
4443/*
4444 * "len()" function
4445 */
4446 static void
4447f_len(typval_T *argvars, typval_T *rettv)
4448{
4449 switch (argvars[0].v_type)
4450 {
4451 case VAR_STRING:
4452 case VAR_NUMBER:
4453 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004454 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004455 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004456 case VAR_BLOB:
4457 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4458 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004459 case VAR_LIST:
4460 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4461 break;
4462 case VAR_DICT:
4463 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4464 break;
4465 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004466 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004467 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004468 case VAR_SPECIAL:
4469 case VAR_FLOAT:
4470 case VAR_FUNC:
4471 case VAR_PARTIAL:
4472 case VAR_JOB:
4473 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004474 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004475 break;
4476 }
4477}
4478
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004480libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004481{
4482#ifdef FEAT_LIBCALL
4483 char_u *string_in;
4484 char_u **string_result;
4485 int nr_result;
4486#endif
4487
4488 rettv->v_type = type;
4489 if (type != VAR_NUMBER)
4490 rettv->vval.v_string = NULL;
4491
4492 if (check_restricted() || check_secure())
4493 return;
4494
4495#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004496 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004497 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4498 {
4499 string_in = NULL;
4500 if (argvars[2].v_type == VAR_STRING)
4501 string_in = argvars[2].vval.v_string;
4502 if (type == VAR_NUMBER)
4503 string_result = NULL;
4504 else
4505 string_result = &rettv->vval.v_string;
4506 if (mch_libcall(argvars[0].vval.v_string,
4507 argvars[1].vval.v_string,
4508 string_in,
4509 argvars[2].vval.v_number,
4510 string_result,
4511 &nr_result) == OK
4512 && type == VAR_NUMBER)
4513 rettv->vval.v_number = nr_result;
4514 }
4515#endif
4516}
4517
4518/*
4519 * "libcall()" function
4520 */
4521 static void
4522f_libcall(typval_T *argvars, typval_T *rettv)
4523{
4524 libcall_common(argvars, rettv, VAR_STRING);
4525}
4526
4527/*
4528 * "libcallnr()" function
4529 */
4530 static void
4531f_libcallnr(typval_T *argvars, typval_T *rettv)
4532{
4533 libcall_common(argvars, rettv, VAR_NUMBER);
4534}
4535
4536/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004537 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004538 */
4539 static void
4540f_line(typval_T *argvars, typval_T *rettv)
4541{
4542 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004543 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004544 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004545 int id;
4546 tabpage_T *tp;
4547 win_T *wp;
4548 win_T *save_curwin;
4549 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004550
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004551 if (argvars[1].v_type != VAR_UNKNOWN)
4552 {
4553 // use window specified in the second argument
4554 id = (int)tv_get_number(&argvars[1]);
4555 wp = win_id2wp_tp(id, &tp);
4556 if (wp != NULL && tp != NULL)
4557 {
4558 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4559 == OK)
4560 {
4561 check_cursor();
4562 fp = var2fpos(&argvars[0], TRUE, &fnum);
4563 }
4564 restore_win_noblock(save_curwin, save_curtab, TRUE);
4565 }
4566 }
4567 else
4568 // use current window
4569 fp = var2fpos(&argvars[0], TRUE, &fnum);
4570
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004571 if (fp != NULL)
4572 lnum = fp->lnum;
4573 rettv->vval.v_number = lnum;
4574}
4575
4576/*
4577 * "line2byte(lnum)" function
4578 */
4579 static void
4580f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4581{
4582#ifndef FEAT_BYTEOFF
4583 rettv->vval.v_number = -1;
4584#else
4585 linenr_T lnum;
4586
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004587 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004588 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4589 rettv->vval.v_number = -1;
4590 else
4591 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4592 if (rettv->vval.v_number >= 0)
4593 ++rettv->vval.v_number;
4594#endif
4595}
4596
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004597#ifdef FEAT_FLOAT
4598/*
4599 * "log()" function
4600 */
4601 static void
4602f_log(typval_T *argvars, typval_T *rettv)
4603{
4604 float_T f = 0.0;
4605
4606 rettv->v_type = VAR_FLOAT;
4607 if (get_float_arg(argvars, &f) == OK)
4608 rettv->vval.v_float = log(f);
4609 else
4610 rettv->vval.v_float = 0.0;
4611}
4612
4613/*
4614 * "log10()" function
4615 */
4616 static void
4617f_log10(typval_T *argvars, typval_T *rettv)
4618{
4619 float_T f = 0.0;
4620
4621 rettv->v_type = VAR_FLOAT;
4622 if (get_float_arg(argvars, &f) == OK)
4623 rettv->vval.v_float = log10(f);
4624 else
4625 rettv->vval.v_float = 0.0;
4626}
4627#endif
4628
4629#ifdef FEAT_LUA
4630/*
4631 * "luaeval()" function
4632 */
4633 static void
4634f_luaeval(typval_T *argvars, typval_T *rettv)
4635{
4636 char_u *str;
4637 char_u buf[NUMBUFLEN];
4638
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004639 if (check_restricted() || check_secure())
4640 return;
4641
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004642 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004643 do_luaeval(str, argvars + 1, rettv);
4644}
4645#endif
4646
4647/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004648 * "maparg()" function
4649 */
4650 static void
4651f_maparg(typval_T *argvars, typval_T *rettv)
4652{
4653 get_maparg(argvars, rettv, TRUE);
4654}
4655
4656/*
4657 * "mapcheck()" function
4658 */
4659 static void
4660f_mapcheck(typval_T *argvars, typval_T *rettv)
4661{
4662 get_maparg(argvars, rettv, FALSE);
4663}
4664
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004665typedef enum
4666{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004667 MATCH_END, // matchend()
4668 MATCH_MATCH, // match()
4669 MATCH_STR, // matchstr()
4670 MATCH_LIST, // matchlist()
4671 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004672} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004673
4674 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004675find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004676{
4677 char_u *str = NULL;
4678 long len = 0;
4679 char_u *expr = NULL;
4680 char_u *pat;
4681 regmatch_T regmatch;
4682 char_u patbuf[NUMBUFLEN];
4683 char_u strbuf[NUMBUFLEN];
4684 char_u *save_cpo;
4685 long start = 0;
4686 long nth = 1;
4687 colnr_T startcol = 0;
4688 int match = 0;
4689 list_T *l = NULL;
4690 listitem_T *li = NULL;
4691 long idx = 0;
4692 char_u *tofree = NULL;
4693
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004694 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004695 save_cpo = p_cpo;
4696 p_cpo = (char_u *)"";
4697
4698 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004699 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004701 // type MATCH_LIST: return empty list when there are no matches.
4702 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004703 if (rettv_list_alloc(rettv) == FAIL)
4704 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004705 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004706 && (list_append_string(rettv->vval.v_list,
4707 (char_u *)"", 0) == FAIL
4708 || list_append_number(rettv->vval.v_list,
4709 (varnumber_T)-1) == FAIL
4710 || list_append_number(rettv->vval.v_list,
4711 (varnumber_T)-1) == FAIL
4712 || list_append_number(rettv->vval.v_list,
4713 (varnumber_T)-1) == FAIL))
4714 {
4715 list_free(rettv->vval.v_list);
4716 rettv->vval.v_list = NULL;
4717 goto theend;
4718 }
4719 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004720 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004721 {
4722 rettv->v_type = VAR_STRING;
4723 rettv->vval.v_string = NULL;
4724 }
4725
4726 if (argvars[0].v_type == VAR_LIST)
4727 {
4728 if ((l = argvars[0].vval.v_list) == NULL)
4729 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004730 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004731 li = l->lv_first;
4732 }
4733 else
4734 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004735 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004736 len = (long)STRLEN(str);
4737 }
4738
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004739 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004740 if (pat == NULL)
4741 goto theend;
4742
4743 if (argvars[2].v_type != VAR_UNKNOWN)
4744 {
4745 int error = FALSE;
4746
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004747 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748 if (error)
4749 goto theend;
4750 if (l != NULL)
4751 {
4752 li = list_find(l, start);
4753 if (li == NULL)
4754 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004755 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004756 }
4757 else
4758 {
4759 if (start < 0)
4760 start = 0;
4761 if (start > len)
4762 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004763 // When "count" argument is there ignore matches before "start",
4764 // otherwise skip part of the string. Differs when pattern is "^"
4765 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766 if (argvars[3].v_type != VAR_UNKNOWN)
4767 startcol = start;
4768 else
4769 {
4770 str += start;
4771 len -= start;
4772 }
4773 }
4774
4775 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004776 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004777 if (error)
4778 goto theend;
4779 }
4780
4781 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4782 if (regmatch.regprog != NULL)
4783 {
4784 regmatch.rm_ic = p_ic;
4785
4786 for (;;)
4787 {
4788 if (l != NULL)
4789 {
4790 if (li == NULL)
4791 {
4792 match = FALSE;
4793 break;
4794 }
4795 vim_free(tofree);
4796 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4797 if (str == NULL)
4798 break;
4799 }
4800
4801 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4802
4803 if (match && --nth <= 0)
4804 break;
4805 if (l == NULL && !match)
4806 break;
4807
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004808 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004809 if (l != NULL)
4810 {
4811 li = li->li_next;
4812 ++idx;
4813 }
4814 else
4815 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004816 startcol = (colnr_T)(regmatch.startp[0]
4817 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004818 if (startcol > (colnr_T)len
4819 || str + startcol <= regmatch.startp[0])
4820 {
4821 match = FALSE;
4822 break;
4823 }
4824 }
4825 }
4826
4827 if (match)
4828 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004829 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004830 {
4831 listitem_T *li1 = rettv->vval.v_list->lv_first;
4832 listitem_T *li2 = li1->li_next;
4833 listitem_T *li3 = li2->li_next;
4834 listitem_T *li4 = li3->li_next;
4835
4836 vim_free(li1->li_tv.vval.v_string);
4837 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4838 (int)(regmatch.endp[0] - regmatch.startp[0]));
4839 li3->li_tv.vval.v_number =
4840 (varnumber_T)(regmatch.startp[0] - expr);
4841 li4->li_tv.vval.v_number =
4842 (varnumber_T)(regmatch.endp[0] - expr);
4843 if (l != NULL)
4844 li2->li_tv.vval.v_number = (varnumber_T)idx;
4845 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004846 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004847 {
4848 int i;
4849
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004850 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004851 for (i = 0; i < NSUBEXP; ++i)
4852 {
4853 if (regmatch.endp[i] == NULL)
4854 {
4855 if (list_append_string(rettv->vval.v_list,
4856 (char_u *)"", 0) == FAIL)
4857 break;
4858 }
4859 else if (list_append_string(rettv->vval.v_list,
4860 regmatch.startp[i],
4861 (int)(regmatch.endp[i] - regmatch.startp[i]))
4862 == FAIL)
4863 break;
4864 }
4865 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004866 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004867 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004868 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004869 if (l != NULL)
4870 copy_tv(&li->li_tv, rettv);
4871 else
4872 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4873 (int)(regmatch.endp[0] - regmatch.startp[0]));
4874 }
4875 else if (l != NULL)
4876 rettv->vval.v_number = idx;
4877 else
4878 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004879 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004880 rettv->vval.v_number =
4881 (varnumber_T)(regmatch.startp[0] - str);
4882 else
4883 rettv->vval.v_number =
4884 (varnumber_T)(regmatch.endp[0] - str);
4885 rettv->vval.v_number += (varnumber_T)(str - expr);
4886 }
4887 }
4888 vim_regfree(regmatch.regprog);
4889 }
4890
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004891theend:
4892 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004893 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894 listitem_remove(rettv->vval.v_list,
4895 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004896 vim_free(tofree);
4897 p_cpo = save_cpo;
4898}
4899
4900/*
4901 * "match()" function
4902 */
4903 static void
4904f_match(typval_T *argvars, typval_T *rettv)
4905{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004906 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004907}
4908
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909/*
4910 * "matchend()" function
4911 */
4912 static void
4913f_matchend(typval_T *argvars, typval_T *rettv)
4914{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004915 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004916}
4917
4918/*
4919 * "matchlist()" function
4920 */
4921 static void
4922f_matchlist(typval_T *argvars, typval_T *rettv)
4923{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004924 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004925}
4926
4927/*
4928 * "matchstr()" function
4929 */
4930 static void
4931f_matchstr(typval_T *argvars, typval_T *rettv)
4932{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004933 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004934}
4935
4936/*
4937 * "matchstrpos()" function
4938 */
4939 static void
4940f_matchstrpos(typval_T *argvars, typval_T *rettv)
4941{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004942 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004943}
4944
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945 static void
4946max_min(typval_T *argvars, typval_T *rettv, int domax)
4947{
4948 varnumber_T n = 0;
4949 varnumber_T i;
4950 int error = FALSE;
4951
4952 if (argvars[0].v_type == VAR_LIST)
4953 {
4954 list_T *l;
4955 listitem_T *li;
4956
4957 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004958 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004959 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004960 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004962 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4963 n = l->lv_u.nonmat.lv_start;
4964 else
4965 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4966 * l->lv_u.nonmat.lv_stride;
4967 }
4968 else
4969 {
4970 li = l->lv_first;
4971 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004973 n = tv_get_number_chk(&li->li_tv, &error);
4974 for (;;)
4975 {
4976 li = li->li_next;
4977 if (li == NULL)
4978 break;
4979 i = tv_get_number_chk(&li->li_tv, &error);
4980 if (domax ? i > n : i < n)
4981 n = i;
4982 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004983 }
4984 }
4985 }
4986 }
4987 else if (argvars[0].v_type == VAR_DICT)
4988 {
4989 dict_T *d;
4990 int first = TRUE;
4991 hashitem_T *hi;
4992 int todo;
4993
4994 d = argvars[0].vval.v_dict;
4995 if (d != NULL)
4996 {
4997 todo = (int)d->dv_hashtab.ht_used;
4998 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4999 {
5000 if (!HASHITEM_EMPTY(hi))
5001 {
5002 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005003 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005004 if (first)
5005 {
5006 n = i;
5007 first = FALSE;
5008 }
5009 else if (domax ? i > n : i < n)
5010 n = i;
5011 }
5012 }
5013 }
5014 }
5015 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005016 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005017 rettv->vval.v_number = error ? 0 : n;
5018}
5019
5020/*
5021 * "max()" function
5022 */
5023 static void
5024f_max(typval_T *argvars, typval_T *rettv)
5025{
5026 max_min(argvars, rettv, TRUE);
5027}
5028
5029/*
5030 * "min()" function
5031 */
5032 static void
5033f_min(typval_T *argvars, typval_T *rettv)
5034{
5035 max_min(argvars, rettv, FALSE);
5036}
5037
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005038#if defined(FEAT_MZSCHEME) || defined(PROTO)
5039/*
5040 * "mzeval()" function
5041 */
5042 static void
5043f_mzeval(typval_T *argvars, typval_T *rettv)
5044{
5045 char_u *str;
5046 char_u buf[NUMBUFLEN];
5047
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005048 if (check_restricted() || check_secure())
5049 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005050 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005051 do_mzeval(str, rettv);
5052}
5053
5054 void
5055mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5056{
5057 typval_T argvars[3];
5058
5059 argvars[0].v_type = VAR_STRING;
5060 argvars[0].vval.v_string = name;
5061 copy_tv(args, &argvars[1]);
5062 argvars[2].v_type = VAR_UNKNOWN;
5063 f_call(argvars, rettv);
5064 clear_tv(&argvars[1]);
5065}
5066#endif
5067
5068/*
5069 * "nextnonblank()" function
5070 */
5071 static void
5072f_nextnonblank(typval_T *argvars, typval_T *rettv)
5073{
5074 linenr_T lnum;
5075
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005076 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 {
5078 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5079 {
5080 lnum = 0;
5081 break;
5082 }
5083 if (*skipwhite(ml_get(lnum)) != NUL)
5084 break;
5085 }
5086 rettv->vval.v_number = lnum;
5087}
5088
5089/*
5090 * "nr2char()" function
5091 */
5092 static void
5093f_nr2char(typval_T *argvars, typval_T *rettv)
5094{
5095 char_u buf[NUMBUFLEN];
5096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097 if (has_mbyte)
5098 {
5099 int utf8 = 0;
5100
5101 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005102 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005104 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005106 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 }
5108 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005110 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005111 buf[1] = NUL;
5112 }
5113 rettv->v_type = VAR_STRING;
5114 rettv->vval.v_string = vim_strsave(buf);
5115}
5116
5117/*
5118 * "or(expr, expr)" function
5119 */
5120 static void
5121f_or(typval_T *argvars, typval_T *rettv)
5122{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005123 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5124 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005125}
5126
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127#ifdef FEAT_PERL
5128/*
5129 * "perleval()" function
5130 */
5131 static void
5132f_perleval(typval_T *argvars, typval_T *rettv)
5133{
5134 char_u *str;
5135 char_u buf[NUMBUFLEN];
5136
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005137 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005138 do_perleval(str, rettv);
5139}
5140#endif
5141
5142#ifdef FEAT_FLOAT
5143/*
5144 * "pow()" function
5145 */
5146 static void
5147f_pow(typval_T *argvars, typval_T *rettv)
5148{
5149 float_T fx = 0.0, fy = 0.0;
5150
5151 rettv->v_type = VAR_FLOAT;
5152 if (get_float_arg(argvars, &fx) == OK
5153 && get_float_arg(&argvars[1], &fy) == OK)
5154 rettv->vval.v_float = pow(fx, fy);
5155 else
5156 rettv->vval.v_float = 0.0;
5157}
5158#endif
5159
5160/*
5161 * "prevnonblank()" function
5162 */
5163 static void
5164f_prevnonblank(typval_T *argvars, typval_T *rettv)
5165{
5166 linenr_T lnum;
5167
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005168 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005169 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5170 lnum = 0;
5171 else
5172 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5173 --lnum;
5174 rettv->vval.v_number = lnum;
5175}
5176
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005177// This dummy va_list is here because:
5178// - passing a NULL pointer doesn't work when va_list isn't a pointer
5179// - locally in the function results in a "used before set" warning
5180// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005181static va_list ap;
5182
5183/*
5184 * "printf()" function
5185 */
5186 static void
5187f_printf(typval_T *argvars, typval_T *rettv)
5188{
5189 char_u buf[NUMBUFLEN];
5190 int len;
5191 char_u *s;
5192 int saved_did_emsg = did_emsg;
5193 char *fmt;
5194
5195 rettv->v_type = VAR_STRING;
5196 rettv->vval.v_string = NULL;
5197
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005198 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005200 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005201 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005202 if (!did_emsg)
5203 {
5204 s = alloc(len + 1);
5205 if (s != NULL)
5206 {
5207 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005208 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5209 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005210 }
5211 }
5212 did_emsg |= saved_did_emsg;
5213}
5214
5215/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005216 * "pum_getpos()" function
5217 */
5218 static void
5219f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5220{
5221 if (rettv_dict_alloc(rettv) != OK)
5222 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005223 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005224}
5225
5226/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005227 * "pumvisible()" function
5228 */
5229 static void
5230f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5231{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005232 if (pum_visible())
5233 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005234}
5235
5236#ifdef FEAT_PYTHON3
5237/*
5238 * "py3eval()" function
5239 */
5240 static void
5241f_py3eval(typval_T *argvars, typval_T *rettv)
5242{
5243 char_u *str;
5244 char_u buf[NUMBUFLEN];
5245
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005246 if (check_restricted() || check_secure())
5247 return;
5248
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005249 if (p_pyx == 0)
5250 p_pyx = 3;
5251
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005252 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005253 do_py3eval(str, rettv);
5254}
5255#endif
5256
5257#ifdef FEAT_PYTHON
5258/*
5259 * "pyeval()" function
5260 */
5261 static void
5262f_pyeval(typval_T *argvars, typval_T *rettv)
5263{
5264 char_u *str;
5265 char_u buf[NUMBUFLEN];
5266
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005267 if (check_restricted() || check_secure())
5268 return;
5269
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005270 if (p_pyx == 0)
5271 p_pyx = 2;
5272
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005273 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005274 do_pyeval(str, rettv);
5275}
5276#endif
5277
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005278#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5279/*
5280 * "pyxeval()" function
5281 */
5282 static void
5283f_pyxeval(typval_T *argvars, typval_T *rettv)
5284{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005285 if (check_restricted() || check_secure())
5286 return;
5287
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005288# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5289 init_pyxversion();
5290 if (p_pyx == 2)
5291 f_pyeval(argvars, rettv);
5292 else
5293 f_py3eval(argvars, rettv);
5294# elif defined(FEAT_PYTHON)
5295 f_pyeval(argvars, rettv);
5296# elif defined(FEAT_PYTHON3)
5297 f_py3eval(argvars, rettv);
5298# endif
5299}
5300#endif
5301
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005302static UINT32_T srand_seed_for_testing = 0;
5303static int srand_seed_for_testing_is_used = FALSE;
5304
5305 static void
5306f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5307{
5308 if (argvars[0].v_type == VAR_UNKNOWN)
5309 srand_seed_for_testing_is_used = FALSE;
5310 else
5311 {
5312 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5313 srand_seed_for_testing_is_used = TRUE;
5314 }
5315}
5316
5317 static void
5318init_srand(UINT32_T *x)
5319{
5320#ifndef MSWIN
5321 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5322#endif
5323
5324 if (srand_seed_for_testing_is_used)
5325 {
5326 *x = srand_seed_for_testing;
5327 return;
5328 }
5329#ifndef MSWIN
5330 if (dev_urandom_state != FAIL)
5331 {
5332 int fd = open("/dev/urandom", O_RDONLY);
5333 struct {
5334 union {
5335 UINT32_T number;
5336 char bytes[sizeof(UINT32_T)];
5337 } contents;
5338 } buf;
5339
5340 // Attempt reading /dev/urandom.
5341 if (fd == -1)
5342 dev_urandom_state = FAIL;
5343 else
5344 {
5345 buf.contents.number = 0;
5346 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5347 != sizeof(UINT32_T))
5348 dev_urandom_state = FAIL;
5349 else
5350 {
5351 dev_urandom_state = OK;
5352 *x = buf.contents.number;
5353 }
5354 close(fd);
5355 }
5356 }
5357 if (dev_urandom_state != OK)
5358 // Reading /dev/urandom doesn't work, fall back to time().
5359#endif
5360 *x = vim_time();
5361}
5362
5363#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5364#define SPLITMIX32(x, z) ( \
5365 z = (x += 0x9e3779b9), \
5366 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5367 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5368 z ^ (z >> 16) \
5369 )
5370#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5371 result = ROTL(y * 5, 7) * 9; \
5372 t = y << 9; \
5373 z ^= x; \
5374 w ^= y; \
5375 y ^= z, x ^= w; \
5376 z ^= t; \
5377 w = ROTL(w, 11);
5378
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005380 * "rand()" function
5381 */
5382 static void
5383f_rand(typval_T *argvars, typval_T *rettv)
5384{
5385 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005386 static UINT32_T gx, gy, gz, gw;
5387 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005388 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005389 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005390
5391 if (argvars[0].v_type == VAR_UNKNOWN)
5392 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005393 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005394 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005395 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005396 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005397 init_srand(&x);
5398
5399 gx = SPLITMIX32(x, z);
5400 gy = SPLITMIX32(x, z);
5401 gz = SPLITMIX32(x, z);
5402 gw = SPLITMIX32(x, z);
5403 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005404 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005405
5406 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005407 }
5408 else if (argvars[0].v_type == VAR_LIST)
5409 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005410 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005411 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005412 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005413
5414 lx = list_find(l, 0L);
5415 ly = list_find(l, 1L);
5416 lz = list_find(l, 2L);
5417 lw = list_find(l, 3L);
5418 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5419 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5420 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5421 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5422 x = (UINT32_T)lx->li_tv.vval.v_number;
5423 y = (UINT32_T)ly->li_tv.vval.v_number;
5424 z = (UINT32_T)lz->li_tv.vval.v_number;
5425 w = (UINT32_T)lw->li_tv.vval.v_number;
5426
5427 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5428
5429 lx->li_tv.vval.v_number = (varnumber_T)x;
5430 ly->li_tv.vval.v_number = (varnumber_T)y;
5431 lz->li_tv.vval.v_number = (varnumber_T)z;
5432 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005433 }
5434 else
5435 goto theend;
5436
5437 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005438 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005439 return;
5440
5441theend:
5442 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005443 rettv->v_type = VAR_NUMBER;
5444 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005445}
5446
5447/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005448 * "srand()" function
5449 */
5450 static void
5451f_srand(typval_T *argvars, typval_T *rettv)
5452{
5453 UINT32_T x = 0, z;
5454
5455 if (rettv_list_alloc(rettv) == FAIL)
5456 return;
5457 if (argvars[0].v_type == VAR_UNKNOWN)
5458 {
5459 init_srand(&x);
5460 }
5461 else
5462 {
5463 int error = FALSE;
5464
5465 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5466 if (error)
5467 return;
5468 }
5469
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 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5474}
5475
5476#undef ROTL
5477#undef SPLITMIX32
5478#undef SHUFFLE_XOSHIRO128STARSTAR
5479
5480/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005481 * "range()" function
5482 */
5483 static void
5484f_range(typval_T *argvars, typval_T *rettv)
5485{
5486 varnumber_T start;
5487 varnumber_T end;
5488 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489 int error = FALSE;
5490
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005491 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005492 if (argvars[1].v_type == VAR_UNKNOWN)
5493 {
5494 end = start - 1;
5495 start = 0;
5496 }
5497 else
5498 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005499 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005500 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005501 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502 }
5503
5504 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005505 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005506 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005507 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005508 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005509 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005510 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005512 list_T *list = rettv->vval.v_list;
5513
5514 // Create a non-materialized list. This is much more efficient and
5515 // works with ":for". If used otherwise range_list_materialize() must
5516 // be called.
5517 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005518 list->lv_u.nonmat.lv_start = start;
5519 list->lv_u.nonmat.lv_end = end;
5520 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005521 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005522 }
5523}
5524
5525/*
5526 * If "list" is a non-materialized list then materialize it now.
5527 */
5528 void
5529range_list_materialize(list_T *list)
5530{
5531 if (list->lv_first == &range_list_item)
5532 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005533 varnumber_T start = list->lv_u.nonmat.lv_start;
5534 varnumber_T end = list->lv_u.nonmat.lv_end;
5535 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005536 varnumber_T i;
5537
5538 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005539 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005540 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005541 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005542 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5543 if (list_append_number(list, (varnumber_T)i) == FAIL)
5544 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005545 }
5546}
5547
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005548 static void
5549return_register(int regname, typval_T *rettv)
5550{
5551 char_u buf[2] = {0, 0};
5552
5553 buf[0] = (char_u)regname;
5554 rettv->v_type = VAR_STRING;
5555 rettv->vval.v_string = vim_strsave(buf);
5556}
5557
5558/*
5559 * "reg_executing()" function
5560 */
5561 static void
5562f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5563{
5564 return_register(reg_executing, rettv);
5565}
5566
5567/*
5568 * "reg_recording()" function
5569 */
5570 static void
5571f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5572{
5573 return_register(reg_recording, rettv);
5574}
5575
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005576#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 static void
5578make_connection(void)
5579{
5580 if (X_DISPLAY == NULL
5581# ifdef FEAT_GUI
5582 && !gui.in_use
5583# endif
5584 )
5585 {
5586 x_force_connect = TRUE;
5587 setup_term_clip();
5588 x_force_connect = FALSE;
5589 }
5590}
5591
5592 static int
5593check_connection(void)
5594{
5595 make_connection();
5596 if (X_DISPLAY == NULL)
5597 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005598 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005599 return FAIL;
5600 }
5601 return OK;
5602}
5603#endif
5604
5605#ifdef FEAT_CLIENTSERVER
5606 static void
5607remote_common(typval_T *argvars, typval_T *rettv, int expr)
5608{
5609 char_u *server_name;
5610 char_u *keys;
5611 char_u *r = NULL;
5612 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005613 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005614# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005615 HWND w;
5616# else
5617 Window w;
5618# endif
5619
5620 if (check_restricted() || check_secure())
5621 return;
5622
5623# ifdef FEAT_X11
5624 if (check_connection() == FAIL)
5625 return;
5626# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005627 if (argvars[2].v_type != VAR_UNKNOWN
5628 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005629 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005631 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005632 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005633 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005634 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005635# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005636 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005637# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005638 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5639 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005640# endif
5641 {
5642 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005643 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005644 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005645 vim_free(r);
5646 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005647 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005648 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005649 return;
5650 }
5651
5652 rettv->vval.v_string = r;
5653
5654 if (argvars[2].v_type != VAR_UNKNOWN)
5655 {
5656 dictitem_T v;
5657 char_u str[30];
5658 char_u *idvar;
5659
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005660 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005661 if (idvar != NULL && *idvar != NUL)
5662 {
5663 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5664 v.di_tv.v_type = VAR_STRING;
5665 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005666 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005667 vim_free(v.di_tv.vval.v_string);
5668 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005669 }
5670}
5671#endif
5672
5673/*
5674 * "remote_expr()" function
5675 */
5676 static void
5677f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5678{
5679 rettv->v_type = VAR_STRING;
5680 rettv->vval.v_string = NULL;
5681#ifdef FEAT_CLIENTSERVER
5682 remote_common(argvars, rettv, TRUE);
5683#endif
5684}
5685
5686/*
5687 * "remote_foreground()" function
5688 */
5689 static void
5690f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5691{
5692#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005693# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005694 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005695 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005696 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005697
5698 if (server_name != NULL)
5699 serverForeground(server_name);
5700 }
5701# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005702 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005703 argvars[1].v_type = VAR_STRING;
5704 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5705 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005706 rettv->v_type = VAR_STRING;
5707 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005708 remote_common(argvars, rettv, TRUE);
5709 vim_free(argvars[1].vval.v_string);
5710# endif
5711#endif
5712}
5713
5714 static void
5715f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5716{
5717#ifdef FEAT_CLIENTSERVER
5718 dictitem_T v;
5719 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005720# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005721 long_u n = 0;
5722# endif
5723 char_u *serverid;
5724
5725 if (check_restricted() || check_secure())
5726 {
5727 rettv->vval.v_number = -1;
5728 return;
5729 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005730 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005731 if (serverid == NULL)
5732 {
5733 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005734 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005735 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005736# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005737 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5738 if (n == 0)
5739 rettv->vval.v_number = -1;
5740 else
5741 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005742 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743 rettv->vval.v_number = (s != NULL);
5744 }
5745# else
5746 if (check_connection() == FAIL)
5747 return;
5748
5749 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5750 serverStrToWin(serverid), &s);
5751# endif
5752
5753 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5754 {
5755 char_u *retvar;
5756
5757 v.di_tv.v_type = VAR_STRING;
5758 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005759 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005760 if (retvar != NULL)
5761 set_var(retvar, &v.di_tv, FALSE);
5762 vim_free(v.di_tv.vval.v_string);
5763 }
5764#else
5765 rettv->vval.v_number = -1;
5766#endif
5767}
5768
5769 static void
5770f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5771{
5772 char_u *r = NULL;
5773
5774#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005775 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005776
5777 if (serverid != NULL && !check_restricted() && !check_secure())
5778 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005779 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005780# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005781 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005782 long_u n = 0;
5783# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005784
5785 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005786 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005787
Bram Moolenaar4f974752019-02-17 17:44:42 +01005788# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005789 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5790 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005791 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 if (r == NULL)
5793# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005794 if (check_connection() == FAIL
5795 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5796 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005797# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005798 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 }
5800#endif
5801 rettv->v_type = VAR_STRING;
5802 rettv->vval.v_string = r;
5803}
5804
5805/*
5806 * "remote_send()" function
5807 */
5808 static void
5809f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5810{
5811 rettv->v_type = VAR_STRING;
5812 rettv->vval.v_string = NULL;
5813#ifdef FEAT_CLIENTSERVER
5814 remote_common(argvars, rettv, FALSE);
5815#endif
5816}
5817
5818/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005819 * "remote_startserver()" function
5820 */
5821 static void
5822f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5823{
5824#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005825 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005826
5827 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005828 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005829 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005830 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005831 else
5832 {
5833# ifdef FEAT_X11
5834 if (check_connection() == OK)
5835 serverRegisterName(X_DISPLAY, server);
5836# else
5837 serverSetName(server);
5838# endif
5839 }
5840#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005841 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005842#endif
5843}
5844
5845/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005846 * "rename({from}, {to})" function
5847 */
5848 static void
5849f_rename(typval_T *argvars, typval_T *rettv)
5850{
5851 char_u buf[NUMBUFLEN];
5852
5853 if (check_restricted() || check_secure())
5854 rettv->vval.v_number = -1;
5855 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005856 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5857 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005858}
5859
5860/*
5861 * "repeat()" function
5862 */
5863 static void
5864f_repeat(typval_T *argvars, typval_T *rettv)
5865{
5866 char_u *p;
5867 int n;
5868 int slen;
5869 int len;
5870 char_u *r;
5871 int i;
5872
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005873 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005874 if (argvars[0].v_type == VAR_LIST)
5875 {
5876 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5877 while (n-- > 0)
5878 if (list_extend(rettv->vval.v_list,
5879 argvars[0].vval.v_list, NULL) == FAIL)
5880 break;
5881 }
5882 else
5883 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005884 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 rettv->v_type = VAR_STRING;
5886 rettv->vval.v_string = NULL;
5887
5888 slen = (int)STRLEN(p);
5889 len = slen * n;
5890 if (len <= 0)
5891 return;
5892
5893 r = alloc(len + 1);
5894 if (r != NULL)
5895 {
5896 for (i = 0; i < n; i++)
5897 mch_memmove(r + i * slen, p, (size_t)slen);
5898 r[len] = NUL;
5899 }
5900
5901 rettv->vval.v_string = r;
5902 }
5903}
5904
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005905#define SP_NOMOVE 0x01 // don't move cursor
5906#define SP_REPEAT 0x02 // repeat to find outer pair
5907#define SP_RETCOUNT 0x04 // return matchcount
5908#define SP_SETPCMARK 0x08 // set previous context mark
5909#define SP_START 0x10 // accept match at start position
5910#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5911#define SP_END 0x40 // leave cursor at end of match
5912#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005913
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914/*
5915 * Get flags for a search function.
5916 * Possibly sets "p_ws".
5917 * Returns BACKWARD, FORWARD or zero (for an error).
5918 */
5919 static int
5920get_search_arg(typval_T *varp, int *flagsp)
5921{
5922 int dir = FORWARD;
5923 char_u *flags;
5924 char_u nbuf[NUMBUFLEN];
5925 int mask;
5926
5927 if (varp->v_type != VAR_UNKNOWN)
5928 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005929 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005930 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005931 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005932 while (*flags != NUL)
5933 {
5934 switch (*flags)
5935 {
5936 case 'b': dir = BACKWARD; break;
5937 case 'w': p_ws = TRUE; break;
5938 case 'W': p_ws = FALSE; break;
5939 default: mask = 0;
5940 if (flagsp != NULL)
5941 switch (*flags)
5942 {
5943 case 'c': mask = SP_START; break;
5944 case 'e': mask = SP_END; break;
5945 case 'm': mask = SP_RETCOUNT; break;
5946 case 'n': mask = SP_NOMOVE; break;
5947 case 'p': mask = SP_SUBPAT; break;
5948 case 'r': mask = SP_REPEAT; break;
5949 case 's': mask = SP_SETPCMARK; break;
5950 case 'z': mask = SP_COLUMN; break;
5951 }
5952 if (mask == 0)
5953 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005954 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005955 dir = 0;
5956 }
5957 else
5958 *flagsp |= mask;
5959 }
5960 if (dir == 0)
5961 break;
5962 ++flags;
5963 }
5964 }
5965 return dir;
5966}
5967
5968/*
5969 * Shared by search() and searchpos() functions.
5970 */
5971 static int
5972search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5973{
5974 int flags;
5975 char_u *pat;
5976 pos_T pos;
5977 pos_T save_cursor;
5978 int save_p_ws = p_ws;
5979 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005980 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005981 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005982#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005983 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005984 long time_limit = 0;
5985#endif
5986 int options = SEARCH_KEEP;
5987 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005988 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005989
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005990 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005991 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005992 if (dir == 0)
5993 goto theend;
5994 flags = *flagsp;
5995 if (flags & SP_START)
5996 options |= SEARCH_START;
5997 if (flags & SP_END)
5998 options |= SEARCH_END;
5999 if (flags & SP_COLUMN)
6000 options |= SEARCH_COL;
6001
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006002 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006003 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6004 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006005 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006 if (lnum_stop < 0)
6007 goto theend;
6008#ifdef FEAT_RELTIME
6009 if (argvars[3].v_type != VAR_UNKNOWN)
6010 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006011 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006012 if (time_limit < 0)
6013 goto theend;
6014 }
6015#endif
6016 }
6017
6018#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006019 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006020 profile_setlimit(time_limit, &tm);
6021#endif
6022
6023 /*
6024 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6025 * Check to make sure only those flags are set.
6026 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6027 * flags cannot be set. Check for that condition also.
6028 */
6029 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6030 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6031 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006032 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006033 goto theend;
6034 }
6035
6036 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006037 vim_memset(&sia, 0, sizeof(sia));
6038 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6039#ifdef FEAT_RELTIME
6040 sia.sa_tm = &tm;
6041#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006042 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006043 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006044 if (subpatnum != FAIL)
6045 {
6046 if (flags & SP_SUBPAT)
6047 retval = subpatnum;
6048 else
6049 retval = pos.lnum;
6050 if (flags & SP_SETPCMARK)
6051 setpcmark();
6052 curwin->w_cursor = pos;
6053 if (match_pos != NULL)
6054 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006055 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006056 match_pos->lnum = pos.lnum;
6057 match_pos->col = pos.col + 1;
6058 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006059 // "/$" will put the cursor after the end of the line, may need to
6060 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006061 check_cursor();
6062 }
6063
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006064 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065 if (flags & SP_NOMOVE)
6066 curwin->w_cursor = save_cursor;
6067 else
6068 curwin->w_set_curswant = TRUE;
6069theend:
6070 p_ws = save_p_ws;
6071
6072 return retval;
6073}
6074
6075#ifdef FEAT_FLOAT
6076
6077/*
6078 * round() is not in C90, use ceil() or floor() instead.
6079 */
6080 float_T
6081vim_round(float_T f)
6082{
6083 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6084}
6085
6086/*
6087 * "round({float})" function
6088 */
6089 static void
6090f_round(typval_T *argvars, typval_T *rettv)
6091{
6092 float_T f = 0.0;
6093
6094 rettv->v_type = VAR_FLOAT;
6095 if (get_float_arg(argvars, &f) == OK)
6096 rettv->vval.v_float = vim_round(f);
6097 else
6098 rettv->vval.v_float = 0.0;
6099}
6100#endif
6101
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006102#ifdef FEAT_RUBY
6103/*
6104 * "rubyeval()" function
6105 */
6106 static void
6107f_rubyeval(typval_T *argvars, typval_T *rettv)
6108{
6109 char_u *str;
6110 char_u buf[NUMBUFLEN];
6111
6112 str = tv_get_string_buf(&argvars[0], buf);
6113 do_rubyeval(str, rettv);
6114}
6115#endif
6116
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006117/*
6118 * "screenattr()" function
6119 */
6120 static void
6121f_screenattr(typval_T *argvars, typval_T *rettv)
6122{
6123 int row;
6124 int col;
6125 int c;
6126
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006127 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6128 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006129 if (row < 0 || row >= screen_Rows
6130 || col < 0 || col >= screen_Columns)
6131 c = -1;
6132 else
6133 c = ScreenAttrs[LineOffset[row] + col];
6134 rettv->vval.v_number = c;
6135}
6136
6137/*
6138 * "screenchar()" function
6139 */
6140 static void
6141f_screenchar(typval_T *argvars, typval_T *rettv)
6142{
6143 int row;
6144 int col;
6145 int off;
6146 int c;
6147
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006148 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6149 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006150 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006151 c = -1;
6152 else
6153 {
6154 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006155 if (enc_utf8 && ScreenLinesUC[off] != 0)
6156 c = ScreenLinesUC[off];
6157 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006158 c = ScreenLines[off];
6159 }
6160 rettv->vval.v_number = c;
6161}
6162
6163/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006164 * "screenchars()" function
6165 */
6166 static void
6167f_screenchars(typval_T *argvars, typval_T *rettv)
6168{
6169 int row;
6170 int col;
6171 int off;
6172 int c;
6173 int i;
6174
6175 if (rettv_list_alloc(rettv) == FAIL)
6176 return;
6177 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6178 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6179 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6180 return;
6181
6182 off = LineOffset[row] + col;
6183 if (enc_utf8 && ScreenLinesUC[off] != 0)
6184 c = ScreenLinesUC[off];
6185 else
6186 c = ScreenLines[off];
6187 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6188
6189 if (enc_utf8)
6190
6191 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6192 list_append_number(rettv->vval.v_list,
6193 (varnumber_T)ScreenLinesC[i][off]);
6194}
6195
6196/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197 * "screencol()" function
6198 *
6199 * First column is 1 to be consistent with virtcol().
6200 */
6201 static void
6202f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6203{
6204 rettv->vval.v_number = screen_screencol() + 1;
6205}
6206
6207/*
6208 * "screenrow()" function
6209 */
6210 static void
6211f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6212{
6213 rettv->vval.v_number = screen_screenrow() + 1;
6214}
6215
6216/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006217 * "screenstring()" function
6218 */
6219 static void
6220f_screenstring(typval_T *argvars, typval_T *rettv)
6221{
6222 int row;
6223 int col;
6224 int off;
6225 int c;
6226 int i;
6227 char_u buf[MB_MAXBYTES + 1];
6228 int buflen = 0;
6229
6230 rettv->vval.v_string = NULL;
6231 rettv->v_type = VAR_STRING;
6232
6233 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6234 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6235 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6236 return;
6237
6238 off = LineOffset[row] + col;
6239 if (enc_utf8 && ScreenLinesUC[off] != 0)
6240 c = ScreenLinesUC[off];
6241 else
6242 c = ScreenLines[off];
6243 buflen += mb_char2bytes(c, buf);
6244
6245 if (enc_utf8)
6246 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6247 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6248
6249 buf[buflen] = NUL;
6250 rettv->vval.v_string = vim_strsave(buf);
6251}
6252
6253/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006254 * "search()" function
6255 */
6256 static void
6257f_search(typval_T *argvars, typval_T *rettv)
6258{
6259 int flags = 0;
6260
6261 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6262}
6263
6264/*
6265 * "searchdecl()" function
6266 */
6267 static void
6268f_searchdecl(typval_T *argvars, typval_T *rettv)
6269{
6270 int locally = 1;
6271 int thisblock = 0;
6272 int error = FALSE;
6273 char_u *name;
6274
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006275 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006276
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006277 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006278 if (argvars[1].v_type != VAR_UNKNOWN)
6279 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006280 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006281 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006282 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283 }
6284 if (!error && name != NULL)
6285 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6286 locally, thisblock, SEARCH_KEEP) == FAIL;
6287}
6288
6289/*
6290 * Used by searchpair() and searchpairpos()
6291 */
6292 static int
6293searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6294{
6295 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006296 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 int save_p_ws = p_ws;
6298 int dir;
6299 int flags = 0;
6300 char_u nbuf1[NUMBUFLEN];
6301 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006302 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006303 long lnum_stop = 0;
6304 long time_limit = 0;
6305
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006306 // Get the three pattern arguments: start, middle, end. Will result in an
6307 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006308 spat = tv_get_string_chk(&argvars[0]);
6309 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6310 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006311 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006312 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006314 // Handle the optional fourth argument: flags
6315 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006316 if (dir == 0)
6317 goto theend;
6318
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006319 // Don't accept SP_END or SP_SUBPAT.
6320 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321 if ((flags & (SP_END | SP_SUBPAT)) != 0
6322 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6323 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006324 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325 goto theend;
6326 }
6327
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006328 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006329 if (flags & SP_REPEAT)
6330 p_ws = FALSE;
6331
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006332 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333 if (argvars[3].v_type == VAR_UNKNOWN
6334 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006335 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006336 else
6337 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006338 skip = &argvars[4];
6339 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6340 && skip->v_type != VAR_STRING)
6341 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006342 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006343 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006344 goto theend;
6345 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006346 if (argvars[5].v_type != VAR_UNKNOWN)
6347 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006348 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006349 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006350 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006351 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006352 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006353 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006354#ifdef FEAT_RELTIME
6355 if (argvars[6].v_type != VAR_UNKNOWN)
6356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006357 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006358 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006359 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006360 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006362 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363 }
6364#endif
6365 }
6366 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006367
6368 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6369 match_pos, lnum_stop, time_limit);
6370
6371theend:
6372 p_ws = save_p_ws;
6373
6374 return retval;
6375}
6376
6377/*
6378 * "searchpair()" function
6379 */
6380 static void
6381f_searchpair(typval_T *argvars, typval_T *rettv)
6382{
6383 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6384}
6385
6386/*
6387 * "searchpairpos()" function
6388 */
6389 static void
6390f_searchpairpos(typval_T *argvars, typval_T *rettv)
6391{
6392 pos_T match_pos;
6393 int lnum = 0;
6394 int col = 0;
6395
6396 if (rettv_list_alloc(rettv) == FAIL)
6397 return;
6398
6399 if (searchpair_cmn(argvars, &match_pos) > 0)
6400 {
6401 lnum = match_pos.lnum;
6402 col = match_pos.col;
6403 }
6404
6405 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6406 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6407}
6408
6409/*
6410 * Search for a start/middle/end thing.
6411 * Used by searchpair(), see its documentation for the details.
6412 * Returns 0 or -1 for no match,
6413 */
6414 long
6415do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006416 char_u *spat, // start pattern
6417 char_u *mpat, // middle pattern
6418 char_u *epat, // end pattern
6419 int dir, // BACKWARD or FORWARD
6420 typval_T *skip, // skip expression
6421 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006423 linenr_T lnum_stop, // stop at this line if not zero
6424 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006425{
6426 char_u *save_cpo;
6427 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6428 long retval = 0;
6429 pos_T pos;
6430 pos_T firstpos;
6431 pos_T foundpos;
6432 pos_T save_cursor;
6433 pos_T save_pos;
6434 int n;
6435 int r;
6436 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006437 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006438 int err;
6439 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006440#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006441 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006442#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006444 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445 save_cpo = p_cpo;
6446 p_cpo = empty_option;
6447
6448#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006449 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006450 profile_setlimit(time_limit, &tm);
6451#endif
6452
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006453 // Make two search patterns: start/end (pat2, for in nested pairs) and
6454 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006455 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6456 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006457 if (pat2 == NULL || pat3 == NULL)
6458 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006459 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006460 if (*mpat == NUL)
6461 STRCPY(pat3, pat2);
6462 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006463 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006464 spat, epat, mpat);
6465 if (flags & SP_START)
6466 options |= SEARCH_START;
6467
Bram Moolenaar48570482017-10-30 21:48:41 +01006468 if (skip != NULL)
6469 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006470 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006471 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6472 use_skip = skip->vval.v_string != NULL
6473 && *skip->vval.v_string != NUL;
6474 }
6475
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 save_cursor = curwin->w_cursor;
6477 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006478 CLEAR_POS(&firstpos);
6479 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006480 pat = pat3;
6481 for (;;)
6482 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006483 searchit_arg_T sia;
6484
6485 vim_memset(&sia, 0, sizeof(sia));
6486 sia.sa_stop_lnum = lnum_stop;
6487#ifdef FEAT_RELTIME
6488 sia.sa_tm = &tm;
6489#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006490 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006491 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006492 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006493 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006494 break;
6495
6496 if (firstpos.lnum == 0)
6497 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006498 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006500 // Found the same position again. Can happen with a pattern that
6501 // has "\zs" at the end and searching backwards. Advance one
6502 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503 if (dir == BACKWARD)
6504 decl(&pos);
6505 else
6506 incl(&pos);
6507 }
6508 foundpos = pos;
6509
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006510 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006511 options &= ~SEARCH_START;
6512
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006513 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006514 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006515 {
6516 save_pos = curwin->w_cursor;
6517 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006518 err = FALSE;
6519 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006520 curwin->w_cursor = save_pos;
6521 if (err)
6522 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006523 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006524 curwin->w_cursor = save_cursor;
6525 retval = -1;
6526 break;
6527 }
6528 if (r)
6529 continue;
6530 }
6531
6532 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6533 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006534 // Found end when searching backwards or start when searching
6535 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006536 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006537 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 }
6539 else
6540 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006541 // Found end when searching forward or start when searching
6542 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006543 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006544 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006545 }
6546
6547 if (nest == 0)
6548 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006549 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 if (flags & SP_RETCOUNT)
6551 ++retval;
6552 else
6553 retval = pos.lnum;
6554 if (flags & SP_SETPCMARK)
6555 setpcmark();
6556 curwin->w_cursor = pos;
6557 if (!(flags & SP_REPEAT))
6558 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006559 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 }
6561 }
6562
6563 if (match_pos != NULL)
6564 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006565 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006566 match_pos->lnum = curwin->w_cursor.lnum;
6567 match_pos->col = curwin->w_cursor.col + 1;
6568 }
6569
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006570 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006571 if ((flags & SP_NOMOVE) || retval == 0)
6572 curwin->w_cursor = save_cursor;
6573
6574theend:
6575 vim_free(pat2);
6576 vim_free(pat3);
6577 if (p_cpo == empty_option)
6578 p_cpo = save_cpo;
6579 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006580 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006581 free_string_option(save_cpo);
6582
6583 return retval;
6584}
6585
6586/*
6587 * "searchpos()" function
6588 */
6589 static void
6590f_searchpos(typval_T *argvars, typval_T *rettv)
6591{
6592 pos_T match_pos;
6593 int lnum = 0;
6594 int col = 0;
6595 int n;
6596 int flags = 0;
6597
6598 if (rettv_list_alloc(rettv) == FAIL)
6599 return;
6600
6601 n = search_cmn(argvars, &match_pos, &flags);
6602 if (n > 0)
6603 {
6604 lnum = match_pos.lnum;
6605 col = match_pos.col;
6606 }
6607
6608 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6609 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6610 if (flags & SP_SUBPAT)
6611 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6612}
6613
6614 static void
6615f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6616{
6617#ifdef FEAT_CLIENTSERVER
6618 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006619 char_u *server = tv_get_string_chk(&argvars[0]);
6620 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006621
6622 rettv->vval.v_number = -1;
6623 if (server == NULL || reply == NULL)
6624 return;
6625 if (check_restricted() || check_secure())
6626 return;
6627# ifdef FEAT_X11
6628 if (check_connection() == FAIL)
6629 return;
6630# endif
6631
6632 if (serverSendReply(server, reply) < 0)
6633 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006634 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006635 return;
6636 }
6637 rettv->vval.v_number = 0;
6638#else
6639 rettv->vval.v_number = -1;
6640#endif
6641}
6642
6643 static void
6644f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6645{
6646 char_u *r = NULL;
6647
6648#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006649# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650 r = serverGetVimNames();
6651# else
6652 make_connection();
6653 if (X_DISPLAY != NULL)
6654 r = serverGetVimNames(X_DISPLAY);
6655# endif
6656#endif
6657 rettv->v_type = VAR_STRING;
6658 rettv->vval.v_string = r;
6659}
6660
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006661 static void
6662f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6663{
6664 dict_T *d;
6665 dictitem_T *di;
6666 char_u *csearch;
6667
6668 if (argvars[0].v_type != VAR_DICT)
6669 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006670 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006671 return;
6672 }
6673
6674 if ((d = argvars[0].vval.v_dict) != NULL)
6675 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006676 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006677 if (csearch != NULL)
6678 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006679 if (enc_utf8)
6680 {
6681 int pcc[MAX_MCO];
6682 int c = utfc_ptr2char(csearch, pcc);
6683
6684 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6685 }
6686 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006687 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006688 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 }
6690
6691 di = dict_find(d, (char_u *)"forward", -1);
6692 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006693 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006694 ? FORWARD : BACKWARD);
6695
6696 di = dict_find(d, (char_u *)"until", -1);
6697 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006698 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699 }
6700}
6701
6702/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006703 * "setenv()" function
6704 */
6705 static void
6706f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6707{
6708 char_u namebuf[NUMBUFLEN];
6709 char_u valbuf[NUMBUFLEN];
6710 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6711
6712 if (argvars[1].v_type == VAR_SPECIAL
6713 && argvars[1].vval.v_number == VVAL_NULL)
6714 vim_unsetenv(name);
6715 else
6716 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6717}
6718
6719/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006720 * "setfperm({fname}, {mode})" function
6721 */
6722 static void
6723f_setfperm(typval_T *argvars, typval_T *rettv)
6724{
6725 char_u *fname;
6726 char_u modebuf[NUMBUFLEN];
6727 char_u *mode_str;
6728 int i;
6729 int mask;
6730 int mode = 0;
6731
6732 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006733 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006734 if (fname == NULL)
6735 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006736 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 if (mode_str == NULL)
6738 return;
6739 if (STRLEN(mode_str) != 9)
6740 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006741 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742 return;
6743 }
6744
6745 mask = 1;
6746 for (i = 8; i >= 0; --i)
6747 {
6748 if (mode_str[i] != '-')
6749 mode |= mask;
6750 mask = mask << 1;
6751 }
6752 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6753}
6754
6755/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006756 * "setpos()" function
6757 */
6758 static void
6759f_setpos(typval_T *argvars, typval_T *rettv)
6760{
6761 pos_T pos;
6762 int fnum;
6763 char_u *name;
6764 colnr_T curswant = -1;
6765
6766 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006767 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 if (name != NULL)
6769 {
6770 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6771 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006772 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 pos.col = 0;
6774 if (name[0] == '.' && name[1] == NUL)
6775 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006776 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006777 curwin->w_cursor = pos;
6778 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006780 curwin->w_curswant = curswant - 1;
6781 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006783 check_cursor();
6784 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006785 }
6786 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6787 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006788 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006789 if (setmark_pos(name[1], &pos, fnum) == OK)
6790 rettv->vval.v_number = 0;
6791 }
6792 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006793 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 }
6795 }
6796}
6797
6798/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006799 * "setreg()" function
6800 */
6801 static void
6802f_setreg(typval_T *argvars, typval_T *rettv)
6803{
6804 int regname;
6805 char_u *strregname;
6806 char_u *stropt;
6807 char_u *strval;
6808 int append;
6809 char_u yank_type;
6810 long block_len;
6811
6812 block_len = -1;
6813 yank_type = MAUTO;
6814 append = FALSE;
6815
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006816 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006817 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006818
6819 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006820 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006821 regname = *strregname;
6822 if (regname == 0 || regname == '@')
6823 regname = '"';
6824
6825 if (argvars[2].v_type != VAR_UNKNOWN)
6826 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006827 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006828 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006829 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830 for (; *stropt != NUL; ++stropt)
6831 switch (*stropt)
6832 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006833 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834 append = TRUE;
6835 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006836 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006837 yank_type = MCHAR;
6838 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006839 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840 yank_type = MLINE;
6841 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006842 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006843 yank_type = MBLOCK;
6844 if (VIM_ISDIGIT(stropt[1]))
6845 {
6846 ++stropt;
6847 block_len = getdigits(&stropt) - 1;
6848 --stropt;
6849 }
6850 break;
6851 }
6852 }
6853
6854 if (argvars[1].v_type == VAR_LIST)
6855 {
6856 char_u **lstval;
6857 char_u **allocval;
6858 char_u buf[NUMBUFLEN];
6859 char_u **curval;
6860 char_u **curallocval;
6861 list_T *ll = argvars[1].vval.v_list;
6862 listitem_T *li;
6863 int len;
6864
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006865 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 len = ll == NULL ? 0 : ll->lv_len;
6867
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006868 // First half: use for pointers to result lines; second half: use for
6869 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006870 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006871 if (lstval == NULL)
6872 return;
6873 curval = lstval;
6874 allocval = lstval + len + 2;
6875 curallocval = allocval;
6876
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006877 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006879 range_list_materialize(ll);
6880 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006881 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006882 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 if (strval == NULL)
6884 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006885 if (strval == buf)
6886 {
6887 // Need to make a copy, next tv_get_string_buf_chk() will
6888 // overwrite the string.
6889 strval = vim_strsave(buf);
6890 if (strval == NULL)
6891 goto free_lstval;
6892 *curallocval++ = strval;
6893 }
6894 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006895 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006896 }
6897 *curval++ = NULL;
6898
6899 write_reg_contents_lst(regname, lstval, -1,
6900 append, yank_type, block_len);
6901free_lstval:
6902 while (curallocval > allocval)
6903 vim_free(*--curallocval);
6904 vim_free(lstval);
6905 }
6906 else
6907 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006908 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006909 if (strval == NULL)
6910 return;
6911 write_reg_contents_ex(regname, strval, -1,
6912 append, yank_type, block_len);
6913 }
6914 rettv->vval.v_number = 0;
6915}
6916
6917/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006918 * "settagstack()" function
6919 */
6920 static void
6921f_settagstack(typval_T *argvars, typval_T *rettv)
6922{
6923 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6924 win_T *wp;
6925 dict_T *d;
6926 int action = 'r';
6927
6928 rettv->vval.v_number = -1;
6929
6930 // first argument: window number or id
6931 wp = find_win_by_nr_or_id(&argvars[0]);
6932 if (wp == NULL)
6933 return;
6934
6935 // second argument: dict with items to set in the tag stack
6936 if (argvars[1].v_type != VAR_DICT)
6937 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006938 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006939 return;
6940 }
6941 d = argvars[1].vval.v_dict;
6942 if (d == NULL)
6943 return;
6944
6945 // third argument: action - 'a' for append and 'r' for replace.
6946 // default is to replace the stack.
6947 if (argvars[2].v_type == VAR_UNKNOWN)
6948 action = 'r';
6949 else if (argvars[2].v_type == VAR_STRING)
6950 {
6951 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006952 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006953 if (actstr == NULL)
6954 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006955 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6956 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006957 action = *actstr;
6958 else
6959 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006960 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006961 return;
6962 }
6963 }
6964 else
6965 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006966 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006967 return;
6968 }
6969
6970 if (set_tagstack(wp, d, action) == OK)
6971 rettv->vval.v_number = 0;
6972}
6973
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974#ifdef FEAT_CRYPT
6975/*
6976 * "sha256({string})" function
6977 */
6978 static void
6979f_sha256(typval_T *argvars, typval_T *rettv)
6980{
6981 char_u *p;
6982
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006983 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006984 rettv->vval.v_string = vim_strsave(
6985 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6986 rettv->v_type = VAR_STRING;
6987}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006988#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006989
6990/*
6991 * "shellescape({string})" function
6992 */
6993 static void
6994f_shellescape(typval_T *argvars, typval_T *rettv)
6995{
Bram Moolenaar20615522017-06-05 18:46:26 +02006996 int do_special = non_zero_arg(&argvars[1]);
6997
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006998 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006999 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007000 rettv->v_type = VAR_STRING;
7001}
7002
7003/*
7004 * shiftwidth() function
7005 */
7006 static void
7007f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7008{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007009 rettv->vval.v_number = 0;
7010
7011 if (argvars[0].v_type != VAR_UNKNOWN)
7012 {
7013 long col;
7014
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007015 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007016 if (col < 0)
7017 return; // type error; errmsg already given
7018#ifdef FEAT_VARTABS
7019 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7020 return;
7021#endif
7022 }
7023
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024 rettv->vval.v_number = get_sw_value(curbuf);
7025}
7026
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007027#ifdef FEAT_FLOAT
7028/*
7029 * "sin()" function
7030 */
7031 static void
7032f_sin(typval_T *argvars, typval_T *rettv)
7033{
7034 float_T f = 0.0;
7035
7036 rettv->v_type = VAR_FLOAT;
7037 if (get_float_arg(argvars, &f) == OK)
7038 rettv->vval.v_float = sin(f);
7039 else
7040 rettv->vval.v_float = 0.0;
7041}
7042
7043/*
7044 * "sinh()" function
7045 */
7046 static void
7047f_sinh(typval_T *argvars, typval_T *rettv)
7048{
7049 float_T f = 0.0;
7050
7051 rettv->v_type = VAR_FLOAT;
7052 if (get_float_arg(argvars, &f) == OK)
7053 rettv->vval.v_float = sinh(f);
7054 else
7055 rettv->vval.v_float = 0.0;
7056}
7057#endif
7058
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007059/*
7060 * "soundfold({word})" function
7061 */
7062 static void
7063f_soundfold(typval_T *argvars, typval_T *rettv)
7064{
7065 char_u *s;
7066
7067 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007068 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069#ifdef FEAT_SPELL
7070 rettv->vval.v_string = eval_soundfold(s);
7071#else
7072 rettv->vval.v_string = vim_strsave(s);
7073#endif
7074}
7075
7076/*
7077 * "spellbadword()" function
7078 */
7079 static void
7080f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7081{
7082 char_u *word = (char_u *)"";
7083 hlf_T attr = HLF_COUNT;
7084 int len = 0;
7085
7086 if (rettv_list_alloc(rettv) == FAIL)
7087 return;
7088
7089#ifdef FEAT_SPELL
7090 if (argvars[0].v_type == VAR_UNKNOWN)
7091 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007092 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007093 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7094 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007095 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007096 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007097 curwin->w_set_curswant = TRUE;
7098 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007099 }
7100 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7101 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007102 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007103 int capcol = -1;
7104
7105 if (str != NULL)
7106 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007107 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108 while (*str != NUL)
7109 {
7110 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7111 if (attr != HLF_COUNT)
7112 {
7113 word = str;
7114 break;
7115 }
7116 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007117 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007118 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119 }
7120 }
7121 }
7122#endif
7123
7124 list_append_string(rettv->vval.v_list, word, len);
7125 list_append_string(rettv->vval.v_list, (char_u *)(
7126 attr == HLF_SPB ? "bad" :
7127 attr == HLF_SPR ? "rare" :
7128 attr == HLF_SPL ? "local" :
7129 attr == HLF_SPC ? "caps" :
7130 ""), -1);
7131}
7132
7133/*
7134 * "spellsuggest()" function
7135 */
7136 static void
7137f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7138{
7139#ifdef FEAT_SPELL
7140 char_u *str;
7141 int typeerr = FALSE;
7142 int maxcount;
7143 garray_T ga;
7144 int i;
7145 listitem_T *li;
7146 int need_capital = FALSE;
7147#endif
7148
7149 if (rettv_list_alloc(rettv) == FAIL)
7150 return;
7151
7152#ifdef FEAT_SPELL
7153 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7154 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007155 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007156 if (argvars[1].v_type != VAR_UNKNOWN)
7157 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007158 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007159 if (maxcount <= 0)
7160 return;
7161 if (argvars[2].v_type != VAR_UNKNOWN)
7162 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007163 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 if (typeerr)
7165 return;
7166 }
7167 }
7168 else
7169 maxcount = 25;
7170
7171 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7172
7173 for (i = 0; i < ga.ga_len; ++i)
7174 {
7175 str = ((char_u **)ga.ga_data)[i];
7176
7177 li = listitem_alloc();
7178 if (li == NULL)
7179 vim_free(str);
7180 else
7181 {
7182 li->li_tv.v_type = VAR_STRING;
7183 li->li_tv.v_lock = 0;
7184 li->li_tv.vval.v_string = str;
7185 list_append(rettv->vval.v_list, li);
7186 }
7187 }
7188 ga_clear(&ga);
7189 }
7190#endif
7191}
7192
7193 static void
7194f_split(typval_T *argvars, typval_T *rettv)
7195{
7196 char_u *str;
7197 char_u *end;
7198 char_u *pat = NULL;
7199 regmatch_T regmatch;
7200 char_u patbuf[NUMBUFLEN];
7201 char_u *save_cpo;
7202 int match;
7203 colnr_T col = 0;
7204 int keepempty = FALSE;
7205 int typeerr = FALSE;
7206
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007207 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208 save_cpo = p_cpo;
7209 p_cpo = (char_u *)"";
7210
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007211 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007212 if (argvars[1].v_type != VAR_UNKNOWN)
7213 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007214 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007215 if (pat == NULL)
7216 typeerr = TRUE;
7217 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007218 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007219 }
7220 if (pat == NULL || *pat == NUL)
7221 pat = (char_u *)"[\\x01- ]\\+";
7222
7223 if (rettv_list_alloc(rettv) == FAIL)
7224 return;
7225 if (typeerr)
7226 return;
7227
7228 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7229 if (regmatch.regprog != NULL)
7230 {
7231 regmatch.rm_ic = FALSE;
7232 while (*str != NUL || keepempty)
7233 {
7234 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007235 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 else
7237 match = vim_regexec_nl(&regmatch, str, col);
7238 if (match)
7239 end = regmatch.startp[0];
7240 else
7241 end = str + STRLEN(str);
7242 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7243 && *str != NUL && match && end < regmatch.endp[0]))
7244 {
7245 if (list_append_string(rettv->vval.v_list, str,
7246 (int)(end - str)) == FAIL)
7247 break;
7248 }
7249 if (!match)
7250 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007251 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007252 if (regmatch.endp[0] > str)
7253 col = 0;
7254 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007255 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007256 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007257 str = regmatch.endp[0];
7258 }
7259
7260 vim_regfree(regmatch.regprog);
7261 }
7262
7263 p_cpo = save_cpo;
7264}
7265
7266#ifdef FEAT_FLOAT
7267/*
7268 * "sqrt()" function
7269 */
7270 static void
7271f_sqrt(typval_T *argvars, typval_T *rettv)
7272{
7273 float_T f = 0.0;
7274
7275 rettv->v_type = VAR_FLOAT;
7276 if (get_float_arg(argvars, &f) == OK)
7277 rettv->vval.v_float = sqrt(f);
7278 else
7279 rettv->vval.v_float = 0.0;
7280}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007281#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007282
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007283#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007284/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 * "str2float()" function
7286 */
7287 static void
7288f_str2float(typval_T *argvars, typval_T *rettv)
7289{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007290 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007291 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007292
Bram Moolenaar08243d22017-01-10 16:12:29 +01007293 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294 p = skipwhite(p + 1);
7295 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007296 if (isneg)
7297 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007298 rettv->v_type = VAR_FLOAT;
7299}
7300#endif
7301
7302/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007303 * "str2list()" function
7304 */
7305 static void
7306f_str2list(typval_T *argvars, typval_T *rettv)
7307{
7308 char_u *p;
7309 int utf8 = FALSE;
7310
7311 if (rettv_list_alloc(rettv) == FAIL)
7312 return;
7313
7314 if (argvars[1].v_type != VAR_UNKNOWN)
7315 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7316
7317 p = tv_get_string(&argvars[0]);
7318
7319 if (has_mbyte || utf8)
7320 {
7321 int (*ptr2len)(char_u *);
7322 int (*ptr2char)(char_u *);
7323
7324 if (utf8 || enc_utf8)
7325 {
7326 ptr2len = utf_ptr2len;
7327 ptr2char = utf_ptr2char;
7328 }
7329 else
7330 {
7331 ptr2len = mb_ptr2len;
7332 ptr2char = mb_ptr2char;
7333 }
7334
7335 for ( ; *p != NUL; p += (*ptr2len)(p))
7336 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7337 }
7338 else
7339 for ( ; *p != NUL; ++p)
7340 list_append_number(rettv->vval.v_list, *p);
7341}
7342
7343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 * "str2nr()" function
7345 */
7346 static void
7347f_str2nr(typval_T *argvars, typval_T *rettv)
7348{
7349 int base = 10;
7350 char_u *p;
7351 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007352 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007353 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007354
7355 if (argvars[1].v_type != VAR_UNKNOWN)
7356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007357 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358 if (base != 2 && base != 8 && base != 10 && base != 16)
7359 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007360 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007361 return;
7362 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007363 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7364 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007365 }
7366
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007367 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007368 isneg = (*p == '-');
7369 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007370 p = skipwhite(p + 1);
7371 switch (base)
7372 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007373 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7374 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7375 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007376 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007377 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7378 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007379 if (isneg)
7380 rettv->vval.v_number = -n;
7381 else
7382 rettv->vval.v_number = n;
7383
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384}
7385
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386/*
7387 * "strgetchar()" function
7388 */
7389 static void
7390f_strgetchar(typval_T *argvars, typval_T *rettv)
7391{
7392 char_u *str;
7393 int len;
7394 int error = FALSE;
7395 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007396 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007397
7398 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007399 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007400 if (str == NULL)
7401 return;
7402 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007403 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007404 if (error)
7405 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007406
Bram Moolenaar13505972019-01-24 15:04:48 +01007407 while (charidx >= 0 && byteidx < len)
7408 {
7409 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007411 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7412 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007413 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007414 --charidx;
7415 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007416 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007417}
7418
7419/*
7420 * "stridx()" function
7421 */
7422 static void
7423f_stridx(typval_T *argvars, typval_T *rettv)
7424{
7425 char_u buf[NUMBUFLEN];
7426 char_u *needle;
7427 char_u *haystack;
7428 char_u *save_haystack;
7429 char_u *pos;
7430 int start_idx;
7431
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007432 needle = tv_get_string_chk(&argvars[1]);
7433 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 rettv->vval.v_number = -1;
7435 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007436 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007437
7438 if (argvars[2].v_type != VAR_UNKNOWN)
7439 {
7440 int error = FALSE;
7441
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007442 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007443 if (error || start_idx >= (int)STRLEN(haystack))
7444 return;
7445 if (start_idx >= 0)
7446 haystack += start_idx;
7447 }
7448
7449 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7450 if (pos != NULL)
7451 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7452}
7453
7454/*
7455 * "string()" function
7456 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007457 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458f_string(typval_T *argvars, typval_T *rettv)
7459{
7460 char_u *tofree;
7461 char_u numbuf[NUMBUFLEN];
7462
7463 rettv->v_type = VAR_STRING;
7464 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7465 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007466 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007467 if (rettv->vval.v_string != NULL && tofree == NULL)
7468 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7469}
7470
7471/*
7472 * "strlen()" function
7473 */
7474 static void
7475f_strlen(typval_T *argvars, typval_T *rettv)
7476{
7477 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007478 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007479}
7480
7481/*
7482 * "strchars()" function
7483 */
7484 static void
7485f_strchars(typval_T *argvars, typval_T *rettv)
7486{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007487 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007489 varnumber_T len = 0;
7490 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491
7492 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007493 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007494 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007495 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007496 else
7497 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7499 while (*s != NUL)
7500 {
7501 func_mb_ptr2char_adv(&s);
7502 ++len;
7503 }
7504 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007505 }
7506}
7507
7508/*
7509 * "strdisplaywidth()" function
7510 */
7511 static void
7512f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7513{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007514 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 int col = 0;
7516
7517 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007518 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519
7520 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7521}
7522
7523/*
7524 * "strwidth()" function
7525 */
7526 static void
7527f_strwidth(typval_T *argvars, typval_T *rettv)
7528{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007529 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007530
Bram Moolenaar13505972019-01-24 15:04:48 +01007531 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532}
7533
7534/*
7535 * "strcharpart()" function
7536 */
7537 static void
7538f_strcharpart(typval_T *argvars, typval_T *rettv)
7539{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540 char_u *p;
7541 int nchar;
7542 int nbyte = 0;
7543 int charlen;
7544 int len = 0;
7545 int slen;
7546 int error = FALSE;
7547
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007548 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007549 slen = (int)STRLEN(p);
7550
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007551 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552 if (!error)
7553 {
7554 if (nchar > 0)
7555 while (nchar > 0 && nbyte < slen)
7556 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007557 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558 --nchar;
7559 }
7560 else
7561 nbyte = nchar;
7562 if (argvars[2].v_type != VAR_UNKNOWN)
7563 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007564 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007565 while (charlen > 0 && nbyte + len < slen)
7566 {
7567 int off = nbyte + len;
7568
7569 if (off < 0)
7570 len += 1;
7571 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007572 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007573 --charlen;
7574 }
7575 }
7576 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007577 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007578 }
7579
7580 /*
7581 * Only return the overlap between the specified part and the actual
7582 * string.
7583 */
7584 if (nbyte < 0)
7585 {
7586 len += nbyte;
7587 nbyte = 0;
7588 }
7589 else if (nbyte > slen)
7590 nbyte = slen;
7591 if (len < 0)
7592 len = 0;
7593 else if (nbyte + len > slen)
7594 len = slen - nbyte;
7595
7596 rettv->v_type = VAR_STRING;
7597 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007598}
7599
7600/*
7601 * "strpart()" function
7602 */
7603 static void
7604f_strpart(typval_T *argvars, typval_T *rettv)
7605{
7606 char_u *p;
7607 int n;
7608 int len;
7609 int slen;
7610 int error = FALSE;
7611
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007612 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613 slen = (int)STRLEN(p);
7614
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007615 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007616 if (error)
7617 len = 0;
7618 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007619 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007620 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007621 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007622
7623 /*
7624 * Only return the overlap between the specified part and the actual
7625 * string.
7626 */
7627 if (n < 0)
7628 {
7629 len += n;
7630 n = 0;
7631 }
7632 else if (n > slen)
7633 n = slen;
7634 if (len < 0)
7635 len = 0;
7636 else if (n + len > slen)
7637 len = slen - n;
7638
7639 rettv->v_type = VAR_STRING;
7640 rettv->vval.v_string = vim_strnsave(p + n, len);
7641}
7642
7643/*
7644 * "strridx()" function
7645 */
7646 static void
7647f_strridx(typval_T *argvars, typval_T *rettv)
7648{
7649 char_u buf[NUMBUFLEN];
7650 char_u *needle;
7651 char_u *haystack;
7652 char_u *rest;
7653 char_u *lastmatch = NULL;
7654 int haystack_len, end_idx;
7655
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007656 needle = tv_get_string_chk(&argvars[1]);
7657 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007658
7659 rettv->vval.v_number = -1;
7660 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007661 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007662
7663 haystack_len = (int)STRLEN(haystack);
7664 if (argvars[2].v_type != VAR_UNKNOWN)
7665 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007666 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007667 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007668 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007669 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 }
7671 else
7672 end_idx = haystack_len;
7673
7674 if (*needle == NUL)
7675 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007676 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007677 lastmatch = haystack + end_idx;
7678 }
7679 else
7680 {
7681 for (rest = haystack; *rest != '\0'; ++rest)
7682 {
7683 rest = (char_u *)strstr((char *)rest, (char *)needle);
7684 if (rest == NULL || rest > haystack + end_idx)
7685 break;
7686 lastmatch = rest;
7687 }
7688 }
7689
7690 if (lastmatch == NULL)
7691 rettv->vval.v_number = -1;
7692 else
7693 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7694}
7695
7696/*
7697 * "strtrans()" function
7698 */
7699 static void
7700f_strtrans(typval_T *argvars, typval_T *rettv)
7701{
7702 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007703 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007704}
7705
7706/*
7707 * "submatch()" function
7708 */
7709 static void
7710f_submatch(typval_T *argvars, typval_T *rettv)
7711{
7712 int error = FALSE;
7713 int no;
7714 int retList = 0;
7715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007716 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717 if (error)
7718 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007719 if (no < 0 || no >= NSUBEXP)
7720 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007721 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007722 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007723 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007724 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007725 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726 if (error)
7727 return;
7728
7729 if (retList == 0)
7730 {
7731 rettv->v_type = VAR_STRING;
7732 rettv->vval.v_string = reg_submatch(no);
7733 }
7734 else
7735 {
7736 rettv->v_type = VAR_LIST;
7737 rettv->vval.v_list = reg_submatch_list(no);
7738 }
7739}
7740
7741/*
7742 * "substitute()" function
7743 */
7744 static void
7745f_substitute(typval_T *argvars, typval_T *rettv)
7746{
7747 char_u patbuf[NUMBUFLEN];
7748 char_u subbuf[NUMBUFLEN];
7749 char_u flagsbuf[NUMBUFLEN];
7750
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007751 char_u *str = tv_get_string_chk(&argvars[0]);
7752 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007753 char_u *sub = NULL;
7754 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007755 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007757 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7758 expr = &argvars[2];
7759 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007760 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007761
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007762 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007763 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7764 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765 rettv->vval.v_string = NULL;
7766 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007767 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007768}
7769
7770/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007771 * "swapinfo(swap_filename)" function
7772 */
7773 static void
7774f_swapinfo(typval_T *argvars, typval_T *rettv)
7775{
7776 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007777 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007778}
7779
7780/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007781 * "swapname(expr)" function
7782 */
7783 static void
7784f_swapname(typval_T *argvars, typval_T *rettv)
7785{
7786 buf_T *buf;
7787
7788 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007789 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007790 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7791 || buf->b_ml.ml_mfp->mf_fname == NULL)
7792 rettv->vval.v_string = NULL;
7793 else
7794 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7795}
7796
7797/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798 * "synID(lnum, col, trans)" function
7799 */
7800 static void
7801f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7802{
7803 int id = 0;
7804#ifdef FEAT_SYN_HL
7805 linenr_T lnum;
7806 colnr_T col;
7807 int trans;
7808 int transerr = FALSE;
7809
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007810 lnum = tv_get_lnum(argvars); // -1 on type error
7811 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007812 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007813
7814 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7815 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7816 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7817#endif
7818
7819 rettv->vval.v_number = id;
7820}
7821
7822/*
7823 * "synIDattr(id, what [, mode])" function
7824 */
7825 static void
7826f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7827{
7828 char_u *p = NULL;
7829#ifdef FEAT_SYN_HL
7830 int id;
7831 char_u *what;
7832 char_u *mode;
7833 char_u modebuf[NUMBUFLEN];
7834 int modec;
7835
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007836 id = (int)tv_get_number(&argvars[0]);
7837 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007838 if (argvars[2].v_type != VAR_UNKNOWN)
7839 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007840 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841 modec = TOLOWER_ASC(mode[0]);
7842 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007843 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007844 }
7845 else
7846 {
7847#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7848 if (USE_24BIT)
7849 modec = 'g';
7850 else
7851#endif
7852 if (t_colors > 1)
7853 modec = 'c';
7854 else
7855 modec = 't';
7856 }
7857
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858 switch (TOLOWER_ASC(what[0]))
7859 {
7860 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007861 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007862 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007863 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007864 p = highlight_has_attr(id, HL_BOLD, modec);
7865 break;
7866
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007867 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 p = highlight_color(id, what, modec);
7869 break;
7870
7871 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007872 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007873 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007874 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007875 p = highlight_has_attr(id, HL_ITALIC, modec);
7876 break;
7877
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007878 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007879 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 break;
7881
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007882 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007883 p = highlight_has_attr(id, HL_INVERSE, modec);
7884 break;
7885
7886 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007887 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007888 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007889 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007890 else if (TOLOWER_ASC(what[1]) == 't' &&
7891 TOLOWER_ASC(what[2]) == 'r')
7892 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007893 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007894 p = highlight_has_attr(id, HL_STANDOUT, modec);
7895 break;
7896
7897 case 'u':
7898 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007899 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7901 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007902 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007903 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7904 break;
7905 }
7906
7907 if (p != NULL)
7908 p = vim_strsave(p);
7909#endif
7910 rettv->v_type = VAR_STRING;
7911 rettv->vval.v_string = p;
7912}
7913
7914/*
7915 * "synIDtrans(id)" function
7916 */
7917 static void
7918f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7919{
7920 int id;
7921
7922#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007923 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924
7925 if (id > 0)
7926 id = syn_get_final_id(id);
7927 else
7928#endif
7929 id = 0;
7930
7931 rettv->vval.v_number = id;
7932}
7933
7934/*
7935 * "synconcealed(lnum, col)" function
7936 */
7937 static void
7938f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7939{
7940#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7941 linenr_T lnum;
7942 colnr_T col;
7943 int syntax_flags = 0;
7944 int cchar;
7945 int matchid = 0;
7946 char_u str[NUMBUFLEN];
7947#endif
7948
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007949 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950
7951#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007952 lnum = tv_get_lnum(argvars); // -1 on type error
7953 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954
7955 vim_memset(str, NUL, sizeof(str));
7956
7957 if (rettv_list_alloc(rettv) != FAIL)
7958 {
7959 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7960 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7961 && curwin->w_p_cole > 0)
7962 {
7963 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7964 syntax_flags = get_syntax_info(&matchid);
7965
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007966 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007967 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7968 {
7969 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007970 if (cchar == NUL && curwin->w_p_cole == 1)
7971 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007972 if (cchar != NUL)
7973 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007974 if (has_mbyte)
7975 (*mb_char2bytes)(cchar, str);
7976 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007977 str[0] = cchar;
7978 }
7979 }
7980 }
7981
7982 list_append_number(rettv->vval.v_list,
7983 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007984 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007985 list_append_string(rettv->vval.v_list, str, -1);
7986 list_append_number(rettv->vval.v_list, matchid);
7987 }
7988#endif
7989}
7990
7991/*
7992 * "synstack(lnum, col)" function
7993 */
7994 static void
7995f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7996{
7997#ifdef FEAT_SYN_HL
7998 linenr_T lnum;
7999 colnr_T col;
8000 int i;
8001 int id;
8002#endif
8003
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008004 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008005
8006#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008007 lnum = tv_get_lnum(argvars); // -1 on type error
8008 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009
8010 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8011 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8012 && rettv_list_alloc(rettv) != FAIL)
8013 {
8014 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8015 for (i = 0; ; ++i)
8016 {
8017 id = syn_get_stack_item(i);
8018 if (id < 0)
8019 break;
8020 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8021 break;
8022 }
8023 }
8024#endif
8025}
8026
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008027/*
8028 * "tabpagebuflist()" function
8029 */
8030 static void
8031f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8032{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008033 tabpage_T *tp;
8034 win_T *wp = NULL;
8035
8036 if (argvars[0].v_type == VAR_UNKNOWN)
8037 wp = firstwin;
8038 else
8039 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008040 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008041 if (tp != NULL)
8042 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8043 }
8044 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8045 {
8046 for (; wp != NULL; wp = wp->w_next)
8047 if (list_append_number(rettv->vval.v_list,
8048 wp->w_buffer->b_fnum) == FAIL)
8049 break;
8050 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008051}
8052
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008054 * "tagfiles()" function
8055 */
8056 static void
8057f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8058{
8059 char_u *fname;
8060 tagname_T tn;
8061 int first;
8062
8063 if (rettv_list_alloc(rettv) == FAIL)
8064 return;
8065 fname = alloc(MAXPATHL);
8066 if (fname == NULL)
8067 return;
8068
8069 for (first = TRUE; ; first = FALSE)
8070 if (get_tagfname(&tn, first, fname) == FAIL
8071 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8072 break;
8073 tagname_free(&tn);
8074 vim_free(fname);
8075}
8076
8077/*
8078 * "taglist()" function
8079 */
8080 static void
8081f_taglist(typval_T *argvars, typval_T *rettv)
8082{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008083 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084 char_u *tag_pattern;
8085
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008086 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008087
8088 rettv->vval.v_number = FALSE;
8089 if (*tag_pattern == NUL)
8090 return;
8091
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008092 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008093 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008094 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008095 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096}
8097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008098#ifdef FEAT_FLOAT
8099/*
8100 * "tan()" function
8101 */
8102 static void
8103f_tan(typval_T *argvars, typval_T *rettv)
8104{
8105 float_T f = 0.0;
8106
8107 rettv->v_type = VAR_FLOAT;
8108 if (get_float_arg(argvars, &f) == OK)
8109 rettv->vval.v_float = tan(f);
8110 else
8111 rettv->vval.v_float = 0.0;
8112}
8113
8114/*
8115 * "tanh()" function
8116 */
8117 static void
8118f_tanh(typval_T *argvars, typval_T *rettv)
8119{
8120 float_T f = 0.0;
8121
8122 rettv->v_type = VAR_FLOAT;
8123 if (get_float_arg(argvars, &f) == OK)
8124 rettv->vval.v_float = tanh(f);
8125 else
8126 rettv->vval.v_float = 0.0;
8127}
8128#endif
8129
8130/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008131 * "tolower(string)" function
8132 */
8133 static void
8134f_tolower(typval_T *argvars, typval_T *rettv)
8135{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008136 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008137 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008138}
8139
8140/*
8141 * "toupper(string)" function
8142 */
8143 static void
8144f_toupper(typval_T *argvars, typval_T *rettv)
8145{
8146 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008147 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148}
8149
8150/*
8151 * "tr(string, fromstr, tostr)" function
8152 */
8153 static void
8154f_tr(typval_T *argvars, typval_T *rettv)
8155{
8156 char_u *in_str;
8157 char_u *fromstr;
8158 char_u *tostr;
8159 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160 int inlen;
8161 int fromlen;
8162 int tolen;
8163 int idx;
8164 char_u *cpstr;
8165 int cplen;
8166 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167 char_u buf[NUMBUFLEN];
8168 char_u buf2[NUMBUFLEN];
8169 garray_T ga;
8170
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008171 in_str = tv_get_string(&argvars[0]);
8172 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8173 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008175 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 rettv->v_type = VAR_STRING;
8177 rettv->vval.v_string = NULL;
8178 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008179 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008180 ga_init2(&ga, (int)sizeof(char), 80);
8181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008183 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 if (STRLEN(fromstr) != STRLEN(tostr))
8185 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008187 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 ga_clear(&ga);
8189 return;
8190 }
8191
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008192 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008193 while (*in_str != NUL)
8194 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008195 if (has_mbyte)
8196 {
8197 inlen = (*mb_ptr2len)(in_str);
8198 cpstr = in_str;
8199 cplen = inlen;
8200 idx = 0;
8201 for (p = fromstr; *p != NUL; p += fromlen)
8202 {
8203 fromlen = (*mb_ptr2len)(p);
8204 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8205 {
8206 for (p = tostr; *p != NUL; p += tolen)
8207 {
8208 tolen = (*mb_ptr2len)(p);
8209 if (idx-- == 0)
8210 {
8211 cplen = tolen;
8212 cpstr = p;
8213 break;
8214 }
8215 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008216 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008217 goto error;
8218 break;
8219 }
8220 ++idx;
8221 }
8222
8223 if (first && cpstr == in_str)
8224 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008225 // Check that fromstr and tostr have the same number of
8226 // (multi-byte) characters. Done only once when a character
8227 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008228 first = FALSE;
8229 for (p = tostr; *p != NUL; p += tolen)
8230 {
8231 tolen = (*mb_ptr2len)(p);
8232 --idx;
8233 }
8234 if (idx != 0)
8235 goto error;
8236 }
8237
8238 (void)ga_grow(&ga, cplen);
8239 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8240 ga.ga_len += cplen;
8241
8242 in_str += inlen;
8243 }
8244 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008245 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008246 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008247 p = vim_strchr(fromstr, *in_str);
8248 if (p != NULL)
8249 ga_append(&ga, tostr[p - fromstr]);
8250 else
8251 ga_append(&ga, *in_str);
8252 ++in_str;
8253 }
8254 }
8255
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008256 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 (void)ga_grow(&ga, 1);
8258 ga_append(&ga, NUL);
8259
8260 rettv->vval.v_string = ga.ga_data;
8261}
8262
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008263/*
8264 * "trim({expr})" function
8265 */
8266 static void
8267f_trim(typval_T *argvars, typval_T *rettv)
8268{
8269 char_u buf1[NUMBUFLEN];
8270 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008271 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008272 char_u *mask = NULL;
8273 char_u *tail;
8274 char_u *prev;
8275 char_u *p;
8276 int c1;
8277
8278 rettv->v_type = VAR_STRING;
8279 if (head == NULL)
8280 {
8281 rettv->vval.v_string = NULL;
8282 return;
8283 }
8284
8285 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008286 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008287
8288 while (*head != NUL)
8289 {
8290 c1 = PTR2CHAR(head);
8291 if (mask == NULL)
8292 {
8293 if (c1 > ' ' && c1 != 0xa0)
8294 break;
8295 }
8296 else
8297 {
8298 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8299 if (c1 == PTR2CHAR(p))
8300 break;
8301 if (*p == NUL)
8302 break;
8303 }
8304 MB_PTR_ADV(head);
8305 }
8306
8307 for (tail = head + STRLEN(head); tail > head; tail = prev)
8308 {
8309 prev = tail;
8310 MB_PTR_BACK(head, prev);
8311 c1 = PTR2CHAR(prev);
8312 if (mask == NULL)
8313 {
8314 if (c1 > ' ' && c1 != 0xa0)
8315 break;
8316 }
8317 else
8318 {
8319 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8320 if (c1 == PTR2CHAR(p))
8321 break;
8322 if (*p == NUL)
8323 break;
8324 }
8325 }
8326 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8327}
8328
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329#ifdef FEAT_FLOAT
8330/*
8331 * "trunc({float})" function
8332 */
8333 static void
8334f_trunc(typval_T *argvars, typval_T *rettv)
8335{
8336 float_T f = 0.0;
8337
8338 rettv->v_type = VAR_FLOAT;
8339 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008340 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008341 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8342 else
8343 rettv->vval.v_float = 0.0;
8344}
8345#endif
8346
8347/*
8348 * "type(expr)" function
8349 */
8350 static void
8351f_type(typval_T *argvars, typval_T *rettv)
8352{
8353 int n = -1;
8354
8355 switch (argvars[0].v_type)
8356 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008357 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8358 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008359 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008360 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8361 case VAR_LIST: n = VAR_TYPE_LIST; break;
8362 case VAR_DICT: n = VAR_TYPE_DICT; break;
8363 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8364 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8365 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008366 case VAR_JOB: n = VAR_TYPE_JOB; break;
8367 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008368 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008370 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008371 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008372 n = -1;
8373 break;
8374 }
8375 rettv->vval.v_number = n;
8376}
8377
8378/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008379 * "virtcol(string)" function
8380 */
8381 static void
8382f_virtcol(typval_T *argvars, typval_T *rettv)
8383{
8384 colnr_T vcol = 0;
8385 pos_T *fp;
8386 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008387 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388
8389 fp = var2fpos(&argvars[0], FALSE, &fnum);
8390 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8391 && fnum == curbuf->b_fnum)
8392 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008393 // Limit the column to a valid value, getvvcol() doesn't check.
8394 if (fp->col < 0)
8395 fp->col = 0;
8396 else
8397 {
8398 len = (int)STRLEN(ml_get(fp->lnum));
8399 if (fp->col > len)
8400 fp->col = len;
8401 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 getvvcol(curwin, fp, NULL, NULL, &vcol);
8403 ++vcol;
8404 }
8405
8406 rettv->vval.v_number = vcol;
8407}
8408
8409/*
8410 * "visualmode()" function
8411 */
8412 static void
8413f_visualmode(typval_T *argvars, typval_T *rettv)
8414{
8415 char_u str[2];
8416
8417 rettv->v_type = VAR_STRING;
8418 str[0] = curbuf->b_visual_mode_eval;
8419 str[1] = NUL;
8420 rettv->vval.v_string = vim_strsave(str);
8421
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008422 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008423 if (non_zero_arg(&argvars[0]))
8424 curbuf->b_visual_mode_eval = NUL;
8425}
8426
8427/*
8428 * "wildmenumode()" function
8429 */
8430 static void
8431f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8432{
8433#ifdef FEAT_WILDMENU
8434 if (wild_menu_showing)
8435 rettv->vval.v_number = 1;
8436#endif
8437}
8438
8439/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008440 * "windowsversion()" function
8441 */
8442 static void
8443f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8444{
8445 rettv->v_type = VAR_STRING;
8446 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8447}
8448
8449/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008450 * "wordcount()" function
8451 */
8452 static void
8453f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8454{
8455 if (rettv_dict_alloc(rettv) == FAIL)
8456 return;
8457 cursor_pos_info(rettv->vval.v_dict);
8458}
8459
8460/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008461 * "xor(expr, expr)" function
8462 */
8463 static void
8464f_xor(typval_T *argvars, typval_T *rettv)
8465{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008466 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8467 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008468}
8469
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008470#endif // FEAT_EVAL