blob: 363ac69492033014d18a9ec87f968293cf39eee0 [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}
283 static type_T *
284ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
285{
286 return &t_float;
287}
288 static type_T *
289ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
290{
291 return &t_string;
292}
293 static type_T * ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
294{
295 return &t_list_any;
296}
297 static type_T *
298ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
299{
300 return &t_list_number;
301}
302 static type_T *
303ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
304{
305 return &t_list_string;
306}
307 static type_T *
308ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
309{
310 return &t_list_dict_any;
311}
312 static type_T *
313ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
314{
315 return &t_dict_any;
316}
317 static type_T *
318ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
319{
320 return &t_dict_number;
321}
322 static type_T *
323ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
324{
325 return &t_dict_string;
326}
327 static type_T *
328ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
329{
330 return &t_blob;
331}
332 static type_T *
333ret_partial_void(int argcount UNUSED, type_T **argtypes UNUSED)
334{
335 return &t_partial_void;
336}
337#ifdef FEAT_JOB_CHANNEL
338 static type_T *
339ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
340{
341 return &t_channel;
342}
343 static type_T *
344ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
345{
346 return &t_job;
347}
348#endif
349
350static type_T *ret_f_function(int argcount, type_T **argtypes);
351
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352/*
353 * Array with names and number of arguments of all internal functions
354 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
355 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200356typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200358 char *f_name; // function name
359 char f_min_argc; // minimal number of arguments
360 char f_max_argc; // maximal number of arguments
361 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100362 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
363 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200364 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200365 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200366} funcentry_T;
367
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200368// values for f_argtype; zero means it cannot be used as a method
369#define FEARG_1 1 // base is the first argument
370#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200371#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200372#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200373#define FEARG_LAST 9 // base is the last argument
374
Bram Moolenaarac92e252019-08-03 21:58:38 +0200375static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200376{
377#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100378 {"abs", 1, 1, FEARG_1, ret_any, f_abs},
379 {"acos", 1, 1, FEARG_1, ret_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200380#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100381 {"add", 2, 2, FEARG_1, ret_any, f_add},
382 {"and", 2, 2, FEARG_1, ret_number, f_and},
383 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
384 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
385 {"argc", 0, 1, 0, ret_number, f_argc},
386 {"argidx", 0, 0, 0, ret_number, f_argidx},
387 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
388 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200389#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100390 {"asin", 1, 1, FEARG_1, ret_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100392 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
393 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
394 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile},
395 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
396 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
397 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
398 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
399 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
400 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
401 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
402 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
403 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200404#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100405 {"atan", 1, 1, FEARG_1, ret_float, f_atan},
406 {"atan2", 2, 2, FEARG_1, ret_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200407#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100408#ifdef FEAT_BEVAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100409 {"balloon_gettext", 0, 0, 0, ret_string, f_balloon_gettext},
410 {"balloon_show", 1, 1, FEARG_1, ret_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100411# if defined(FEAT_BEVAL_TERM)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100412 {"balloon_split", 1, 1, FEARG_1, ret_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100413# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100414#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100415 {"browse", 4, 4, 0, ret_string, f_browse},
416 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
417 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
418 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
419 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
420 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
421 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
422 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
423 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
424 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
425 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
426 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
427 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
428 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
429 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
430 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
431 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
432 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200433#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100434 {"ceil", 1, 1, FEARG_1, ret_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#endif
436#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100437 {"ch_canread", 1, 1, FEARG_1, ret_number, f_ch_canread},
438 {"ch_close", 1, 1, FEARG_1, ret_void, f_ch_close},
439 {"ch_close_in", 1, 1, FEARG_1, ret_void, f_ch_close_in},
440 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, f_ch_evalexpr},
441 {"ch_evalraw", 2, 3, FEARG_1, ret_any, f_ch_evalraw},
442 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, f_ch_getbufnr},
443 {"ch_getjob", 1, 1, FEARG_1, ret_job, f_ch_getjob},
444 {"ch_info", 1, 1, FEARG_1, ret_dict_any, f_ch_info},
445 {"ch_log", 1, 2, FEARG_1, ret_void, f_ch_log},
446 {"ch_logfile", 1, 2, FEARG_1, ret_void, f_ch_logfile},
447 {"ch_open", 1, 2, FEARG_1, ret_channel, f_ch_open},
448 {"ch_read", 1, 2, FEARG_1, ret_string, f_ch_read},
449 {"ch_readblob", 1, 2, FEARG_1, ret_blob, f_ch_readblob},
450 {"ch_readraw", 1, 2, FEARG_1, ret_string, f_ch_readraw},
451 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, f_ch_sendexpr},
452 {"ch_sendraw", 2, 3, FEARG_1, ret_void, f_ch_sendraw},
453 {"ch_setoptions", 2, 2, FEARG_1, ret_void, f_ch_setoptions},
454 {"ch_status", 1, 2, FEARG_1, ret_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200455#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100456 {"changenr", 0, 0, 0, ret_number, f_changenr},
457 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
458 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
459 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
460 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
461 {"col", 1, 1, FEARG_1, ret_number, f_col},
462 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
463 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
464 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
465 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
466 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
467 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200468#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100469 {"cos", 1, 1, FEARG_1, ret_float, f_cos},
470 {"cosh", 1, 1, FEARG_1, ret_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200471#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100472 {"count", 2, 4, FEARG_1, ret_number, f_count},
473 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
474 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100475#ifdef MSWIN
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100476 {"debugbreak", 1, 1, FEARG_1, ret_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200477#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100478 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
479 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
480 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
481 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
482 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
483 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
484 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
485 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
486 {"environ", 0, 0, 0, ret_dict_string, f_environ},
487 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
488 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
489 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
490 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
491 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
492 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
493 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200494#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100495 {"exp", 1, 1, FEARG_1, ret_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200496#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
498 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
499 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
500 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
501 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
502 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
503 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
504 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
505 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
506 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200507#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100508 {"float2nr", 1, 1, FEARG_1, ret_number, f_float2nr},
509 {"floor", 1, 1, FEARG_1, ret_float, f_floor},
510 {"fmod", 2, 2, FEARG_1, ret_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200511#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100512 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
513 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
514 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
515 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
516 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
517 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
518 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
519 {"foreground", 0, 0, 0, ret_void, f_foreground},
520 {"funcref", 1, 3, FEARG_1, ret_partial_void, f_funcref},
521 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
522 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
523 {"get", 2, 3, FEARG_1, ret_any, f_get},
524 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
525 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
526 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
527 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
528 {"getchar", 0, 1, 0, ret_number, f_getchar},
529 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
530 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
531 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
532 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
533 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
534 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
535 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
536 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
537 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
538 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
539 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
540 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
541 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
542 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
543 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
544 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
545 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
546 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
547 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
548 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
549 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
550 {"getpid", 0, 0, 0, ret_number, f_getpid},
551 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
552 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
553 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
554 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
555 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
556 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
557 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
558 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
559 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
560 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
561 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
562 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
563 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
564 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
565 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
566 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
567 {"has", 1, 1, 0, ret_number, f_has},
568 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
569 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
570 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
571 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
572 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
573 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
574 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
575 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
576 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
577 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
578 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
579 {"hostname", 0, 0, 0, ret_string, f_hostname},
580 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
581 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
582 {"index", 2, 4, FEARG_1, ret_number, f_index},
583 {"input", 1, 3, FEARG_1, ret_string, f_input},
584 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
585 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
586 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
587 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
588 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
589 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
590 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
591 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
592 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200593#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100594 {"isinf", 1, 1, FEARG_1, ret_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200595#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100596 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200597#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100598 {"isnan", 1, 1, FEARG_1, ret_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100602 {"job_getchannel", 1, 1, FEARG_1, ret_channel, f_job_getchannel},
603 {"job_info", 0, 1, FEARG_1, ret_dict_any, f_job_info},
604 {"job_setoptions", 2, 2, FEARG_1, ret_void, f_job_setoptions},
605 {"job_start", 1, 2, FEARG_1, ret_job, f_job_start},
606 {"job_status", 1, 1, FEARG_1, ret_string, f_job_status},
607 {"job_stop", 1, 2, FEARG_1, ret_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200608#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100609 {"join", 1, 2, FEARG_1, ret_string, f_join},
610 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
611 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
612 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
613 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
614 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
615 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
616 {"len", 1, 1, FEARG_1, ret_number, f_len},
617 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
618 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
619 {"line", 1, 2, FEARG_1, ret_number, f_line},
620 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
621 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
622 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
623 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
624 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
625 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
626 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100628 {"log", 1, 1, FEARG_1, ret_float, f_log},
629 {"log10", 1, 1, FEARG_1, ret_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200630#endif
631#ifdef FEAT_LUA
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100632 {"luaeval", 1, 2, FEARG_1, ret_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"map", 2, 2, FEARG_1, ret_any, f_map},
635 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
636 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
637 {"match", 2, 4, FEARG_1, ret_any, f_match},
638 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
639 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
640 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
641 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
642 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
643 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
644 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
645 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
646 {"max", 1, 1, FEARG_1, ret_any, f_max},
647 {"min", 1, 1, FEARG_1, ret_any, f_min},
648 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
649 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200650#ifdef FEAT_MZSCHEME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100651 {"mzeval", 1, 1, FEARG_1, ret_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100653 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
654 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
655 {"or", 2, 2, FEARG_1, ret_number, f_or},
656 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657#ifdef FEAT_PERL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100658 {"perleval", 1, 1, FEARG_1, ret_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200659#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100660#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100661 {"popup_atcursor", 2, 2, FEARG_1, ret_number, f_popup_atcursor},
662 {"popup_beval", 2, 2, FEARG_1, ret_number, f_popup_beval},
663 {"popup_clear", 0, 0, 0, ret_void, f_popup_clear},
664 {"popup_close", 1, 2, FEARG_1, ret_void, f_popup_close},
665 {"popup_create", 2, 2, FEARG_1, ret_number, f_popup_create},
666 {"popup_dialog", 2, 2, FEARG_1, ret_number, f_popup_dialog},
667 {"popup_filter_menu", 2, 2, 0, ret_number, f_popup_filter_menu},
668 {"popup_filter_yesno", 2, 2, 0, ret_number, f_popup_filter_yesno},
669 {"popup_findinfo", 0, 0, 0, ret_number, f_popup_findinfo},
670 {"popup_findpreview", 0, 0, 0, ret_number, f_popup_findpreview},
671 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, f_popup_getoptions},
672 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, f_popup_getpos},
673 {"popup_hide", 1, 1, FEARG_1, ret_void, f_popup_hide},
674 {"popup_locate", 2, 2, 0, ret_number, f_popup_locate},
675 {"popup_menu", 2, 2, FEARG_1, ret_number, f_popup_menu},
676 {"popup_move", 2, 2, FEARG_1, ret_void, f_popup_move},
677 {"popup_notification", 2, 2, FEARG_1, ret_number, f_popup_notification},
678 {"popup_setoptions", 2, 2, FEARG_1, ret_void, f_popup_setoptions},
679 {"popup_settext", 2, 2, FEARG_1, ret_void, f_popup_settext},
680 {"popup_show", 1, 1, FEARG_1, ret_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200681#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200682#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100683 {"pow", 2, 2, FEARG_1, ret_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200684#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100685 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
686 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200687#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100688 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, f_prompt_setcallback},
689 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, f_prompt_setinterrupt},
690 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200691#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100692#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100693 {"prop_add", 3, 3, FEARG_1, ret_void, f_prop_add},
694 {"prop_clear", 1, 3, FEARG_1, ret_void, f_prop_clear},
695 {"prop_find", 1, 2, FEARG_1, ret_dict_any, f_prop_find},
696 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, f_prop_list},
697 {"prop_remove", 1, 3, FEARG_1, ret_number, f_prop_remove},
698 {"prop_type_add", 2, 2, FEARG_1, ret_void, f_prop_type_add},
699 {"prop_type_change", 2, 2, FEARG_1, ret_void, f_prop_type_change},
700 {"prop_type_delete", 1, 2, FEARG_1, ret_void, f_prop_type_delete},
701 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, f_prop_type_get},
702 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100703#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100704 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
705 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200706#ifdef FEAT_PYTHON3
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100707 {"py3eval", 1, 1, FEARG_1, ret_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200708#endif
709#ifdef FEAT_PYTHON
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100710 {"pyeval", 1, 1, FEARG_1, ret_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200711#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100712#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100713 {"pyxeval", 1, 1, FEARG_1, ret_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100714#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100715 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
716 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
717 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
718 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
719 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
720 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
721 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200722#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100723 {"reltimefloat", 1, 1, FEARG_1, ret_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200724#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100725 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
726 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
727 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
728 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
729 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
730 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
731 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
732 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
733 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
734 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
735 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
736 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200737#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100738 {"round", 1, 1, FEARG_1, ret_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200739#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100740#ifdef FEAT_RUBY
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100741 {"rubyeval", 1, 1, FEARG_1, ret_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100742#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100743 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
744 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
745 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
746 {"screencol", 0, 0, 0, ret_number, f_screencol},
747 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
748 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
749 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
750 {"search", 1, 4, FEARG_1, ret_number, f_search},
751 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
752 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
753 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
754 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
755 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
756 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
757 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
758 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
759 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
760 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
761 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
762 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
763 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
764 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
765 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
766 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
767 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
768 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
769 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
770 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
771 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
772 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200773#ifdef FEAT_CRYPT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100774 {"sha256", 1, 1, FEARG_1, ret_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200775#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100776 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
777 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100778#ifdef FEAT_SIGNS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100779 {"sign_define", 1, 2, FEARG_1, ret_any, f_sign_define},
780 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, f_sign_getdefined},
781 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, f_sign_getplaced},
782 {"sign_jump", 3, 3, FEARG_1, ret_number, f_sign_jump},
783 {"sign_place", 4, 5, FEARG_1, ret_number, f_sign_place},
784 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, f_sign_placelist},
785 {"sign_undefine", 0, 1, FEARG_1, ret_number, f_sign_undefine},
786 {"sign_unplace", 1, 2, FEARG_1, ret_number, f_sign_unplace},
787 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100788#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100789 {"simplify", 1, 1, 0, ret_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200790#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100791 {"sin", 1, 1, FEARG_1, ret_float, f_sin},
792 {"sinh", 1, 1, FEARG_1, ret_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100794 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200795#ifdef FEAT_SOUND
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100796 {"sound_clear", 0, 0, 0, ret_void, f_sound_clear},
797 {"sound_playevent", 1, 2, FEARG_1, ret_number, f_sound_playevent},
798 {"sound_playfile", 1, 2, FEARG_1, ret_number, f_sound_playfile},
799 {"sound_stop", 1, 1, FEARG_1, ret_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200800#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100801 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
802 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
803 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
804 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200805#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100806 {"sqrt", 1, 1, FEARG_1, ret_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200807#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100808 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
809 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200810#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100811 {"str2float", 1, 1, FEARG_1, ret_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200812#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100813 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
814 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
815 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
816 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
817 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200818#ifdef HAVE_STRFTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100819 {"strftime", 1, 2, FEARG_1, ret_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100821 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
822 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
823 {"string", 1, 1, FEARG_1, ret_string, f_string},
824 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
825 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100826#ifdef HAVE_STRPTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100827 {"strptime", 2, 2, FEARG_1, ret_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100828#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100829 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
830 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
831 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
832 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
833 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
834 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
835 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
836 {"synID", 3, 3, 0, ret_number, f_synID},
837 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
838 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
839 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
840 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
841 {"system", 1, 2, FEARG_1, ret_string, f_system},
842 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
843 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
844 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
845 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
846 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
847 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100849 {"tan", 1, 1, FEARG_1, ret_float, f_tan},
850 {"tanh", 1, 1, FEARG_1, ret_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100852 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200853#ifdef FEAT_TERMINAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100854 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, f_term_dumpdiff},
855 {"term_dumpload", 1, 2, FEARG_1, ret_number, f_term_dumpload},
856 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, f_term_dumpwrite},
857 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200858# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100859 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200860# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100861 {"term_getattr", 2, 2, FEARG_1, ret_number, f_term_getattr},
862 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, f_term_getcursor},
863 {"term_getjob", 1, 1, FEARG_1, ret_job, f_term_getjob},
864 {"term_getline", 2, 2, FEARG_1, ret_string, f_term_getline},
865 {"term_getscrolled", 1, 1, FEARG_1, ret_number, f_term_getscrolled},
866 {"term_getsize", 1, 1, FEARG_1, ret_list_number, f_term_getsize},
867 {"term_getstatus", 1, 1, FEARG_1, ret_string, f_term_getstatus},
868 {"term_gettitle", 1, 1, FEARG_1, ret_string, f_term_gettitle},
869 {"term_gettty", 1, 2, FEARG_1, ret_string, f_term_gettty},
870 {"term_list", 0, 0, 0, ret_list_number, f_term_list},
871 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, f_term_scrape},
872 {"term_sendkeys", 2, 2, FEARG_1, ret_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200873# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100874 {"term_setansicolors", 2, 2, FEARG_1, ret_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200875# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100876 {"term_setapi", 2, 2, FEARG_1, ret_void, f_term_setapi},
877 {"term_setkill", 2, 2, FEARG_1, ret_void, f_term_setkill},
878 {"term_setrestore", 2, 2, FEARG_1, ret_void, f_term_setrestore},
879 {"term_setsize", 3, 3, FEARG_1, ret_void, f_term_setsize},
880 {"term_start", 1, 2, FEARG_1, ret_number, f_term_start},
881 {"term_wait", 1, 2, FEARG_1, ret_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200882#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100883 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
884 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
885 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
886 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
887 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
888 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
889 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
890 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200891#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100892 {"test_null_channel", 0, 0, 0, ret_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200893#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100894 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200895#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100896 {"test_null_job", 0, 0, 0, ret_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200897#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100898 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
899 {"test_null_partial", 0, 0, 0, ret_partial_void, f_test_null_partial},
900 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
901 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
902 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
903 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200904#ifdef FEAT_GUI
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100905 {"test_scrollbar", 3, 3, FEARG_2, ret_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200906#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100907 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
908 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
909 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
910 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
911 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200912#ifdef FEAT_TIMERS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100913 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, f_timer_info},
914 {"timer_pause", 2, 2, FEARG_1, ret_void, f_timer_pause},
915 {"timer_start", 2, 3, FEARG_1, ret_number, f_timer_start},
916 {"timer_stop", 1, 1, FEARG_1, ret_void, f_timer_stop},
917 {"timer_stopall", 0, 0, 0, ret_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100919 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
920 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
921 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
922 {"trim", 1, 2, FEARG_1, ret_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100924 {"trunc", 1, 1, FEARG_1, ret_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100926 {"type", 1, 1, FEARG_1, ret_number, f_type},
927 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
928 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
929 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
930 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
931 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
932 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
933 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
934 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
935 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
936 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
937 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
938 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
939 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
940 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
941 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
942 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
943 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
944 {"wincol", 0, 0, 0, ret_number, f_wincol},
945 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
946 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
947 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
948 {"winline", 0, 0, 0, ret_number, f_winline},
949 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
950 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
951 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
952 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
953 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
954 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
955 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
956 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200957};
958
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200959/*
960 * Function given to ExpandGeneric() to obtain the list of internal
961 * or user defined function names.
962 */
963 char_u *
964get_function_name(expand_T *xp, int idx)
965{
966 static int intidx = -1;
967 char_u *name;
968
969 if (idx == 0)
970 intidx = -1;
971 if (intidx < 0)
972 {
973 name = get_user_func_name(xp, idx);
974 if (name != NULL)
975 return name;
976 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200977 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200978 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200979 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200980 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200981 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200982 STRCAT(IObuff, ")");
983 return IObuff;
984 }
985
986 return NULL;
987}
988
989/*
990 * Function given to ExpandGeneric() to obtain the list of internal or
991 * user defined variable or function names.
992 */
993 char_u *
994get_expr_name(expand_T *xp, int idx)
995{
996 static int intidx = -1;
997 char_u *name;
998
999 if (idx == 0)
1000 intidx = -1;
1001 if (intidx < 0)
1002 {
1003 name = get_function_name(xp, idx);
1004 if (name != NULL)
1005 return name;
1006 }
1007 return get_user_var_name(xp, ++intidx);
1008}
1009
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001010/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001011 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012 * Return index, or -1 if not found
1013 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001014 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001015find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001016{
1017 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001018 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019 int cmp;
1020 int x;
1021
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001022 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001023
1024 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001025 while (first <= last)
1026 {
1027 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001028 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001029 if (cmp < 0)
1030 last = x - 1;
1031 else if (cmp > 0)
1032 first = x + 1;
1033 else
1034 return x;
1035 }
1036 return -1;
1037}
1038
1039 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001040has_internal_func(char_u *name)
1041{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001042 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001043}
1044
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001045 char *
1046internal_func_name(int idx)
1047{
1048 return global_functions[idx].f_name;
1049}
1050
1051 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001052internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001053{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001054 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001055}
1056
1057/*
1058 * Check the argument count to use for internal function "idx".
1059 * Returns OK or FAIL;
1060 */
1061 int
1062check_internal_func(int idx, int argcount)
1063{
1064 int res;
1065 char *name;
1066
1067 if (argcount < global_functions[idx].f_min_argc)
1068 res = FCERR_TOOFEW;
1069 else if (argcount > global_functions[idx].f_max_argc)
1070 res = FCERR_TOOMANY;
1071 else
1072 return OK;
1073
1074 name = internal_func_name(idx);
1075 if (res == FCERR_TOOMANY)
1076 semsg(_(e_toomanyarg), name);
1077 else
1078 semsg(_(e_toofewarg), name);
1079 return FAIL;
1080}
1081
Bram Moolenaarac92e252019-08-03 21:58:38 +02001082 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001083call_internal_func(
1084 char_u *name,
1085 int argcount,
1086 typval_T *argvars,
1087 typval_T *rettv)
1088{
1089 int i;
1090
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001091 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001092 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001093 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001094 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001095 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001096 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001097 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001098 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001099 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001100 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001101}
1102
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001103 void
1104call_internal_func_by_idx(
1105 int idx,
1106 typval_T *argvars,
1107 typval_T *rettv)
1108{
1109 global_functions[idx].f_func(argvars, rettv);
1110}
1111
Bram Moolenaarac92e252019-08-03 21:58:38 +02001112/*
1113 * Invoke a method for base->method().
1114 */
1115 int
1116call_internal_method(
1117 char_u *name,
1118 int argcount,
1119 typval_T *argvars,
1120 typval_T *rettv,
1121 typval_T *basetv)
1122{
1123 int i;
1124 int fi;
1125 typval_T argv[MAX_FUNC_ARGS + 1];
1126
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001127 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001128 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001129 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001130 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001131 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001132 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001133 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001134 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001135 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001136
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001137 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001138 {
1139 // base value goes last
1140 for (i = 0; i < argcount; ++i)
1141 argv[i] = argvars[i];
1142 argv[argcount] = *basetv;
1143 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001144 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001145 {
1146 // base value goes second
1147 argv[0] = argvars[0];
1148 argv[1] = *basetv;
1149 for (i = 1; i < argcount; ++i)
1150 argv[i + 1] = argvars[i];
1151 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001152 else if (global_functions[fi].f_argtype == FEARG_3)
1153 {
1154 // base value goes third
1155 argv[0] = argvars[0];
1156 argv[1] = argvars[1];
1157 argv[2] = *basetv;
1158 for (i = 2; i < argcount; ++i)
1159 argv[i + 1] = argvars[i];
1160 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001161 else if (global_functions[fi].f_argtype == FEARG_4)
1162 {
1163 // base value goes fourth
1164 argv[0] = argvars[0];
1165 argv[1] = argvars[1];
1166 argv[2] = argvars[2];
1167 argv[3] = *basetv;
1168 for (i = 3; i < argcount; ++i)
1169 argv[i + 1] = argvars[i];
1170 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001171 else
1172 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001173 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001174 argv[0] = *basetv;
1175 for (i = 0; i < argcount; ++i)
1176 argv[i + 1] = argvars[i];
1177 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001178 argv[argcount + 1].v_type = VAR_UNKNOWN;
1179
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001180 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001181 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001182}
1183
1184/*
1185 * Return TRUE for a non-zero Number and a non-empty String.
1186 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001187 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001188non_zero_arg(typval_T *argvars)
1189{
1190 return ((argvars[0].v_type == VAR_NUMBER
1191 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001192 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001193 && argvars[0].vval.v_number == VVAL_TRUE)
1194 || (argvars[0].v_type == VAR_STRING
1195 && argvars[0].vval.v_string != NULL
1196 && *argvars[0].vval.v_string != NUL));
1197}
1198
1199/*
1200 * Get the lnum from the first argument.
1201 * Also accepts ".", "$", etc., but that only works for the current buffer.
1202 * Returns -1 on error.
1203 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001204 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001205tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001206{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001207 linenr_T lnum;
1208
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001209 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001210 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001211 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001212 int fnum;
1213 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1214
1215 if (fp != NULL)
1216 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001217 }
1218 return lnum;
1219}
1220
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001221/*
1222 * Get the lnum from the first argument.
1223 * Also accepts "$", then "buf" is used.
1224 * Returns 0 on error.
1225 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001226 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001227tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1228{
1229 if (argvars[0].v_type == VAR_STRING
1230 && argvars[0].vval.v_string != NULL
1231 && argvars[0].vval.v_string[0] == '$'
1232 && buf != NULL)
1233 return buf->b_ml.ml_line_count;
1234 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1235}
1236
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001237#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001238/*
1239 * Get the float value of "argvars[0]" into "f".
1240 * Returns FAIL when the argument is not a Number or Float.
1241 */
1242 static int
1243get_float_arg(typval_T *argvars, float_T *f)
1244{
1245 if (argvars[0].v_type == VAR_FLOAT)
1246 {
1247 *f = argvars[0].vval.v_float;
1248 return OK;
1249 }
1250 if (argvars[0].v_type == VAR_NUMBER)
1251 {
1252 *f = (float_T)argvars[0].vval.v_number;
1253 return OK;
1254 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001255 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001256 return FAIL;
1257}
1258
1259/*
1260 * "abs(expr)" function
1261 */
1262 static void
1263f_abs(typval_T *argvars, typval_T *rettv)
1264{
1265 if (argvars[0].v_type == VAR_FLOAT)
1266 {
1267 rettv->v_type = VAR_FLOAT;
1268 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1269 }
1270 else
1271 {
1272 varnumber_T n;
1273 int error = FALSE;
1274
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001275 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001276 if (error)
1277 rettv->vval.v_number = -1;
1278 else if (n > 0)
1279 rettv->vval.v_number = n;
1280 else
1281 rettv->vval.v_number = -n;
1282 }
1283}
1284
1285/*
1286 * "acos()" function
1287 */
1288 static void
1289f_acos(typval_T *argvars, typval_T *rettv)
1290{
1291 float_T f = 0.0;
1292
1293 rettv->v_type = VAR_FLOAT;
1294 if (get_float_arg(argvars, &f) == OK)
1295 rettv->vval.v_float = acos(f);
1296 else
1297 rettv->vval.v_float = 0.0;
1298}
1299#endif
1300
1301/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001302 * "and(expr, expr)" function
1303 */
1304 static void
1305f_and(typval_T *argvars, typval_T *rettv)
1306{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001307 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1308 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001309}
1310
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001311#ifdef FEAT_FLOAT
1312/*
1313 * "asin()" function
1314 */
1315 static void
1316f_asin(typval_T *argvars, typval_T *rettv)
1317{
1318 float_T f = 0.0;
1319
1320 rettv->v_type = VAR_FLOAT;
1321 if (get_float_arg(argvars, &f) == OK)
1322 rettv->vval.v_float = asin(f);
1323 else
1324 rettv->vval.v_float = 0.0;
1325}
1326
1327/*
1328 * "atan()" function
1329 */
1330 static void
1331f_atan(typval_T *argvars, typval_T *rettv)
1332{
1333 float_T f = 0.0;
1334
1335 rettv->v_type = VAR_FLOAT;
1336 if (get_float_arg(argvars, &f) == OK)
1337 rettv->vval.v_float = atan(f);
1338 else
1339 rettv->vval.v_float = 0.0;
1340}
1341
1342/*
1343 * "atan2()" function
1344 */
1345 static void
1346f_atan2(typval_T *argvars, typval_T *rettv)
1347{
1348 float_T fx = 0.0, fy = 0.0;
1349
1350 rettv->v_type = VAR_FLOAT;
1351 if (get_float_arg(argvars, &fx) == OK
1352 && get_float_arg(&argvars[1], &fy) == OK)
1353 rettv->vval.v_float = atan2(fx, fy);
1354 else
1355 rettv->vval.v_float = 0.0;
1356}
1357#endif
1358
1359/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001360 * "balloon_show()" function
1361 */
1362#ifdef FEAT_BEVAL
1363 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001364f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1365{
1366 rettv->v_type = VAR_STRING;
1367 if (balloonEval != NULL)
1368 {
1369 if (balloonEval->msg == NULL)
1370 rettv->vval.v_string = NULL;
1371 else
1372 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1373 }
1374}
1375
1376 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001377f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1378{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001379 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001380 {
1381 if (argvars[0].v_type == VAR_LIST
1382# ifdef FEAT_GUI
1383 && !gui.in_use
1384# endif
1385 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001386 {
1387 list_T *l = argvars[0].vval.v_list;
1388
1389 // empty list removes the balloon
1390 post_balloon(balloonEval, NULL,
1391 l == NULL || l->lv_len == 0 ? NULL : l);
1392 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001393 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001394 {
1395 char_u *mesg = tv_get_string_chk(&argvars[0]);
1396
1397 if (mesg != NULL)
1398 // empty string removes the balloon
1399 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1400 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001401 }
1402}
1403
Bram Moolenaar669a8282017-11-19 20:13:05 +01001404# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001405 static void
1406f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1407{
1408 if (rettv_list_alloc(rettv) == OK)
1409 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001410 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001411
1412 if (msg != NULL)
1413 {
1414 pumitem_T *array;
1415 int size = split_message(msg, &array);
1416 int i;
1417
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001418 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001419 for (i = 1; i < size - 1; ++i)
1420 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001421 while (size > 0)
1422 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001423 vim_free(array);
1424 }
1425 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001426}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001427# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001428#endif
1429
1430/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001431 * Get buffer by number or pattern.
1432 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001433 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001434tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001435{
1436 char_u *name = tv->vval.v_string;
1437 buf_T *buf;
1438
1439 if (tv->v_type == VAR_NUMBER)
1440 return buflist_findnr((int)tv->vval.v_number);
1441 if (tv->v_type != VAR_STRING)
1442 return NULL;
1443 if (name == NULL || *name == NUL)
1444 return curbuf;
1445 if (name[0] == '$' && name[1] == NUL)
1446 return lastbuf;
1447
1448 buf = buflist_find_by_name(name, curtab_only);
1449
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001450 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001451 if (buf == NULL)
1452 buf = find_buffer(tv);
1453
1454 return buf;
1455}
1456
1457/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001458 * Get the buffer from "arg" and give an error and return NULL if it is not
1459 * valid.
1460 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001461 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001462get_buf_arg(typval_T *arg)
1463{
1464 buf_T *buf;
1465
1466 ++emsg_off;
1467 buf = tv_get_buf(arg, FALSE);
1468 --emsg_off;
1469 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001470 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001471 return buf;
1472}
1473
1474/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001475 * "byte2line(byte)" function
1476 */
1477 static void
1478f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1479{
1480#ifndef FEAT_BYTEOFF
1481 rettv->vval.v_number = -1;
1482#else
1483 long boff = 0;
1484
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001485 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486 if (boff < 0)
1487 rettv->vval.v_number = -1;
1488 else
1489 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1490 (linenr_T)0, &boff);
1491#endif
1492}
1493
1494 static void
1495byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1496{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001498 char_u *str;
1499 varnumber_T idx;
1500
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001501 str = tv_get_string_chk(&argvars[0]);
1502 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001503 rettv->vval.v_number = -1;
1504 if (str == NULL || idx < 0)
1505 return;
1506
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001507 t = str;
1508 for ( ; idx > 0; idx--)
1509 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001510 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001511 return;
1512 if (enc_utf8 && comp)
1513 t += utf_ptr2len(t);
1514 else
1515 t += (*mb_ptr2len)(t);
1516 }
1517 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001518}
1519
1520/*
1521 * "byteidx()" function
1522 */
1523 static void
1524f_byteidx(typval_T *argvars, typval_T *rettv)
1525{
1526 byteidx(argvars, rettv, FALSE);
1527}
1528
1529/*
1530 * "byteidxcomp()" function
1531 */
1532 static void
1533f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1534{
1535 byteidx(argvars, rettv, TRUE);
1536}
1537
1538/*
1539 * "call(func, arglist [, dict])" function
1540 */
1541 static void
1542f_call(typval_T *argvars, typval_T *rettv)
1543{
1544 char_u *func;
1545 partial_T *partial = NULL;
1546 dict_T *selfdict = NULL;
1547
1548 if (argvars[1].v_type != VAR_LIST)
1549 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001550 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001551 return;
1552 }
1553 if (argvars[1].vval.v_list == NULL)
1554 return;
1555
1556 if (argvars[0].v_type == VAR_FUNC)
1557 func = argvars[0].vval.v_string;
1558 else if (argvars[0].v_type == VAR_PARTIAL)
1559 {
1560 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001561 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001562 }
1563 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001564 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001565 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001566 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567
1568 if (argvars[2].v_type != VAR_UNKNOWN)
1569 {
1570 if (argvars[2].v_type != VAR_DICT)
1571 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001572 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001573 return;
1574 }
1575 selfdict = argvars[2].vval.v_dict;
1576 }
1577
1578 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1579}
1580
1581#ifdef FEAT_FLOAT
1582/*
1583 * "ceil({float})" function
1584 */
1585 static void
1586f_ceil(typval_T *argvars, typval_T *rettv)
1587{
1588 float_T f = 0.0;
1589
1590 rettv->v_type = VAR_FLOAT;
1591 if (get_float_arg(argvars, &f) == OK)
1592 rettv->vval.v_float = ceil(f);
1593 else
1594 rettv->vval.v_float = 0.0;
1595}
1596#endif
1597
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598/*
1599 * "changenr()" function
1600 */
1601 static void
1602f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1603{
1604 rettv->vval.v_number = curbuf->b_u_seq_cur;
1605}
1606
1607/*
1608 * "char2nr(string)" function
1609 */
1610 static void
1611f_char2nr(typval_T *argvars, typval_T *rettv)
1612{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001613 if (has_mbyte)
1614 {
1615 int utf8 = 0;
1616
1617 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001618 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001619
1620 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001621 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001623 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624 }
1625 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001626 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627}
1628
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001629 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001630get_optional_window(typval_T *argvars, int idx)
1631{
1632 win_T *win = curwin;
1633
1634 if (argvars[idx].v_type != VAR_UNKNOWN)
1635 {
1636 win = find_win_by_nr_or_id(&argvars[idx]);
1637 if (win == NULL)
1638 {
1639 emsg(_(e_invalwindow));
1640 return NULL;
1641 }
1642 }
1643 return win;
1644}
1645
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001647 * "col(string)" function
1648 */
1649 static void
1650f_col(typval_T *argvars, typval_T *rettv)
1651{
1652 colnr_T col = 0;
1653 pos_T *fp;
1654 int fnum = curbuf->b_fnum;
1655
1656 fp = var2fpos(&argvars[0], FALSE, &fnum);
1657 if (fp != NULL && fnum == curbuf->b_fnum)
1658 {
1659 if (fp->col == MAXCOL)
1660 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001661 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001662 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1663 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1664 else
1665 col = MAXCOL;
1666 }
1667 else
1668 {
1669 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001670 // col(".") when the cursor is on the NUL at the end of the line
1671 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001672 if (virtual_active() && fp == &curwin->w_cursor)
1673 {
1674 char_u *p = ml_get_cursor();
1675
1676 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1677 curwin->w_virtcol - curwin->w_cursor.coladd))
1678 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001679 int l;
1680
1681 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1682 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001683 }
1684 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 }
1686 }
1687 rettv->vval.v_number = col;
1688}
1689
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001690/*
1691 * "confirm(message, buttons[, default [, type]])" function
1692 */
1693 static void
1694f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1695{
1696#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1697 char_u *message;
1698 char_u *buttons = NULL;
1699 char_u buf[NUMBUFLEN];
1700 char_u buf2[NUMBUFLEN];
1701 int def = 1;
1702 int type = VIM_GENERIC;
1703 char_u *typestr;
1704 int error = FALSE;
1705
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001706 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001707 if (message == NULL)
1708 error = TRUE;
1709 if (argvars[1].v_type != VAR_UNKNOWN)
1710 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001711 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 if (buttons == NULL)
1713 error = TRUE;
1714 if (argvars[2].v_type != VAR_UNKNOWN)
1715 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001716 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001717 if (argvars[3].v_type != VAR_UNKNOWN)
1718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001719 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720 if (typestr == NULL)
1721 error = TRUE;
1722 else
1723 {
1724 switch (TOUPPER_ASC(*typestr))
1725 {
1726 case 'E': type = VIM_ERROR; break;
1727 case 'Q': type = VIM_QUESTION; break;
1728 case 'I': type = VIM_INFO; break;
1729 case 'W': type = VIM_WARNING; break;
1730 case 'G': type = VIM_GENERIC; break;
1731 }
1732 }
1733 }
1734 }
1735 }
1736
1737 if (buttons == NULL || *buttons == NUL)
1738 buttons = (char_u *)_("&Ok");
1739
1740 if (!error)
1741 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1742 def, NULL, FALSE);
1743#endif
1744}
1745
1746/*
1747 * "copy()" function
1748 */
1749 static void
1750f_copy(typval_T *argvars, typval_T *rettv)
1751{
1752 item_copy(&argvars[0], rettv, FALSE, 0);
1753}
1754
1755#ifdef FEAT_FLOAT
1756/*
1757 * "cos()" function
1758 */
1759 static void
1760f_cos(typval_T *argvars, typval_T *rettv)
1761{
1762 float_T f = 0.0;
1763
1764 rettv->v_type = VAR_FLOAT;
1765 if (get_float_arg(argvars, &f) == OK)
1766 rettv->vval.v_float = cos(f);
1767 else
1768 rettv->vval.v_float = 0.0;
1769}
1770
1771/*
1772 * "cosh()" function
1773 */
1774 static void
1775f_cosh(typval_T *argvars, typval_T *rettv)
1776{
1777 float_T f = 0.0;
1778
1779 rettv->v_type = VAR_FLOAT;
1780 if (get_float_arg(argvars, &f) == OK)
1781 rettv->vval.v_float = cosh(f);
1782 else
1783 rettv->vval.v_float = 0.0;
1784}
1785#endif
1786
1787/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001788 * "cursor(lnum, col)" function, or
1789 * "cursor(list)"
1790 *
1791 * Moves the cursor to the specified line and column.
1792 * Returns 0 when the position could be set, -1 otherwise.
1793 */
1794 static void
1795f_cursor(typval_T *argvars, typval_T *rettv)
1796{
1797 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001798 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001799 int set_curswant = TRUE;
1800
1801 rettv->vval.v_number = -1;
1802 if (argvars[1].v_type == VAR_UNKNOWN)
1803 {
1804 pos_T pos;
1805 colnr_T curswant = -1;
1806
1807 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1808 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001809 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001810 return;
1811 }
1812 line = pos.lnum;
1813 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001814 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001815 if (curswant >= 0)
1816 {
1817 curwin->w_curswant = curswant - 1;
1818 set_curswant = FALSE;
1819 }
1820 }
1821 else
1822 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001823 line = tv_get_lnum(argvars);
1824 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001826 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001827 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001828 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001829 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 if (line > 0)
1831 curwin->w_cursor.lnum = line;
1832 if (col > 0)
1833 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001836 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001837 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001838 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 if (has_mbyte)
1840 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001841
1842 curwin->w_set_curswant = set_curswant;
1843 rettv->vval.v_number = 0;
1844}
1845
Bram Moolenaar4f974752019-02-17 17:44:42 +01001846#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001847/*
1848 * "debugbreak()" function
1849 */
1850 static void
1851f_debugbreak(typval_T *argvars, typval_T *rettv)
1852{
1853 int pid;
1854
1855 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001856 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001857 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001858 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001859 else
1860 {
1861 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1862
1863 if (hProcess != NULL)
1864 {
1865 DebugBreakProcess(hProcess);
1866 CloseHandle(hProcess);
1867 rettv->vval.v_number = OK;
1868 }
1869 }
1870}
1871#endif
1872
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001873/*
1874 * "deepcopy()" function
1875 */
1876 static void
1877f_deepcopy(typval_T *argvars, typval_T *rettv)
1878{
1879 int noref = 0;
1880 int copyID;
1881
1882 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001883 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001884 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001885 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001886 else
1887 {
1888 copyID = get_copyID();
1889 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1890 }
1891}
1892
1893/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001894 * "did_filetype()" function
1895 */
1896 static void
1897f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1898{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001899 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900}
1901
1902/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001903 * "echoraw({expr})" function
1904 */
1905 static void
1906f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1907{
1908 char_u *str = tv_get_string_chk(&argvars[0]);
1909
1910 if (str != NULL && *str != NUL)
1911 {
1912 out_str(str);
1913 out_flush();
1914 }
1915}
1916
1917/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001918 * "empty({expr})" function
1919 */
1920 static void
1921f_empty(typval_T *argvars, typval_T *rettv)
1922{
1923 int n = FALSE;
1924
1925 switch (argvars[0].v_type)
1926 {
1927 case VAR_STRING:
1928 case VAR_FUNC:
1929 n = argvars[0].vval.v_string == NULL
1930 || *argvars[0].vval.v_string == NUL;
1931 break;
1932 case VAR_PARTIAL:
1933 n = FALSE;
1934 break;
1935 case VAR_NUMBER:
1936 n = argvars[0].vval.v_number == 0;
1937 break;
1938 case VAR_FLOAT:
1939#ifdef FEAT_FLOAT
1940 n = argvars[0].vval.v_float == 0.0;
1941 break;
1942#endif
1943 case VAR_LIST:
1944 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001945 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001946 break;
1947 case VAR_DICT:
1948 n = argvars[0].vval.v_dict == NULL
1949 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1950 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001951 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001952 case VAR_SPECIAL:
1953 n = argvars[0].vval.v_number != VVAL_TRUE;
1954 break;
1955
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001956 case VAR_BLOB:
1957 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001958 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1959 break;
1960
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001961 case VAR_JOB:
1962#ifdef FEAT_JOB_CHANNEL
1963 n = argvars[0].vval.v_job == NULL
1964 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1965 break;
1966#endif
1967 case VAR_CHANNEL:
1968#ifdef FEAT_JOB_CHANNEL
1969 n = argvars[0].vval.v_channel == NULL
1970 || !channel_is_open(argvars[0].vval.v_channel);
1971 break;
1972#endif
1973 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001974 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001975 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 n = TRUE;
1977 break;
1978 }
1979
1980 rettv->vval.v_number = n;
1981}
1982
1983/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001984 * "environ()" function
1985 */
1986 static void
1987f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1988{
1989#if !defined(AMIGA)
1990 int i = 0;
1991 char_u *entry, *value;
1992# ifdef MSWIN
1993 extern wchar_t **_wenviron;
1994# else
1995 extern char **environ;
1996# endif
1997
1998 if (rettv_dict_alloc(rettv) != OK)
1999 return;
2000
2001# ifdef MSWIN
2002 if (*_wenviron == NULL)
2003 return;
2004# else
2005 if (*environ == NULL)
2006 return;
2007# endif
2008
2009 for (i = 0; ; ++i)
2010 {
2011# ifdef MSWIN
2012 short_u *p;
2013
2014 if ((p = (short_u *)_wenviron[i]) == NULL)
2015 return;
2016 entry = utf16_to_enc(p, NULL);
2017# else
2018 if ((entry = (char_u *)environ[i]) == NULL)
2019 return;
2020 entry = vim_strsave(entry);
2021# endif
2022 if (entry == NULL) // out of memory
2023 return;
2024 if ((value = vim_strchr(entry, '=')) == NULL)
2025 {
2026 vim_free(entry);
2027 continue;
2028 }
2029 *value++ = NUL;
2030 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2031 vim_free(entry);
2032 }
2033#endif
2034}
2035
2036/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002037 * "escape({string}, {chars})" function
2038 */
2039 static void
2040f_escape(typval_T *argvars, typval_T *rettv)
2041{
2042 char_u buf[NUMBUFLEN];
2043
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002044 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2045 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002046 rettv->v_type = VAR_STRING;
2047}
2048
2049/*
2050 * "eval()" function
2051 */
2052 static void
2053f_eval(typval_T *argvars, typval_T *rettv)
2054{
2055 char_u *s, *p;
2056
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002057 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058 if (s != NULL)
2059 s = skipwhite(s);
2060
2061 p = s;
2062 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2063 {
2064 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002065 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002066 need_clr_eos = FALSE;
2067 rettv->v_type = VAR_NUMBER;
2068 rettv->vval.v_number = 0;
2069 }
2070 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002071 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002072}
2073
2074/*
2075 * "eventhandler()" function
2076 */
2077 static void
2078f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2079{
2080 rettv->vval.v_number = vgetc_busy;
2081}
2082
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002083static garray_T redir_execute_ga;
2084
2085/*
2086 * Append "value[value_len]" to the execute() output.
2087 */
2088 void
2089execute_redir_str(char_u *value, int value_len)
2090{
2091 int len;
2092
2093 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002094 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002096 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 if (ga_grow(&redir_execute_ga, len) == OK)
2098 {
2099 mch_memmove((char *)redir_execute_ga.ga_data
2100 + redir_execute_ga.ga_len, value, len);
2101 redir_execute_ga.ga_len += len;
2102 }
2103}
2104
2105/*
2106 * Get next line from a list.
2107 * Called by do_cmdline() to get the next line.
2108 * Returns allocated string, or NULL for end of function.
2109 */
2110
2111 static char_u *
2112get_list_line(
2113 int c UNUSED,
2114 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002115 int indent UNUSED,
2116 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002117{
2118 listitem_T **p = (listitem_T **)cookie;
2119 listitem_T *item = *p;
2120 char_u buf[NUMBUFLEN];
2121 char_u *s;
2122
2123 if (item == NULL)
2124 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002125 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002126 *p = item->li_next;
2127 return s == NULL ? NULL : vim_strsave(s);
2128}
2129
2130/*
2131 * "execute()" function
2132 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002133 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002134execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135{
2136 char_u *cmd = NULL;
2137 list_T *list = NULL;
2138 int save_msg_silent = msg_silent;
2139 int save_emsg_silent = emsg_silent;
2140 int save_emsg_noredir = emsg_noredir;
2141 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002142 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002143 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002144 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002145 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002146
2147 rettv->vval.v_string = NULL;
2148 rettv->v_type = VAR_STRING;
2149
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002150 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002151 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002152 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002153 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002154 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002155 return;
2156 ++list->lv_refcount;
2157 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002158 else if (argvars[arg_off].v_type == VAR_JOB
2159 || argvars[arg_off].v_type == VAR_CHANNEL)
2160 {
2161 emsg(_(e_inval_string));
2162 return;
2163 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 else
2165 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002166 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167 if (cmd == NULL)
2168 return;
2169 }
2170
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002171 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172 {
2173 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002174 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175
2176 if (s == NULL)
2177 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002178 if (*s == NUL)
2179 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180 if (STRNCMP(s, "silent", 6) == 0)
2181 ++msg_silent;
2182 if (STRCMP(s, "silent!") == 0)
2183 {
2184 emsg_silent = TRUE;
2185 emsg_noredir = TRUE;
2186 }
2187 }
2188 else
2189 ++msg_silent;
2190
2191 if (redir_execute)
2192 save_ga = redir_execute_ga;
2193 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2194 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002195 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002196 if (!echo_output)
2197 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002198
2199 if (cmd != NULL)
2200 do_cmdline_cmd(cmd);
2201 else
2202 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002203 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002205 range_list_materialize(list);
2206 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207 do_cmdline(NULL, get_list_line, (void *)&item,
2208 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2209 --list->lv_refcount;
2210 }
2211
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002212 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002213 if (ga_grow(&redir_execute_ga, 1) == OK)
2214 {
2215 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2216 rettv->vval.v_string = redir_execute_ga.ga_data;
2217 }
2218 else
2219 {
2220 ga_clear(&redir_execute_ga);
2221 rettv->vval.v_string = NULL;
2222 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002223 msg_silent = save_msg_silent;
2224 emsg_silent = save_emsg_silent;
2225 emsg_noredir = save_emsg_noredir;
2226
2227 redir_execute = save_redir_execute;
2228 if (redir_execute)
2229 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002230 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002231
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002232 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002233 if (echo_output)
2234 // When not working silently: put it in column zero. A following
2235 // "echon" will overwrite the message, unavoidably.
2236 msg_col = 0;
2237 else
2238 // When working silently: Put it back where it was, since nothing
2239 // should have been written.
2240 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002241}
2242
2243/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002244 * "execute()" function
2245 */
2246 static void
2247f_execute(typval_T *argvars, typval_T *rettv)
2248{
2249 execute_common(argvars, rettv, 0);
2250}
2251
2252/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002253 * "exists()" function
2254 */
2255 static void
2256f_exists(typval_T *argvars, typval_T *rettv)
2257{
2258 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002259 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002260
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002261 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002262 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002264 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002265 if (mch_getenv(p + 1) != NULL)
2266 n = TRUE;
2267 else
2268 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002269 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002270 p = expand_env_save(p);
2271 if (p != NULL && *p != '$')
2272 n = TRUE;
2273 vim_free(p);
2274 }
2275 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002276 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002277 {
2278 n = (get_option_tv(&p, NULL, TRUE) == OK);
2279 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002280 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002281 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002282 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002283 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002284 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002285 }
2286 else if (*p == ':')
2287 {
2288 n = cmd_exists(p + 1);
2289 }
2290 else if (*p == '#')
2291 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 if (p[1] == '#')
2293 n = autocmd_supported(p + 2);
2294 else
2295 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002296 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002297 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002298 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002299 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002300 }
2301
2302 rettv->vval.v_number = n;
2303}
2304
2305#ifdef FEAT_FLOAT
2306/*
2307 * "exp()" function
2308 */
2309 static void
2310f_exp(typval_T *argvars, typval_T *rettv)
2311{
2312 float_T f = 0.0;
2313
2314 rettv->v_type = VAR_FLOAT;
2315 if (get_float_arg(argvars, &f) == OK)
2316 rettv->vval.v_float = exp(f);
2317 else
2318 rettv->vval.v_float = 0.0;
2319}
2320#endif
2321
2322/*
2323 * "expand()" function
2324 */
2325 static void
2326f_expand(typval_T *argvars, typval_T *rettv)
2327{
2328 char_u *s;
2329 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002330 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002331 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2332 expand_T xpc;
2333 int error = FALSE;
2334 char_u *result;
2335
2336 rettv->v_type = VAR_STRING;
2337 if (argvars[1].v_type != VAR_UNKNOWN
2338 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002339 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002340 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002341 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002342
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002343 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002344 if (*s == '%' || *s == '#' || *s == '<')
2345 {
2346 ++emsg_off;
2347 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2348 --emsg_off;
2349 if (rettv->v_type == VAR_LIST)
2350 {
2351 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2352 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002353 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002354 }
2355 else
2356 rettv->vval.v_string = result;
2357 }
2358 else
2359 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002360 // When the optional second argument is non-zero, don't remove matches
2361 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002362 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002363 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 options |= WILD_KEEP_ALL;
2365 if (!error)
2366 {
2367 ExpandInit(&xpc);
2368 xpc.xp_context = EXPAND_FILES;
2369 if (p_wic)
2370 options += WILD_ICASE;
2371 if (rettv->v_type == VAR_STRING)
2372 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2373 options, WILD_ALL);
2374 else if (rettv_list_alloc(rettv) != FAIL)
2375 {
2376 int i;
2377
2378 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2379 for (i = 0; i < xpc.xp_numfiles; i++)
2380 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2381 ExpandCleanup(&xpc);
2382 }
2383 }
2384 else
2385 rettv->vval.v_string = NULL;
2386 }
2387}
2388
2389/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002390 * "expandcmd()" function
2391 * Expand all the special characters in a command string.
2392 */
2393 static void
2394f_expandcmd(typval_T *argvars, typval_T *rettv)
2395{
2396 exarg_T eap;
2397 char_u *cmdstr;
2398 char *errormsg = NULL;
2399
2400 rettv->v_type = VAR_STRING;
2401 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2402
2403 memset(&eap, 0, sizeof(eap));
2404 eap.cmd = cmdstr;
2405 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002406 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002407 eap.usefilter = FALSE;
2408 eap.nextcmd = NULL;
2409 eap.cmdidx = CMD_USER;
2410
2411 expand_filename(&eap, &cmdstr, &errormsg);
2412 if (errormsg != NULL && *errormsg != NUL)
2413 emsg(errormsg);
2414
2415 rettv->vval.v_string = cmdstr;
2416}
2417
2418/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419 * "feedkeys()" function
2420 */
2421 static void
2422f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2423{
2424 int remap = TRUE;
2425 int insert = FALSE;
2426 char_u *keys, *flags;
2427 char_u nbuf[NUMBUFLEN];
2428 int typed = FALSE;
2429 int execute = FALSE;
2430 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002431 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432 char_u *keys_esc;
2433
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002434 // This is not allowed in the sandbox. If the commands would still be
2435 // executed in the sandbox it would be OK, but it probably happens later,
2436 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002437 if (check_secure())
2438 return;
2439
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002440 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002441
2442 if (argvars[1].v_type != VAR_UNKNOWN)
2443 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002444 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002445 for ( ; *flags != NUL; ++flags)
2446 {
2447 switch (*flags)
2448 {
2449 case 'n': remap = FALSE; break;
2450 case 'm': remap = TRUE; break;
2451 case 't': typed = TRUE; break;
2452 case 'i': insert = TRUE; break;
2453 case 'x': execute = TRUE; break;
2454 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002455 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002456 }
2457 }
2458 }
2459
2460 if (*keys != NUL || execute)
2461 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002462 // Need to escape K_SPECIAL and CSI before putting the string in the
2463 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002464 keys_esc = vim_strsave_escape_csi(keys);
2465 if (keys_esc != NULL)
2466 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002467 if (lowlevel)
2468 {
2469#ifdef USE_INPUT_BUF
2470 add_to_input_buf(keys, (int)STRLEN(keys));
2471#else
2472 emsg(_("E980: lowlevel input not supported"));
2473#endif
2474 }
2475 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002476 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002477 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002478 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002479 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002480#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002481 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002482#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002483 )
2484 typebuf_was_filled = TRUE;
2485 }
2486 vim_free(keys_esc);
2487
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002488 if (execute)
2489 {
2490 int save_msg_scroll = msg_scroll;
2491
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002492 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002493 msg_scroll = FALSE;
2494
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002495 if (!dangerous)
2496 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002497 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002498 if (!dangerous)
2499 --ex_normal_busy;
2500
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501 msg_scroll |= save_msg_scroll;
2502 }
2503 }
2504 }
2505}
2506
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002507#ifdef FEAT_FLOAT
2508/*
2509 * "float2nr({float})" function
2510 */
2511 static void
2512f_float2nr(typval_T *argvars, typval_T *rettv)
2513{
2514 float_T f = 0.0;
2515
2516 if (get_float_arg(argvars, &f) == OK)
2517 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002518 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002519 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002520 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002521 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002522 else
2523 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002524 }
2525}
2526
2527/*
2528 * "floor({float})" function
2529 */
2530 static void
2531f_floor(typval_T *argvars, typval_T *rettv)
2532{
2533 float_T f = 0.0;
2534
2535 rettv->v_type = VAR_FLOAT;
2536 if (get_float_arg(argvars, &f) == OK)
2537 rettv->vval.v_float = floor(f);
2538 else
2539 rettv->vval.v_float = 0.0;
2540}
2541
2542/*
2543 * "fmod()" function
2544 */
2545 static void
2546f_fmod(typval_T *argvars, typval_T *rettv)
2547{
2548 float_T fx = 0.0, fy = 0.0;
2549
2550 rettv->v_type = VAR_FLOAT;
2551 if (get_float_arg(argvars, &fx) == OK
2552 && get_float_arg(&argvars[1], &fy) == OK)
2553 rettv->vval.v_float = fmod(fx, fy);
2554 else
2555 rettv->vval.v_float = 0.0;
2556}
2557#endif
2558
2559/*
2560 * "fnameescape({string})" function
2561 */
2562 static void
2563f_fnameescape(typval_T *argvars, typval_T *rettv)
2564{
2565 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002566 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002567 rettv->v_type = VAR_STRING;
2568}
2569
2570/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002571 * "foreground()" function
2572 */
2573 static void
2574f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2575{
2576#ifdef FEAT_GUI
2577 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002578 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002579 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002580 return;
2581 }
2582#endif
2583#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002584 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002585#endif
2586}
2587
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002588 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002589common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002590{
2591 char_u *s;
2592 char_u *name;
2593 int use_string = FALSE;
2594 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002595 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002596
2597 if (argvars[0].v_type == VAR_FUNC)
2598 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002599 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002600 s = argvars[0].vval.v_string;
2601 }
2602 else if (argvars[0].v_type == VAR_PARTIAL
2603 && argvars[0].vval.v_partial != NULL)
2604 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002605 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002606 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002607 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002608 }
2609 else
2610 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002611 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002612 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002613 use_string = TRUE;
2614 }
2615
Bram Moolenaar843b8842016-08-21 14:36:15 +02002616 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002617 {
2618 name = s;
2619 trans_name = trans_function_name(&name, FALSE,
2620 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2621 if (*name != NUL)
2622 s = NULL;
2623 }
2624
Bram Moolenaar843b8842016-08-21 14:36:15 +02002625 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2626 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002627 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002628 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002629 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002630 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002631 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002632 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002633 else
2634 {
2635 int dict_idx = 0;
2636 int arg_idx = 0;
2637 list_T *list = NULL;
2638
2639 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2640 {
2641 char sid_buf[25];
2642 int off = *s == 's' ? 2 : 5;
2643
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002644 // Expand s: and <SID> into <SNR>nr_, so that the function can
2645 // also be called from another script. Using trans_function_name()
2646 // would also work, but some plugins depend on the name being
2647 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002648 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002649 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002650 if (name != NULL)
2651 {
2652 STRCPY(name, sid_buf);
2653 STRCAT(name, s + off);
2654 }
2655 }
2656 else
2657 name = vim_strsave(s);
2658
2659 if (argvars[1].v_type != VAR_UNKNOWN)
2660 {
2661 if (argvars[2].v_type != VAR_UNKNOWN)
2662 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002663 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002664 arg_idx = 1;
2665 dict_idx = 2;
2666 }
2667 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002668 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002669 dict_idx = 1;
2670 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002671 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002672 arg_idx = 1;
2673 if (dict_idx > 0)
2674 {
2675 if (argvars[dict_idx].v_type != VAR_DICT)
2676 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002677 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002678 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002679 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002680 }
2681 if (argvars[dict_idx].vval.v_dict == NULL)
2682 dict_idx = 0;
2683 }
2684 if (arg_idx > 0)
2685 {
2686 if (argvars[arg_idx].v_type != VAR_LIST)
2687 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002688 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002689 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002690 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 }
2692 list = argvars[arg_idx].vval.v_list;
2693 if (list == NULL || list->lv_len == 0)
2694 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002695 else if (list->lv_len > MAX_FUNC_ARGS)
2696 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002697 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002698 vim_free(name);
2699 goto theend;
2700 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002701 }
2702 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002703 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002705 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002707 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002708 if (pt == NULL)
2709 vim_free(name);
2710 else
2711 {
2712 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2713 {
2714 listitem_T *li;
2715 int i = 0;
2716 int arg_len = 0;
2717 int lv_len = 0;
2718
2719 if (arg_pt != NULL)
2720 arg_len = arg_pt->pt_argc;
2721 if (list != NULL)
2722 lv_len = list->lv_len;
2723 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002724 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002725 if (pt->pt_argv == NULL)
2726 {
2727 vim_free(pt);
2728 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002729 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002730 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002731 for (i = 0; i < arg_len; i++)
2732 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2733 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002734 {
2735 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002736 for (li = list->lv_first; li != NULL;
2737 li = li->li_next)
2738 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002739 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002740 }
2741
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002742 // For "function(dict.func, [], dict)" and "func" is a partial
2743 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002744 if (dict_idx > 0)
2745 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002746 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002747 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2748 ++pt->pt_dict->dv_refcount;
2749 }
2750 else if (arg_pt != NULL)
2751 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002752 // If the dict was bound automatically the result is also
2753 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002754 pt->pt_dict = arg_pt->pt_dict;
2755 pt->pt_auto = arg_pt->pt_auto;
2756 if (pt->pt_dict != NULL)
2757 ++pt->pt_dict->dv_refcount;
2758 }
2759
2760 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002761 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2762 {
2763 pt->pt_func = arg_pt->pt_func;
2764 func_ptr_ref(pt->pt_func);
2765 vim_free(name);
2766 }
2767 else if (is_funcref)
2768 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002769 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002770 func_ptr_ref(pt->pt_func);
2771 vim_free(name);
2772 }
2773 else
2774 {
2775 pt->pt_name = name;
2776 func_ref(name);
2777 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 }
2779 rettv->v_type = VAR_PARTIAL;
2780 rettv->vval.v_partial = pt;
2781 }
2782 else
2783 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002784 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002785 rettv->v_type = VAR_FUNC;
2786 rettv->vval.v_string = name;
2787 func_ref(name);
2788 }
2789 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002790theend:
2791 vim_free(trans_name);
2792}
2793
2794/*
2795 * "funcref()" function
2796 */
2797 static void
2798f_funcref(typval_T *argvars, typval_T *rettv)
2799{
2800 common_function(argvars, rettv, TRUE);
2801}
2802
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002803 static type_T *
2804ret_f_function(int argcount, type_T **argtypes UNUSED)
2805{
2806 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2807 return &t_func_any;
2808 return &t_partial_void;
2809}
2810
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002811/*
2812 * "function()" function
2813 */
2814 static void
2815f_function(typval_T *argvars, typval_T *rettv)
2816{
2817 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002818}
2819
2820/*
2821 * "garbagecollect()" function
2822 */
2823 static void
2824f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2825{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002826 // This is postponed until we are back at the toplevel, because we may be
2827 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002828 want_garbage_collect = TRUE;
2829
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002830 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002831 garbage_collect_at_exit = TRUE;
2832}
2833
2834/*
2835 * "get()" function
2836 */
2837 static void
2838f_get(typval_T *argvars, typval_T *rettv)
2839{
2840 listitem_T *li;
2841 list_T *l;
2842 dictitem_T *di;
2843 dict_T *d;
2844 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002845 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002846
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002847 if (argvars[0].v_type == VAR_BLOB)
2848 {
2849 int error = FALSE;
2850 int idx = tv_get_number_chk(&argvars[1], &error);
2851
2852 if (!error)
2853 {
2854 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002855 if (idx < 0)
2856 idx = blob_len(argvars[0].vval.v_blob) + idx;
2857 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2858 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002859 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002860 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002861 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002862 tv = rettv;
2863 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002864 }
2865 }
2866 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002867 {
2868 if ((l = argvars[0].vval.v_list) != NULL)
2869 {
2870 int error = FALSE;
2871
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002872 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002873 if (!error && li != NULL)
2874 tv = &li->li_tv;
2875 }
2876 }
2877 else if (argvars[0].v_type == VAR_DICT)
2878 {
2879 if ((d = argvars[0].vval.v_dict) != NULL)
2880 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002881 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002882 if (di != NULL)
2883 tv = &di->di_tv;
2884 }
2885 }
2886 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2887 {
2888 partial_T *pt;
2889 partial_T fref_pt;
2890
2891 if (argvars[0].v_type == VAR_PARTIAL)
2892 pt = argvars[0].vval.v_partial;
2893 else
2894 {
2895 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2896 fref_pt.pt_name = argvars[0].vval.v_string;
2897 pt = &fref_pt;
2898 }
2899
2900 if (pt != NULL)
2901 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002902 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002903 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002904
2905 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2906 {
2907 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002908 n = partial_name(pt);
2909 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002910 rettv->vval.v_string = NULL;
2911 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002912 {
2913 rettv->vval.v_string = vim_strsave(n);
2914 if (rettv->v_type == VAR_FUNC)
2915 func_ref(rettv->vval.v_string);
2916 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002917 }
2918 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002919 {
2920 what_is_dict = TRUE;
2921 if (pt->pt_dict != NULL)
2922 rettv_dict_set(rettv, pt->pt_dict);
2923 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002924 else if (STRCMP(what, "args") == 0)
2925 {
2926 rettv->v_type = VAR_LIST;
2927 if (rettv_list_alloc(rettv) == OK)
2928 {
2929 int i;
2930
2931 for (i = 0; i < pt->pt_argc; ++i)
2932 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2933 }
2934 }
2935 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002936 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002937
2938 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2939 // third argument
2940 if (!what_is_dict)
2941 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002942 }
2943 }
2944 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002945 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002946
2947 if (tv == NULL)
2948 {
2949 if (argvars[2].v_type != VAR_UNKNOWN)
2950 copy_tv(&argvars[2], rettv);
2951 }
2952 else
2953 copy_tv(tv, rettv);
2954}
2955
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002956/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002957 * "getchangelist()" function
2958 */
2959 static void
2960f_getchangelist(typval_T *argvars, typval_T *rettv)
2961{
2962#ifdef FEAT_JUMPLIST
2963 buf_T *buf;
2964 int i;
2965 list_T *l;
2966 dict_T *d;
2967#endif
2968
2969 if (rettv_list_alloc(rettv) != OK)
2970 return;
2971
2972#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002973 if (argvars[0].v_type == VAR_UNKNOWN)
2974 buf = curbuf;
2975 else
2976 {
2977 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2978 ++emsg_off;
2979 buf = tv_get_buf(&argvars[0], FALSE);
2980 --emsg_off;
2981 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002982 if (buf == NULL)
2983 return;
2984
2985 l = list_alloc();
2986 if (l == NULL)
2987 return;
2988
2989 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2990 return;
2991 /*
2992 * The current window change list index tracks only the position in the
2993 * current buffer change list. For other buffers, use the change list
2994 * length as the current index.
2995 */
2996 list_append_number(rettv->vval.v_list,
2997 (varnumber_T)((buf == curwin->w_buffer)
2998 ? curwin->w_changelistidx : buf->b_changelistlen));
2999
3000 for (i = 0; i < buf->b_changelistlen; ++i)
3001 {
3002 if (buf->b_changelist[i].lnum == 0)
3003 continue;
3004 if ((d = dict_alloc()) == NULL)
3005 return;
3006 if (list_append_dict(l, d) == FAIL)
3007 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003008 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3009 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003010 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003011 }
3012#endif
3013}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003014
3015/*
3016 * "getcharsearch()" function
3017 */
3018 static void
3019f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3020{
3021 if (rettv_dict_alloc(rettv) != FAIL)
3022 {
3023 dict_T *dict = rettv->vval.v_dict;
3024
Bram Moolenaare0be1672018-07-08 16:50:37 +02003025 dict_add_string(dict, "char", last_csearch());
3026 dict_add_number(dict, "forward", last_csearch_forward());
3027 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003028 }
3029}
3030
3031/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003032 * "getenv()" function
3033 */
3034 static void
3035f_getenv(typval_T *argvars, typval_T *rettv)
3036{
3037 int mustfree = FALSE;
3038 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3039
3040 if (p == NULL)
3041 {
3042 rettv->v_type = VAR_SPECIAL;
3043 rettv->vval.v_number = VVAL_NULL;
3044 return;
3045 }
3046 if (!mustfree)
3047 p = vim_strsave(p);
3048 rettv->vval.v_string = p;
3049 rettv->v_type = VAR_STRING;
3050}
3051
3052/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003053 * "getfontname()" function
3054 */
3055 static void
3056f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3057{
3058 rettv->v_type = VAR_STRING;
3059 rettv->vval.v_string = NULL;
3060#ifdef FEAT_GUI
3061 if (gui.in_use)
3062 {
3063 GuiFont font;
3064 char_u *name = NULL;
3065
3066 if (argvars[0].v_type == VAR_UNKNOWN)
3067 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003068 // Get the "Normal" font. Either the name saved by
3069 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003070 font = gui.norm_font;
3071 name = hl_get_font_name();
3072 }
3073 else
3074 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003075 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003076 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 return;
3078 font = gui_mch_get_font(name, FALSE);
3079 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003080 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003081 }
3082 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3083 if (argvars[0].v_type != VAR_UNKNOWN)
3084 gui_mch_free_font(font);
3085 }
3086#endif
3087}
3088
3089/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003090 * "getjumplist()" function
3091 */
3092 static void
3093f_getjumplist(typval_T *argvars, typval_T *rettv)
3094{
3095#ifdef FEAT_JUMPLIST
3096 win_T *wp;
3097 int i;
3098 list_T *l;
3099 dict_T *d;
3100#endif
3101
3102 if (rettv_list_alloc(rettv) != OK)
3103 return;
3104
3105#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003106 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003107 if (wp == NULL)
3108 return;
3109
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003110 cleanup_jumplist(wp, TRUE);
3111
Bram Moolenaar4f505882018-02-10 21:06:32 +01003112 l = list_alloc();
3113 if (l == NULL)
3114 return;
3115
3116 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3117 return;
3118 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3119
3120 for (i = 0; i < wp->w_jumplistlen; ++i)
3121 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003122 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3123 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003124 if ((d = dict_alloc()) == NULL)
3125 return;
3126 if (list_append_dict(l, d) == FAIL)
3127 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003128 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3129 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003130 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003131 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003132 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003133 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003134 }
3135#endif
3136}
3137
3138/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003139 * "getpid()" function
3140 */
3141 static void
3142f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3143{
3144 rettv->vval.v_number = mch_get_pid();
3145}
3146
3147 static void
3148getpos_both(
3149 typval_T *argvars,
3150 typval_T *rettv,
3151 int getcurpos)
3152{
3153 pos_T *fp;
3154 list_T *l;
3155 int fnum = -1;
3156
3157 if (rettv_list_alloc(rettv) == OK)
3158 {
3159 l = rettv->vval.v_list;
3160 if (getcurpos)
3161 fp = &curwin->w_cursor;
3162 else
3163 fp = var2fpos(&argvars[0], TRUE, &fnum);
3164 if (fnum != -1)
3165 list_append_number(l, (varnumber_T)fnum);
3166 else
3167 list_append_number(l, (varnumber_T)0);
3168 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3169 : (varnumber_T)0);
3170 list_append_number(l, (fp != NULL)
3171 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3172 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003173 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003174 (varnumber_T)0);
3175 if (getcurpos)
3176 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003177 int save_set_curswant = curwin->w_set_curswant;
3178 colnr_T save_curswant = curwin->w_curswant;
3179 colnr_T save_virtcol = curwin->w_virtcol;
3180
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003181 update_curswant();
3182 list_append_number(l, curwin->w_curswant == MAXCOL ?
3183 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003184
3185 // Do not change "curswant", as it is unexpected that a get
3186 // function has a side effect.
3187 if (save_set_curswant)
3188 {
3189 curwin->w_set_curswant = save_set_curswant;
3190 curwin->w_curswant = save_curswant;
3191 curwin->w_virtcol = save_virtcol;
3192 curwin->w_valid &= ~VALID_VIRTCOL;
3193 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003194 }
3195 }
3196 else
3197 rettv->vval.v_number = FALSE;
3198}
3199
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003200/*
3201 * "getcurpos()" function
3202 */
3203 static void
3204f_getcurpos(typval_T *argvars, typval_T *rettv)
3205{
3206 getpos_both(argvars, rettv, TRUE);
3207}
3208
3209/*
3210 * "getpos(string)" function
3211 */
3212 static void
3213f_getpos(typval_T *argvars, typval_T *rettv)
3214{
3215 getpos_both(argvars, rettv, FALSE);
3216}
3217
3218/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003219 * "getreg()" function
3220 */
3221 static void
3222f_getreg(typval_T *argvars, typval_T *rettv)
3223{
3224 char_u *strregname;
3225 int regname;
3226 int arg2 = FALSE;
3227 int return_list = FALSE;
3228 int error = FALSE;
3229
3230 if (argvars[0].v_type != VAR_UNKNOWN)
3231 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003232 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003233 error = strregname == NULL;
3234 if (argvars[1].v_type != VAR_UNKNOWN)
3235 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003236 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003237 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003238 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003239 }
3240 }
3241 else
3242 strregname = get_vim_var_str(VV_REG);
3243
3244 if (error)
3245 return;
3246
3247 regname = (strregname == NULL ? '"' : *strregname);
3248 if (regname == 0)
3249 regname = '"';
3250
3251 if (return_list)
3252 {
3253 rettv->v_type = VAR_LIST;
3254 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3255 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3256 if (rettv->vval.v_list == NULL)
3257 (void)rettv_list_alloc(rettv);
3258 else
3259 ++rettv->vval.v_list->lv_refcount;
3260 }
3261 else
3262 {
3263 rettv->v_type = VAR_STRING;
3264 rettv->vval.v_string = get_reg_contents(regname,
3265 arg2 ? GREG_EXPR_SRC : 0);
3266 }
3267}
3268
3269/*
3270 * "getregtype()" function
3271 */
3272 static void
3273f_getregtype(typval_T *argvars, typval_T *rettv)
3274{
3275 char_u *strregname;
3276 int regname;
3277 char_u buf[NUMBUFLEN + 2];
3278 long reglen = 0;
3279
3280 if (argvars[0].v_type != VAR_UNKNOWN)
3281 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003282 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003283 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003284 {
3285 rettv->v_type = VAR_STRING;
3286 rettv->vval.v_string = NULL;
3287 return;
3288 }
3289 }
3290 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003291 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292 strregname = get_vim_var_str(VV_REG);
3293
3294 regname = (strregname == NULL ? '"' : *strregname);
3295 if (regname == 0)
3296 regname = '"';
3297
3298 buf[0] = NUL;
3299 buf[1] = NUL;
3300 switch (get_reg_type(regname, &reglen))
3301 {
3302 case MLINE: buf[0] = 'V'; break;
3303 case MCHAR: buf[0] = 'v'; break;
3304 case MBLOCK:
3305 buf[0] = Ctrl_V;
3306 sprintf((char *)buf + 1, "%ld", reglen + 1);
3307 break;
3308 }
3309 rettv->v_type = VAR_STRING;
3310 rettv->vval.v_string = vim_strsave(buf);
3311}
3312
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003313/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003314 * "gettagstack()" function
3315 */
3316 static void
3317f_gettagstack(typval_T *argvars, typval_T *rettv)
3318{
3319 win_T *wp = curwin; // default is current window
3320
3321 if (rettv_dict_alloc(rettv) != OK)
3322 return;
3323
3324 if (argvars[0].v_type != VAR_UNKNOWN)
3325 {
3326 wp = find_win_by_nr_or_id(&argvars[0]);
3327 if (wp == NULL)
3328 return;
3329 }
3330
3331 get_tagstack(wp, rettv->vval.v_dict);
3332}
3333
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003334// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003335#include "version.h"
3336
3337/*
3338 * "has()" function
3339 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003340 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003341f_has(typval_T *argvars, typval_T *rettv)
3342{
3343 int i;
3344 char_u *name;
3345 int n = FALSE;
3346 static char *(has_list[]) =
3347 {
3348#ifdef AMIGA
3349 "amiga",
3350# ifdef FEAT_ARP
3351 "arp",
3352# endif
3353#endif
3354#ifdef __BEOS__
3355 "beos",
3356#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003357#ifdef __HAIKU__
3358 "haiku",
3359#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003360#if defined(BSD) && !defined(MACOS_X)
3361 "bsd",
3362#endif
3363#ifdef hpux
3364 "hpux",
3365#endif
3366#ifdef __linux__
3367 "linux",
3368#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003369#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003370 "mac", // Mac OS X (and, once, Mac OS Classic)
3371 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003372# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003373 "macunix", // Mac OS X, with the darwin feature
3374 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003375# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376#endif
3377#ifdef __QNX__
3378 "qnx",
3379#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003380#ifdef SUN_SYSTEM
3381 "sun",
3382#else
3383 "moon",
3384#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003385#ifdef UNIX
3386 "unix",
3387#endif
3388#ifdef VMS
3389 "vms",
3390#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003391#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 "win32",
3393#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003394#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 "win32unix",
3396#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003397#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003398 "win64",
3399#endif
3400#ifdef EBCDIC
3401 "ebcdic",
3402#endif
3403#ifndef CASE_INSENSITIVE_FILENAME
3404 "fname_case",
3405#endif
3406#ifdef HAVE_ACL
3407 "acl",
3408#endif
3409#ifdef FEAT_ARABIC
3410 "arabic",
3411#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003412 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003413#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003414 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003415#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003416#ifdef FEAT_AUTOSERVERNAME
3417 "autoservername",
3418#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003419#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003420 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003421# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422 "balloon_multiline",
3423# endif
3424#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003425#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003426 "balloon_eval_term",
3427#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3429 "builtin_terms",
3430# ifdef ALL_BUILTIN_TCAPS
3431 "all_builtin_terms",
3432# endif
3433#endif
3434#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003435 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436 || defined(FEAT_GUI_MOTIF))
3437 "browsefilter",
3438#endif
3439#ifdef FEAT_BYTEOFF
3440 "byte_offset",
3441#endif
3442#ifdef FEAT_JOB_CHANNEL
3443 "channel",
3444#endif
3445#ifdef FEAT_CINDENT
3446 "cindent",
3447#endif
3448#ifdef FEAT_CLIENTSERVER
3449 "clientserver",
3450#endif
3451#ifdef FEAT_CLIPBOARD
3452 "clipboard",
3453#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003454 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003455 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003456 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457#ifdef FEAT_CONCEAL
3458 "conceal",
3459#endif
3460#ifdef FEAT_CRYPT
3461 "cryptv",
3462 "crypt-blowfish",
3463 "crypt-blowfish2",
3464#endif
3465#ifdef FEAT_CSCOPE
3466 "cscope",
3467#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003469#ifdef CURSOR_SHAPE
3470 "cursorshape",
3471#endif
3472#ifdef DEBUG
3473 "debug",
3474#endif
3475#ifdef FEAT_CON_DIALOG
3476 "dialog_con",
3477#endif
3478#ifdef FEAT_GUI_DIALOG
3479 "dialog_gui",
3480#endif
3481#ifdef FEAT_DIFF
3482 "diff",
3483#endif
3484#ifdef FEAT_DIGRAPHS
3485 "digraphs",
3486#endif
3487#ifdef FEAT_DIRECTX
3488 "directx",
3489#endif
3490#ifdef FEAT_DND
3491 "dnd",
3492#endif
3493#ifdef FEAT_EMACS_TAGS
3494 "emacs_tags",
3495#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003496 "eval", // always present, of course!
3497 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003498#ifdef FEAT_SEARCH_EXTRA
3499 "extra_search",
3500#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003501#ifdef FEAT_SEARCHPATH
3502 "file_in_path",
3503#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003504#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 "filterpipe",
3506#endif
3507#ifdef FEAT_FIND_ID
3508 "find_in_path",
3509#endif
3510#ifdef FEAT_FLOAT
3511 "float",
3512#endif
3513#ifdef FEAT_FOLDING
3514 "folding",
3515#endif
3516#ifdef FEAT_FOOTER
3517 "footer",
3518#endif
3519#if !defined(USE_SYSTEM) && defined(UNIX)
3520 "fork",
3521#endif
3522#ifdef FEAT_GETTEXT
3523 "gettext",
3524#endif
3525#ifdef FEAT_GUI
3526 "gui",
3527#endif
3528#ifdef FEAT_GUI_ATHENA
3529# ifdef FEAT_GUI_NEXTAW
3530 "gui_neXtaw",
3531# else
3532 "gui_athena",
3533# endif
3534#endif
3535#ifdef FEAT_GUI_GTK
3536 "gui_gtk",
3537# ifdef USE_GTK3
3538 "gui_gtk3",
3539# else
3540 "gui_gtk2",
3541# endif
3542#endif
3543#ifdef FEAT_GUI_GNOME
3544 "gui_gnome",
3545#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003546#ifdef FEAT_GUI_HAIKU
3547 "gui_haiku",
3548#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003549#ifdef FEAT_GUI_MAC
3550 "gui_mac",
3551#endif
3552#ifdef FEAT_GUI_MOTIF
3553 "gui_motif",
3554#endif
3555#ifdef FEAT_GUI_PHOTON
3556 "gui_photon",
3557#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003558#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003559 "gui_win32",
3560#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3562 "iconv",
3563#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003564 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565#ifdef FEAT_JOB_CHANNEL
3566 "job",
3567#endif
3568#ifdef FEAT_JUMPLIST
3569 "jumplist",
3570#endif
3571#ifdef FEAT_KEYMAP
3572 "keymap",
3573#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003574 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003575#ifdef FEAT_LANGMAP
3576 "langmap",
3577#endif
3578#ifdef FEAT_LIBCALL
3579 "libcall",
3580#endif
3581#ifdef FEAT_LINEBREAK
3582 "linebreak",
3583#endif
3584#ifdef FEAT_LISP
3585 "lispindent",
3586#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003587 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003588 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589#ifdef FEAT_LUA
3590# ifndef DYNAMIC_LUA
3591 "lua",
3592# endif
3593#endif
3594#ifdef FEAT_MENU
3595 "menu",
3596#endif
3597#ifdef FEAT_SESSION
3598 "mksession",
3599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003601 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602#ifdef FEAT_MOUSESHAPE
3603 "mouseshape",
3604#endif
3605#if defined(UNIX) || defined(VMS)
3606# ifdef FEAT_MOUSE_DEC
3607 "mouse_dec",
3608# endif
3609# ifdef FEAT_MOUSE_GPM
3610 "mouse_gpm",
3611# endif
3612# ifdef FEAT_MOUSE_JSB
3613 "mouse_jsbterm",
3614# endif
3615# ifdef FEAT_MOUSE_NET
3616 "mouse_netterm",
3617# endif
3618# ifdef FEAT_MOUSE_PTERM
3619 "mouse_pterm",
3620# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003621# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003622 "mouse_sgr",
3623# endif
3624# ifdef FEAT_SYSMOUSE
3625 "mouse_sysmouse",
3626# endif
3627# ifdef FEAT_MOUSE_URXVT
3628 "mouse_urxvt",
3629# endif
3630# ifdef FEAT_MOUSE_XTERM
3631 "mouse_xterm",
3632# endif
3633#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635#ifdef FEAT_MBYTE_IME
3636 "multi_byte_ime",
3637#endif
3638#ifdef FEAT_MULTI_LANG
3639 "multi_lang",
3640#endif
3641#ifdef FEAT_MZSCHEME
3642#ifndef DYNAMIC_MZSCHEME
3643 "mzscheme",
3644#endif
3645#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003646 "num64",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647#ifdef FEAT_OLE
3648 "ole",
3649#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003650#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003652#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003653#ifdef FEAT_PATH_EXTRA
3654 "path_extra",
3655#endif
3656#ifdef FEAT_PERL
3657#ifndef DYNAMIC_PERL
3658 "perl",
3659#endif
3660#endif
3661#ifdef FEAT_PERSISTENT_UNDO
3662 "persistent_undo",
3663#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003664#if defined(FEAT_PYTHON)
3665 "python_compiled",
3666# if defined(DYNAMIC_PYTHON)
3667 "python_dynamic",
3668# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003669 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003670 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003671# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003672#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003673#if defined(FEAT_PYTHON3)
3674 "python3_compiled",
3675# if defined(DYNAMIC_PYTHON3)
3676 "python3_dynamic",
3677# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003678 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003679 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003680# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003682#ifdef FEAT_PROP_POPUP
3683 "popupwin",
3684#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685#ifdef FEAT_POSTSCRIPT
3686 "postscript",
3687#endif
3688#ifdef FEAT_PRINTER
3689 "printer",
3690#endif
3691#ifdef FEAT_PROFILE
3692 "profile",
3693#endif
3694#ifdef FEAT_RELTIME
3695 "reltime",
3696#endif
3697#ifdef FEAT_QUICKFIX
3698 "quickfix",
3699#endif
3700#ifdef FEAT_RIGHTLEFT
3701 "rightleft",
3702#endif
3703#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3704 "ruby",
3705#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003706 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707#ifdef FEAT_CMDL_INFO
3708 "showcmd",
3709 "cmdline_info",
3710#endif
3711#ifdef FEAT_SIGNS
3712 "signs",
3713#endif
3714#ifdef FEAT_SMARTINDENT
3715 "smartindent",
3716#endif
3717#ifdef STARTUPTIME
3718 "startuptime",
3719#endif
3720#ifdef FEAT_STL_OPT
3721 "statusline",
3722#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003723#ifdef FEAT_NETBEANS_INTG
3724 "netbeans_intg",
3725#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003726#ifdef FEAT_SOUND
3727 "sound",
3728#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003729#ifdef FEAT_SPELL
3730 "spell",
3731#endif
3732#ifdef FEAT_SYN_HL
3733 "syntax",
3734#endif
3735#if defined(USE_SYSTEM) || !defined(UNIX)
3736 "system",
3737#endif
3738#ifdef FEAT_TAG_BINS
3739 "tag_binary",
3740#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003741#ifdef FEAT_TCL
3742# ifndef DYNAMIC_TCL
3743 "tcl",
3744# endif
3745#endif
3746#ifdef FEAT_TERMGUICOLORS
3747 "termguicolors",
3748#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003749#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003750 "terminal",
3751#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003752#ifdef TERMINFO
3753 "terminfo",
3754#endif
3755#ifdef FEAT_TERMRESPONSE
3756 "termresponse",
3757#endif
3758#ifdef FEAT_TEXTOBJ
3759 "textobjects",
3760#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003761#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003762 "textprop",
3763#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003764#ifdef HAVE_TGETENT
3765 "tgetent",
3766#endif
3767#ifdef FEAT_TIMERS
3768 "timers",
3769#endif
3770#ifdef FEAT_TITLE
3771 "title",
3772#endif
3773#ifdef FEAT_TOOLBAR
3774 "toolbar",
3775#endif
3776#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3777 "unnamedplus",
3778#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003779 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003780 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003781#ifdef FEAT_VARTABS
3782 "vartabs",
3783#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003784 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003785#ifdef FEAT_VIMINFO
3786 "viminfo",
3787#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003788 "vimscript-1",
3789 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003790 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003791 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003792 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003793 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003794 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003795 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003796#ifdef FEAT_VTP
3797 "vtp",
3798#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003799#ifdef FEAT_WILDIGN
3800 "wildignore",
3801#endif
3802#ifdef FEAT_WILDMENU
3803 "wildmenu",
3804#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003805 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003806#ifdef FEAT_WAK
3807 "winaltkeys",
3808#endif
3809#ifdef FEAT_WRITEBACKUP
3810 "writebackup",
3811#endif
3812#ifdef FEAT_XIM
3813 "xim",
3814#endif
3815#ifdef FEAT_XFONTSET
3816 "xfontset",
3817#endif
3818#ifdef FEAT_XPM_W32
3819 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003820 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003821#else
3822# if defined(HAVE_XPM)
3823 "xpm",
3824# endif
3825#endif
3826#ifdef USE_XSMP
3827 "xsmp",
3828#endif
3829#ifdef USE_XSMP_INTERACT
3830 "xsmp_interact",
3831#endif
3832#ifdef FEAT_XCLIPBOARD
3833 "xterm_clipboard",
3834#endif
3835#ifdef FEAT_XTERM_SAVE
3836 "xterm_save",
3837#endif
3838#if defined(UNIX) && defined(FEAT_X11)
3839 "X11",
3840#endif
3841 NULL
3842 };
3843
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003844 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003845 for (i = 0; has_list[i] != NULL; ++i)
3846 if (STRICMP(name, has_list[i]) == 0)
3847 {
3848 n = TRUE;
3849 break;
3850 }
3851
3852 if (n == FALSE)
3853 {
3854 if (STRNICMP(name, "patch", 5) == 0)
3855 {
3856 if (name[5] == '-'
3857 && STRLEN(name) >= 11
3858 && vim_isdigit(name[6])
3859 && vim_isdigit(name[8])
3860 && vim_isdigit(name[10]))
3861 {
3862 int major = atoi((char *)name + 6);
3863 int minor = atoi((char *)name + 8);
3864
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003865 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003866 n = (major < VIM_VERSION_MAJOR
3867 || (major == VIM_VERSION_MAJOR
3868 && (minor < VIM_VERSION_MINOR
3869 || (minor == VIM_VERSION_MINOR
3870 && has_patch(atoi((char *)name + 10))))));
3871 }
3872 else
3873 n = has_patch(atoi((char *)name + 5));
3874 }
3875 else if (STRICMP(name, "vim_starting") == 0)
3876 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003877 else if (STRICMP(name, "ttyin") == 0)
3878 n = mch_input_isatty();
3879 else if (STRICMP(name, "ttyout") == 0)
3880 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003881 else if (STRICMP(name, "multi_byte_encoding") == 0)
3882 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003883#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003884 else if (STRICMP(name, "balloon_multiline") == 0)
3885 n = multiline_balloon_available();
3886#endif
3887#ifdef DYNAMIC_TCL
3888 else if (STRICMP(name, "tcl") == 0)
3889 n = tcl_enabled(FALSE);
3890#endif
3891#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3892 else if (STRICMP(name, "iconv") == 0)
3893 n = iconv_enabled(FALSE);
3894#endif
3895#ifdef DYNAMIC_LUA
3896 else if (STRICMP(name, "lua") == 0)
3897 n = lua_enabled(FALSE);
3898#endif
3899#ifdef DYNAMIC_MZSCHEME
3900 else if (STRICMP(name, "mzscheme") == 0)
3901 n = mzscheme_enabled(FALSE);
3902#endif
3903#ifdef DYNAMIC_RUBY
3904 else if (STRICMP(name, "ruby") == 0)
3905 n = ruby_enabled(FALSE);
3906#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003907#ifdef DYNAMIC_PYTHON
3908 else if (STRICMP(name, "python") == 0)
3909 n = python_enabled(FALSE);
3910#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003911#ifdef DYNAMIC_PYTHON3
3912 else if (STRICMP(name, "python3") == 0)
3913 n = python3_enabled(FALSE);
3914#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003915#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3916 else if (STRICMP(name, "pythonx") == 0)
3917 {
3918# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3919 if (p_pyx == 0)
3920 n = python3_enabled(FALSE) || python_enabled(FALSE);
3921 else if (p_pyx == 3)
3922 n = python3_enabled(FALSE);
3923 else if (p_pyx == 2)
3924 n = python_enabled(FALSE);
3925# elif defined(DYNAMIC_PYTHON)
3926 n = python_enabled(FALSE);
3927# elif defined(DYNAMIC_PYTHON3)
3928 n = python3_enabled(FALSE);
3929# endif
3930 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931#endif
3932#ifdef DYNAMIC_PERL
3933 else if (STRICMP(name, "perl") == 0)
3934 n = perl_enabled(FALSE);
3935#endif
3936#ifdef FEAT_GUI
3937 else if (STRICMP(name, "gui_running") == 0)
3938 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003939# ifdef FEAT_BROWSE
3940 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003941 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942# endif
3943#endif
3944#ifdef FEAT_SYN_HL
3945 else if (STRICMP(name, "syntax_items") == 0)
3946 n = syntax_present(curwin);
3947#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003948#ifdef FEAT_VTP
3949 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003950 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003951#endif
3952#ifdef FEAT_NETBEANS_INTG
3953 else if (STRICMP(name, "netbeans_enabled") == 0)
3954 n = netbeans_active();
3955#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003956#ifdef FEAT_MOUSE_GPM
3957 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3958 n = gpm_enabled();
3959#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003960#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003961 else if (STRICMP(name, "terminal") == 0)
3962 n = terminal_enabled();
3963#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003964#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003965 else if (STRICMP(name, "conpty") == 0)
3966 n = use_conpty();
3967#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003968#ifdef FEAT_CLIPBOARD
3969 else if (STRICMP(name, "clipboard_working") == 0)
3970 n = clip_star.available;
3971#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003972#ifdef VIMDLL
3973 else if (STRICMP(name, "filterpipe") == 0)
3974 n = gui.in_use || gui.starting;
3975#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003976 }
3977
3978 rettv->vval.v_number = n;
3979}
3980
3981/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003982 * "haslocaldir()" function
3983 */
3984 static void
3985f_haslocaldir(typval_T *argvars, typval_T *rettv)
3986{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003987 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003988 win_T *wp = NULL;
3989
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003990 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3991
3992 // Check for window-local and tab-local directories
3993 if (wp != NULL && wp->w_localdir != NULL)
3994 rettv->vval.v_number = 1;
3995 else if (tp != NULL && tp->tp_localdir != NULL)
3996 rettv->vval.v_number = 2;
3997 else
3998 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003999}
4000
4001/*
4002 * "hasmapto()" function
4003 */
4004 static void
4005f_hasmapto(typval_T *argvars, typval_T *rettv)
4006{
4007 char_u *name;
4008 char_u *mode;
4009 char_u buf[NUMBUFLEN];
4010 int abbr = FALSE;
4011
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004012 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 if (argvars[1].v_type == VAR_UNKNOWN)
4014 mode = (char_u *)"nvo";
4015 else
4016 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004017 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004018 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004019 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 }
4021
4022 if (map_to_exists(name, mode, abbr))
4023 rettv->vval.v_number = TRUE;
4024 else
4025 rettv->vval.v_number = FALSE;
4026}
4027
4028/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004029 * "highlightID(name)" function
4030 */
4031 static void
4032f_hlID(typval_T *argvars, typval_T *rettv)
4033{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004034 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004035}
4036
4037/*
4038 * "highlight_exists()" function
4039 */
4040 static void
4041f_hlexists(typval_T *argvars, typval_T *rettv)
4042{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004043 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044}
4045
4046/*
4047 * "hostname()" function
4048 */
4049 static void
4050f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4051{
4052 char_u hostname[256];
4053
4054 mch_get_host_name(hostname, 256);
4055 rettv->v_type = VAR_STRING;
4056 rettv->vval.v_string = vim_strsave(hostname);
4057}
4058
4059/*
4060 * iconv() function
4061 */
4062 static void
4063f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4064{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004065 char_u buf1[NUMBUFLEN];
4066 char_u buf2[NUMBUFLEN];
4067 char_u *from, *to, *str;
4068 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004069
4070 rettv->v_type = VAR_STRING;
4071 rettv->vval.v_string = NULL;
4072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004073 str = tv_get_string(&argvars[0]);
4074 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4075 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004076 vimconv.vc_type = CONV_NONE;
4077 convert_setup(&vimconv, from, to);
4078
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004079 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004080 if (vimconv.vc_type == CONV_NONE)
4081 rettv->vval.v_string = vim_strsave(str);
4082 else
4083 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4084
4085 convert_setup(&vimconv, NULL, NULL);
4086 vim_free(from);
4087 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004088}
4089
4090/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091 * "index()" function
4092 */
4093 static void
4094f_index(typval_T *argvars, typval_T *rettv)
4095{
4096 list_T *l;
4097 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004098 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099 long idx = 0;
4100 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004101 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004102
4103 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004104 if (argvars[0].v_type == VAR_BLOB)
4105 {
4106 typval_T tv;
4107 int start = 0;
4108
4109 if (argvars[2].v_type != VAR_UNKNOWN)
4110 {
4111 start = tv_get_number_chk(&argvars[2], &error);
4112 if (error)
4113 return;
4114 }
4115 b = argvars[0].vval.v_blob;
4116 if (b == NULL)
4117 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004118 if (start < 0)
4119 {
4120 start = blob_len(b) + start;
4121 if (start < 0)
4122 start = 0;
4123 }
4124
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004125 for (idx = start; idx < blob_len(b); ++idx)
4126 {
4127 tv.v_type = VAR_NUMBER;
4128 tv.vval.v_number = blob_get(b, idx);
4129 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4130 {
4131 rettv->vval.v_number = idx;
4132 return;
4133 }
4134 }
4135 return;
4136 }
4137 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004138 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004139 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004140 return;
4141 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004142
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004143 l = argvars[0].vval.v_list;
4144 if (l != NULL)
4145 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004146 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004147 item = l->lv_first;
4148 if (argvars[2].v_type != VAR_UNKNOWN)
4149 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004150 // Start at specified item. Use the cached index that list_find()
4151 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004152 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004153 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004154 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004155 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156 if (error)
4157 item = NULL;
4158 }
4159
4160 for ( ; item != NULL; item = item->li_next, ++idx)
4161 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4162 {
4163 rettv->vval.v_number = idx;
4164 break;
4165 }
4166 }
4167}
4168
4169static int inputsecret_flag = 0;
4170
4171/*
4172 * "input()" function
4173 * Also handles inputsecret() when inputsecret is set.
4174 */
4175 static void
4176f_input(typval_T *argvars, typval_T *rettv)
4177{
4178 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4179}
4180
4181/*
4182 * "inputdialog()" function
4183 */
4184 static void
4185f_inputdialog(typval_T *argvars, typval_T *rettv)
4186{
4187#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004188 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004189 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4190 {
4191 char_u *message;
4192 char_u buf[NUMBUFLEN];
4193 char_u *defstr = (char_u *)"";
4194
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004195 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004196 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004197 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004198 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4199 else
4200 IObuff[0] = NUL;
4201 if (message != NULL && defstr != NULL
4202 && do_dialog(VIM_QUESTION, NULL, message,
4203 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4204 rettv->vval.v_string = vim_strsave(IObuff);
4205 else
4206 {
4207 if (message != NULL && defstr != NULL
4208 && argvars[1].v_type != VAR_UNKNOWN
4209 && argvars[2].v_type != VAR_UNKNOWN)
4210 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004211 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004212 else
4213 rettv->vval.v_string = NULL;
4214 }
4215 rettv->v_type = VAR_STRING;
4216 }
4217 else
4218#endif
4219 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4220}
4221
4222/*
4223 * "inputlist()" function
4224 */
4225 static void
4226f_inputlist(typval_T *argvars, typval_T *rettv)
4227{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004228 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004229 listitem_T *li;
4230 int selected;
4231 int mouse_used;
4232
4233#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004234 // While starting up, there is no place to enter text. When running tests
4235 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004236 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004237 return;
4238#endif
4239 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4240 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004241 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004242 return;
4243 }
4244
4245 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004246 msg_row = Rows - 1; // for when 'cmdheight' > 1
4247 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004248 msg_scroll = TRUE;
4249 msg_clr_eos();
4250
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004251 l = argvars[0].vval.v_list;
4252 range_list_materialize(l);
4253 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004254 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004255 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004256 msg_putchar('\n');
4257 }
4258
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004259 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004260 selected = prompt_for_number(&mouse_used);
4261 if (mouse_used)
4262 selected -= lines_left;
4263
4264 rettv->vval.v_number = selected;
4265}
4266
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004267static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4268
4269/*
4270 * "inputrestore()" function
4271 */
4272 static void
4273f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4274{
4275 if (ga_userinput.ga_len > 0)
4276 {
4277 --ga_userinput.ga_len;
4278 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4279 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004280 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004281 }
4282 else if (p_verbose > 1)
4283 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004284 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004285 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 }
4287}
4288
4289/*
4290 * "inputsave()" function
4291 */
4292 static void
4293f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4294{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004295 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296 if (ga_grow(&ga_userinput, 1) == OK)
4297 {
4298 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4299 + ga_userinput.ga_len);
4300 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004301 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004302 }
4303 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004304 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004305}
4306
4307/*
4308 * "inputsecret()" function
4309 */
4310 static void
4311f_inputsecret(typval_T *argvars, typval_T *rettv)
4312{
4313 ++cmdline_star;
4314 ++inputsecret_flag;
4315 f_input(argvars, rettv);
4316 --cmdline_star;
4317 --inputsecret_flag;
4318}
4319
4320/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004321 * "interrupt()" function
4322 */
4323 static void
4324f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4325{
4326 got_int = TRUE;
4327}
4328
4329/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004330 * "invert(expr)" function
4331 */
4332 static void
4333f_invert(typval_T *argvars, typval_T *rettv)
4334{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004335 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004336}
4337
4338/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004339 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4340 * or it refers to a List or Dictionary that is locked.
4341 */
4342 static int
4343tv_islocked(typval_T *tv)
4344{
4345 return (tv->v_lock & VAR_LOCKED)
4346 || (tv->v_type == VAR_LIST
4347 && tv->vval.v_list != NULL
4348 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4349 || (tv->v_type == VAR_DICT
4350 && tv->vval.v_dict != NULL
4351 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4352}
4353
4354/*
4355 * "islocked()" function
4356 */
4357 static void
4358f_islocked(typval_T *argvars, typval_T *rettv)
4359{
4360 lval_T lv;
4361 char_u *end;
4362 dictitem_T *di;
4363
4364 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004365 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004366 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004367 if (end != NULL && lv.ll_name != NULL)
4368 {
4369 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004370 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004371 else
4372 {
4373 if (lv.ll_tv == NULL)
4374 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004375 di = find_var(lv.ll_name, NULL, TRUE);
4376 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004377 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004378 // Consider a variable locked when:
4379 // 1. the variable itself is locked
4380 // 2. the value of the variable is locked.
4381 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004382 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4383 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384 }
4385 }
4386 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004387 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004388 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004389 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004390 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004391 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004392 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4393 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004394 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004395 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4396 }
4397 }
4398
4399 clear_lval(&lv);
4400}
4401
4402#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4403/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004404 * "isinf()" function
4405 */
4406 static void
4407f_isinf(typval_T *argvars, typval_T *rettv)
4408{
4409 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4410 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4411}
4412
4413/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004414 * "isnan()" function
4415 */
4416 static void
4417f_isnan(typval_T *argvars, typval_T *rettv)
4418{
4419 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4420 && isnan(argvars[0].vval.v_float);
4421}
4422#endif
4423
4424/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004425 * "last_buffer_nr()" function.
4426 */
4427 static void
4428f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4429{
4430 int n = 0;
4431 buf_T *buf;
4432
Bram Moolenaar29323592016-07-24 22:04:11 +02004433 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004434 if (n < buf->b_fnum)
4435 n = buf->b_fnum;
4436
4437 rettv->vval.v_number = n;
4438}
4439
4440/*
4441 * "len()" function
4442 */
4443 static void
4444f_len(typval_T *argvars, typval_T *rettv)
4445{
4446 switch (argvars[0].v_type)
4447 {
4448 case VAR_STRING:
4449 case VAR_NUMBER:
4450 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004451 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004452 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004453 case VAR_BLOB:
4454 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4455 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004456 case VAR_LIST:
4457 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4458 break;
4459 case VAR_DICT:
4460 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4461 break;
4462 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004463 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004464 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004465 case VAR_SPECIAL:
4466 case VAR_FLOAT:
4467 case VAR_FUNC:
4468 case VAR_PARTIAL:
4469 case VAR_JOB:
4470 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004471 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004472 break;
4473 }
4474}
4475
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004477libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004478{
4479#ifdef FEAT_LIBCALL
4480 char_u *string_in;
4481 char_u **string_result;
4482 int nr_result;
4483#endif
4484
4485 rettv->v_type = type;
4486 if (type != VAR_NUMBER)
4487 rettv->vval.v_string = NULL;
4488
4489 if (check_restricted() || check_secure())
4490 return;
4491
4492#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004493 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004494 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4495 {
4496 string_in = NULL;
4497 if (argvars[2].v_type == VAR_STRING)
4498 string_in = argvars[2].vval.v_string;
4499 if (type == VAR_NUMBER)
4500 string_result = NULL;
4501 else
4502 string_result = &rettv->vval.v_string;
4503 if (mch_libcall(argvars[0].vval.v_string,
4504 argvars[1].vval.v_string,
4505 string_in,
4506 argvars[2].vval.v_number,
4507 string_result,
4508 &nr_result) == OK
4509 && type == VAR_NUMBER)
4510 rettv->vval.v_number = nr_result;
4511 }
4512#endif
4513}
4514
4515/*
4516 * "libcall()" function
4517 */
4518 static void
4519f_libcall(typval_T *argvars, typval_T *rettv)
4520{
4521 libcall_common(argvars, rettv, VAR_STRING);
4522}
4523
4524/*
4525 * "libcallnr()" function
4526 */
4527 static void
4528f_libcallnr(typval_T *argvars, typval_T *rettv)
4529{
4530 libcall_common(argvars, rettv, VAR_NUMBER);
4531}
4532
4533/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004534 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004535 */
4536 static void
4537f_line(typval_T *argvars, typval_T *rettv)
4538{
4539 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004540 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004541 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004542 int id;
4543 tabpage_T *tp;
4544 win_T *wp;
4545 win_T *save_curwin;
4546 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004547
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004548 if (argvars[1].v_type != VAR_UNKNOWN)
4549 {
4550 // use window specified in the second argument
4551 id = (int)tv_get_number(&argvars[1]);
4552 wp = win_id2wp_tp(id, &tp);
4553 if (wp != NULL && tp != NULL)
4554 {
4555 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4556 == OK)
4557 {
4558 check_cursor();
4559 fp = var2fpos(&argvars[0], TRUE, &fnum);
4560 }
4561 restore_win_noblock(save_curwin, save_curtab, TRUE);
4562 }
4563 }
4564 else
4565 // use current window
4566 fp = var2fpos(&argvars[0], TRUE, &fnum);
4567
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004568 if (fp != NULL)
4569 lnum = fp->lnum;
4570 rettv->vval.v_number = lnum;
4571}
4572
4573/*
4574 * "line2byte(lnum)" function
4575 */
4576 static void
4577f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4578{
4579#ifndef FEAT_BYTEOFF
4580 rettv->vval.v_number = -1;
4581#else
4582 linenr_T lnum;
4583
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004584 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004585 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4586 rettv->vval.v_number = -1;
4587 else
4588 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4589 if (rettv->vval.v_number >= 0)
4590 ++rettv->vval.v_number;
4591#endif
4592}
4593
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594#ifdef FEAT_FLOAT
4595/*
4596 * "log()" function
4597 */
4598 static void
4599f_log(typval_T *argvars, typval_T *rettv)
4600{
4601 float_T f = 0.0;
4602
4603 rettv->v_type = VAR_FLOAT;
4604 if (get_float_arg(argvars, &f) == OK)
4605 rettv->vval.v_float = log(f);
4606 else
4607 rettv->vval.v_float = 0.0;
4608}
4609
4610/*
4611 * "log10()" function
4612 */
4613 static void
4614f_log10(typval_T *argvars, typval_T *rettv)
4615{
4616 float_T f = 0.0;
4617
4618 rettv->v_type = VAR_FLOAT;
4619 if (get_float_arg(argvars, &f) == OK)
4620 rettv->vval.v_float = log10(f);
4621 else
4622 rettv->vval.v_float = 0.0;
4623}
4624#endif
4625
4626#ifdef FEAT_LUA
4627/*
4628 * "luaeval()" function
4629 */
4630 static void
4631f_luaeval(typval_T *argvars, typval_T *rettv)
4632{
4633 char_u *str;
4634 char_u buf[NUMBUFLEN];
4635
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004636 if (check_restricted() || check_secure())
4637 return;
4638
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004639 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004640 do_luaeval(str, argvars + 1, rettv);
4641}
4642#endif
4643
4644/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004645 * "maparg()" function
4646 */
4647 static void
4648f_maparg(typval_T *argvars, typval_T *rettv)
4649{
4650 get_maparg(argvars, rettv, TRUE);
4651}
4652
4653/*
4654 * "mapcheck()" function
4655 */
4656 static void
4657f_mapcheck(typval_T *argvars, typval_T *rettv)
4658{
4659 get_maparg(argvars, rettv, FALSE);
4660}
4661
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004662typedef enum
4663{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004664 MATCH_END, // matchend()
4665 MATCH_MATCH, // match()
4666 MATCH_STR, // matchstr()
4667 MATCH_LIST, // matchlist()
4668 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004669} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004670
4671 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004672find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004673{
4674 char_u *str = NULL;
4675 long len = 0;
4676 char_u *expr = NULL;
4677 char_u *pat;
4678 regmatch_T regmatch;
4679 char_u patbuf[NUMBUFLEN];
4680 char_u strbuf[NUMBUFLEN];
4681 char_u *save_cpo;
4682 long start = 0;
4683 long nth = 1;
4684 colnr_T startcol = 0;
4685 int match = 0;
4686 list_T *l = NULL;
4687 listitem_T *li = NULL;
4688 long idx = 0;
4689 char_u *tofree = NULL;
4690
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004691 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004692 save_cpo = p_cpo;
4693 p_cpo = (char_u *)"";
4694
4695 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004696 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004697 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004698 // type MATCH_LIST: return empty list when there are no matches.
4699 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004700 if (rettv_list_alloc(rettv) == FAIL)
4701 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004702 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004703 && (list_append_string(rettv->vval.v_list,
4704 (char_u *)"", 0) == FAIL
4705 || list_append_number(rettv->vval.v_list,
4706 (varnumber_T)-1) == FAIL
4707 || list_append_number(rettv->vval.v_list,
4708 (varnumber_T)-1) == FAIL
4709 || list_append_number(rettv->vval.v_list,
4710 (varnumber_T)-1) == FAIL))
4711 {
4712 list_free(rettv->vval.v_list);
4713 rettv->vval.v_list = NULL;
4714 goto theend;
4715 }
4716 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004717 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718 {
4719 rettv->v_type = VAR_STRING;
4720 rettv->vval.v_string = NULL;
4721 }
4722
4723 if (argvars[0].v_type == VAR_LIST)
4724 {
4725 if ((l = argvars[0].vval.v_list) == NULL)
4726 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004727 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004728 li = l->lv_first;
4729 }
4730 else
4731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004732 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 len = (long)STRLEN(str);
4734 }
4735
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004736 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 if (pat == NULL)
4738 goto theend;
4739
4740 if (argvars[2].v_type != VAR_UNKNOWN)
4741 {
4742 int error = FALSE;
4743
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004744 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004745 if (error)
4746 goto theend;
4747 if (l != NULL)
4748 {
4749 li = list_find(l, start);
4750 if (li == NULL)
4751 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004752 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004753 }
4754 else
4755 {
4756 if (start < 0)
4757 start = 0;
4758 if (start > len)
4759 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004760 // When "count" argument is there ignore matches before "start",
4761 // otherwise skip part of the string. Differs when pattern is "^"
4762 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004763 if (argvars[3].v_type != VAR_UNKNOWN)
4764 startcol = start;
4765 else
4766 {
4767 str += start;
4768 len -= start;
4769 }
4770 }
4771
4772 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004773 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004774 if (error)
4775 goto theend;
4776 }
4777
4778 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4779 if (regmatch.regprog != NULL)
4780 {
4781 regmatch.rm_ic = p_ic;
4782
4783 for (;;)
4784 {
4785 if (l != NULL)
4786 {
4787 if (li == NULL)
4788 {
4789 match = FALSE;
4790 break;
4791 }
4792 vim_free(tofree);
4793 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4794 if (str == NULL)
4795 break;
4796 }
4797
4798 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4799
4800 if (match && --nth <= 0)
4801 break;
4802 if (l == NULL && !match)
4803 break;
4804
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004805 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004806 if (l != NULL)
4807 {
4808 li = li->li_next;
4809 ++idx;
4810 }
4811 else
4812 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004813 startcol = (colnr_T)(regmatch.startp[0]
4814 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004815 if (startcol > (colnr_T)len
4816 || str + startcol <= regmatch.startp[0])
4817 {
4818 match = FALSE;
4819 break;
4820 }
4821 }
4822 }
4823
4824 if (match)
4825 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004826 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004827 {
4828 listitem_T *li1 = rettv->vval.v_list->lv_first;
4829 listitem_T *li2 = li1->li_next;
4830 listitem_T *li3 = li2->li_next;
4831 listitem_T *li4 = li3->li_next;
4832
4833 vim_free(li1->li_tv.vval.v_string);
4834 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4835 (int)(regmatch.endp[0] - regmatch.startp[0]));
4836 li3->li_tv.vval.v_number =
4837 (varnumber_T)(regmatch.startp[0] - expr);
4838 li4->li_tv.vval.v_number =
4839 (varnumber_T)(regmatch.endp[0] - expr);
4840 if (l != NULL)
4841 li2->li_tv.vval.v_number = (varnumber_T)idx;
4842 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004843 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844 {
4845 int i;
4846
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004847 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004848 for (i = 0; i < NSUBEXP; ++i)
4849 {
4850 if (regmatch.endp[i] == NULL)
4851 {
4852 if (list_append_string(rettv->vval.v_list,
4853 (char_u *)"", 0) == FAIL)
4854 break;
4855 }
4856 else if (list_append_string(rettv->vval.v_list,
4857 regmatch.startp[i],
4858 (int)(regmatch.endp[i] - regmatch.startp[i]))
4859 == FAIL)
4860 break;
4861 }
4862 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004863 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004864 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004865 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004866 if (l != NULL)
4867 copy_tv(&li->li_tv, rettv);
4868 else
4869 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4870 (int)(regmatch.endp[0] - regmatch.startp[0]));
4871 }
4872 else if (l != NULL)
4873 rettv->vval.v_number = idx;
4874 else
4875 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004876 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004877 rettv->vval.v_number =
4878 (varnumber_T)(regmatch.startp[0] - str);
4879 else
4880 rettv->vval.v_number =
4881 (varnumber_T)(regmatch.endp[0] - str);
4882 rettv->vval.v_number += (varnumber_T)(str - expr);
4883 }
4884 }
4885 vim_regfree(regmatch.regprog);
4886 }
4887
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004888theend:
4889 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004890 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004891 listitem_remove(rettv->vval.v_list,
4892 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004893 vim_free(tofree);
4894 p_cpo = save_cpo;
4895}
4896
4897/*
4898 * "match()" function
4899 */
4900 static void
4901f_match(typval_T *argvars, typval_T *rettv)
4902{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004903 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004904}
4905
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906/*
4907 * "matchend()" function
4908 */
4909 static void
4910f_matchend(typval_T *argvars, typval_T *rettv)
4911{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004912 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004913}
4914
4915/*
4916 * "matchlist()" function
4917 */
4918 static void
4919f_matchlist(typval_T *argvars, typval_T *rettv)
4920{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004921 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922}
4923
4924/*
4925 * "matchstr()" function
4926 */
4927 static void
4928f_matchstr(typval_T *argvars, typval_T *rettv)
4929{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004930 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931}
4932
4933/*
4934 * "matchstrpos()" function
4935 */
4936 static void
4937f_matchstrpos(typval_T *argvars, typval_T *rettv)
4938{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004939 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940}
4941
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 static void
4943max_min(typval_T *argvars, typval_T *rettv, int domax)
4944{
4945 varnumber_T n = 0;
4946 varnumber_T i;
4947 int error = FALSE;
4948
4949 if (argvars[0].v_type == VAR_LIST)
4950 {
4951 list_T *l;
4952 listitem_T *li;
4953
4954 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004955 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004956 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004957 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004959 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4960 n = l->lv_u.nonmat.lv_start;
4961 else
4962 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4963 * l->lv_u.nonmat.lv_stride;
4964 }
4965 else
4966 {
4967 li = l->lv_first;
4968 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004969 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004970 n = tv_get_number_chk(&li->li_tv, &error);
4971 for (;;)
4972 {
4973 li = li->li_next;
4974 if (li == NULL)
4975 break;
4976 i = tv_get_number_chk(&li->li_tv, &error);
4977 if (domax ? i > n : i < n)
4978 n = i;
4979 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004980 }
4981 }
4982 }
4983 }
4984 else if (argvars[0].v_type == VAR_DICT)
4985 {
4986 dict_T *d;
4987 int first = TRUE;
4988 hashitem_T *hi;
4989 int todo;
4990
4991 d = argvars[0].vval.v_dict;
4992 if (d != NULL)
4993 {
4994 todo = (int)d->dv_hashtab.ht_used;
4995 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4996 {
4997 if (!HASHITEM_EMPTY(hi))
4998 {
4999 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005000 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005001 if (first)
5002 {
5003 n = i;
5004 first = FALSE;
5005 }
5006 else if (domax ? i > n : i < n)
5007 n = i;
5008 }
5009 }
5010 }
5011 }
5012 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005013 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005014 rettv->vval.v_number = error ? 0 : n;
5015}
5016
5017/*
5018 * "max()" function
5019 */
5020 static void
5021f_max(typval_T *argvars, typval_T *rettv)
5022{
5023 max_min(argvars, rettv, TRUE);
5024}
5025
5026/*
5027 * "min()" function
5028 */
5029 static void
5030f_min(typval_T *argvars, typval_T *rettv)
5031{
5032 max_min(argvars, rettv, FALSE);
5033}
5034
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035#if defined(FEAT_MZSCHEME) || defined(PROTO)
5036/*
5037 * "mzeval()" function
5038 */
5039 static void
5040f_mzeval(typval_T *argvars, typval_T *rettv)
5041{
5042 char_u *str;
5043 char_u buf[NUMBUFLEN];
5044
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005045 if (check_restricted() || check_secure())
5046 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005047 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005048 do_mzeval(str, rettv);
5049}
5050
5051 void
5052mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5053{
5054 typval_T argvars[3];
5055
5056 argvars[0].v_type = VAR_STRING;
5057 argvars[0].vval.v_string = name;
5058 copy_tv(args, &argvars[1]);
5059 argvars[2].v_type = VAR_UNKNOWN;
5060 f_call(argvars, rettv);
5061 clear_tv(&argvars[1]);
5062}
5063#endif
5064
5065/*
5066 * "nextnonblank()" function
5067 */
5068 static void
5069f_nextnonblank(typval_T *argvars, typval_T *rettv)
5070{
5071 linenr_T lnum;
5072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005073 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005074 {
5075 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5076 {
5077 lnum = 0;
5078 break;
5079 }
5080 if (*skipwhite(ml_get(lnum)) != NUL)
5081 break;
5082 }
5083 rettv->vval.v_number = lnum;
5084}
5085
5086/*
5087 * "nr2char()" function
5088 */
5089 static void
5090f_nr2char(typval_T *argvars, typval_T *rettv)
5091{
5092 char_u buf[NUMBUFLEN];
5093
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094 if (has_mbyte)
5095 {
5096 int utf8 = 0;
5097
5098 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005099 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005100 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005101 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005103 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104 }
5105 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005107 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108 buf[1] = NUL;
5109 }
5110 rettv->v_type = VAR_STRING;
5111 rettv->vval.v_string = vim_strsave(buf);
5112}
5113
5114/*
5115 * "or(expr, expr)" function
5116 */
5117 static void
5118f_or(typval_T *argvars, typval_T *rettv)
5119{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005120 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5121 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005122}
5123
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005124#ifdef FEAT_PERL
5125/*
5126 * "perleval()" function
5127 */
5128 static void
5129f_perleval(typval_T *argvars, typval_T *rettv)
5130{
5131 char_u *str;
5132 char_u buf[NUMBUFLEN];
5133
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005134 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135 do_perleval(str, rettv);
5136}
5137#endif
5138
5139#ifdef FEAT_FLOAT
5140/*
5141 * "pow()" function
5142 */
5143 static void
5144f_pow(typval_T *argvars, typval_T *rettv)
5145{
5146 float_T fx = 0.0, fy = 0.0;
5147
5148 rettv->v_type = VAR_FLOAT;
5149 if (get_float_arg(argvars, &fx) == OK
5150 && get_float_arg(&argvars[1], &fy) == OK)
5151 rettv->vval.v_float = pow(fx, fy);
5152 else
5153 rettv->vval.v_float = 0.0;
5154}
5155#endif
5156
5157/*
5158 * "prevnonblank()" function
5159 */
5160 static void
5161f_prevnonblank(typval_T *argvars, typval_T *rettv)
5162{
5163 linenr_T lnum;
5164
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005165 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005166 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5167 lnum = 0;
5168 else
5169 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5170 --lnum;
5171 rettv->vval.v_number = lnum;
5172}
5173
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005174// This dummy va_list is here because:
5175// - passing a NULL pointer doesn't work when va_list isn't a pointer
5176// - locally in the function results in a "used before set" warning
5177// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005178static va_list ap;
5179
5180/*
5181 * "printf()" function
5182 */
5183 static void
5184f_printf(typval_T *argvars, typval_T *rettv)
5185{
5186 char_u buf[NUMBUFLEN];
5187 int len;
5188 char_u *s;
5189 int saved_did_emsg = did_emsg;
5190 char *fmt;
5191
5192 rettv->v_type = VAR_STRING;
5193 rettv->vval.v_string = NULL;
5194
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005195 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005196 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005197 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005198 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 if (!did_emsg)
5200 {
5201 s = alloc(len + 1);
5202 if (s != NULL)
5203 {
5204 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005205 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5206 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005207 }
5208 }
5209 did_emsg |= saved_did_emsg;
5210}
5211
5212/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005213 * "pum_getpos()" function
5214 */
5215 static void
5216f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5217{
5218 if (rettv_dict_alloc(rettv) != OK)
5219 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005220 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005221}
5222
5223/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005224 * "pumvisible()" function
5225 */
5226 static void
5227f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5228{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005229 if (pum_visible())
5230 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005231}
5232
5233#ifdef FEAT_PYTHON3
5234/*
5235 * "py3eval()" function
5236 */
5237 static void
5238f_py3eval(typval_T *argvars, typval_T *rettv)
5239{
5240 char_u *str;
5241 char_u buf[NUMBUFLEN];
5242
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005243 if (check_restricted() || check_secure())
5244 return;
5245
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005246 if (p_pyx == 0)
5247 p_pyx = 3;
5248
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005249 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005250 do_py3eval(str, rettv);
5251}
5252#endif
5253
5254#ifdef FEAT_PYTHON
5255/*
5256 * "pyeval()" function
5257 */
5258 static void
5259f_pyeval(typval_T *argvars, typval_T *rettv)
5260{
5261 char_u *str;
5262 char_u buf[NUMBUFLEN];
5263
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005264 if (check_restricted() || check_secure())
5265 return;
5266
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005267 if (p_pyx == 0)
5268 p_pyx = 2;
5269
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005270 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005271 do_pyeval(str, rettv);
5272}
5273#endif
5274
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005275#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5276/*
5277 * "pyxeval()" function
5278 */
5279 static void
5280f_pyxeval(typval_T *argvars, typval_T *rettv)
5281{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005282 if (check_restricted() || check_secure())
5283 return;
5284
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005285# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5286 init_pyxversion();
5287 if (p_pyx == 2)
5288 f_pyeval(argvars, rettv);
5289 else
5290 f_py3eval(argvars, rettv);
5291# elif defined(FEAT_PYTHON)
5292 f_pyeval(argvars, rettv);
5293# elif defined(FEAT_PYTHON3)
5294 f_py3eval(argvars, rettv);
5295# endif
5296}
5297#endif
5298
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005299static UINT32_T srand_seed_for_testing = 0;
5300static int srand_seed_for_testing_is_used = FALSE;
5301
5302 static void
5303f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5304{
5305 if (argvars[0].v_type == VAR_UNKNOWN)
5306 srand_seed_for_testing_is_used = FALSE;
5307 else
5308 {
5309 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5310 srand_seed_for_testing_is_used = TRUE;
5311 }
5312}
5313
5314 static void
5315init_srand(UINT32_T *x)
5316{
5317#ifndef MSWIN
5318 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5319#endif
5320
5321 if (srand_seed_for_testing_is_used)
5322 {
5323 *x = srand_seed_for_testing;
5324 return;
5325 }
5326#ifndef MSWIN
5327 if (dev_urandom_state != FAIL)
5328 {
5329 int fd = open("/dev/urandom", O_RDONLY);
5330 struct {
5331 union {
5332 UINT32_T number;
5333 char bytes[sizeof(UINT32_T)];
5334 } contents;
5335 } buf;
5336
5337 // Attempt reading /dev/urandom.
5338 if (fd == -1)
5339 dev_urandom_state = FAIL;
5340 else
5341 {
5342 buf.contents.number = 0;
5343 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5344 != sizeof(UINT32_T))
5345 dev_urandom_state = FAIL;
5346 else
5347 {
5348 dev_urandom_state = OK;
5349 *x = buf.contents.number;
5350 }
5351 close(fd);
5352 }
5353 }
5354 if (dev_urandom_state != OK)
5355 // Reading /dev/urandom doesn't work, fall back to time().
5356#endif
5357 *x = vim_time();
5358}
5359
5360#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5361#define SPLITMIX32(x, z) ( \
5362 z = (x += 0x9e3779b9), \
5363 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5364 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5365 z ^ (z >> 16) \
5366 )
5367#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5368 result = ROTL(y * 5, 7) * 9; \
5369 t = y << 9; \
5370 z ^= x; \
5371 w ^= y; \
5372 y ^= z, x ^= w; \
5373 z ^= t; \
5374 w = ROTL(w, 11);
5375
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005376/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005377 * "rand()" function
5378 */
5379 static void
5380f_rand(typval_T *argvars, typval_T *rettv)
5381{
5382 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005383 static UINT32_T gx, gy, gz, gw;
5384 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005385 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005386 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005387
5388 if (argvars[0].v_type == VAR_UNKNOWN)
5389 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005390 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005391 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005392 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005393 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005394 init_srand(&x);
5395
5396 gx = SPLITMIX32(x, z);
5397 gy = SPLITMIX32(x, z);
5398 gz = SPLITMIX32(x, z);
5399 gw = SPLITMIX32(x, z);
5400 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005401 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005402
5403 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005404 }
5405 else if (argvars[0].v_type == VAR_LIST)
5406 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005407 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005408 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005409 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005410
5411 lx = list_find(l, 0L);
5412 ly = list_find(l, 1L);
5413 lz = list_find(l, 2L);
5414 lw = list_find(l, 3L);
5415 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5416 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5417 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5418 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5419 x = (UINT32_T)lx->li_tv.vval.v_number;
5420 y = (UINT32_T)ly->li_tv.vval.v_number;
5421 z = (UINT32_T)lz->li_tv.vval.v_number;
5422 w = (UINT32_T)lw->li_tv.vval.v_number;
5423
5424 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5425
5426 lx->li_tv.vval.v_number = (varnumber_T)x;
5427 ly->li_tv.vval.v_number = (varnumber_T)y;
5428 lz->li_tv.vval.v_number = (varnumber_T)z;
5429 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005430 }
5431 else
5432 goto theend;
5433
5434 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005435 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005436 return;
5437
5438theend:
5439 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005440 rettv->v_type = VAR_NUMBER;
5441 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005442}
5443
5444/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005445 * "srand()" function
5446 */
5447 static void
5448f_srand(typval_T *argvars, typval_T *rettv)
5449{
5450 UINT32_T x = 0, z;
5451
5452 if (rettv_list_alloc(rettv) == FAIL)
5453 return;
5454 if (argvars[0].v_type == VAR_UNKNOWN)
5455 {
5456 init_srand(&x);
5457 }
5458 else
5459 {
5460 int error = FALSE;
5461
5462 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5463 if (error)
5464 return;
5465 }
5466
5467 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5468 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5469 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5470 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5471}
5472
5473#undef ROTL
5474#undef SPLITMIX32
5475#undef SHUFFLE_XOSHIRO128STARSTAR
5476
5477/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005478 * "range()" function
5479 */
5480 static void
5481f_range(typval_T *argvars, typval_T *rettv)
5482{
5483 varnumber_T start;
5484 varnumber_T end;
5485 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005486 int error = FALSE;
5487
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005488 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489 if (argvars[1].v_type == VAR_UNKNOWN)
5490 {
5491 end = start - 1;
5492 start = 0;
5493 }
5494 else
5495 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005496 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005497 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005498 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005499 }
5500
5501 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005502 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005503 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005504 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005505 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005506 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005507 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005508 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005509 list_T *list = rettv->vval.v_list;
5510
5511 // Create a non-materialized list. This is much more efficient and
5512 // works with ":for". If used otherwise range_list_materialize() must
5513 // be called.
5514 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005515 list->lv_u.nonmat.lv_start = start;
5516 list->lv_u.nonmat.lv_end = end;
5517 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005518 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005519 }
5520}
5521
5522/*
5523 * If "list" is a non-materialized list then materialize it now.
5524 */
5525 void
5526range_list_materialize(list_T *list)
5527{
5528 if (list->lv_first == &range_list_item)
5529 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005530 varnumber_T start = list->lv_u.nonmat.lv_start;
5531 varnumber_T end = list->lv_u.nonmat.lv_end;
5532 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005533 varnumber_T i;
5534
5535 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005536 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005537 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005538 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005539 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5540 if (list_append_number(list, (varnumber_T)i) == FAIL)
5541 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005542 }
5543}
5544
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005545 static void
5546return_register(int regname, typval_T *rettv)
5547{
5548 char_u buf[2] = {0, 0};
5549
5550 buf[0] = (char_u)regname;
5551 rettv->v_type = VAR_STRING;
5552 rettv->vval.v_string = vim_strsave(buf);
5553}
5554
5555/*
5556 * "reg_executing()" function
5557 */
5558 static void
5559f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5560{
5561 return_register(reg_executing, rettv);
5562}
5563
5564/*
5565 * "reg_recording()" function
5566 */
5567 static void
5568f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5569{
5570 return_register(reg_recording, rettv);
5571}
5572
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005573#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005574 static void
5575make_connection(void)
5576{
5577 if (X_DISPLAY == NULL
5578# ifdef FEAT_GUI
5579 && !gui.in_use
5580# endif
5581 )
5582 {
5583 x_force_connect = TRUE;
5584 setup_term_clip();
5585 x_force_connect = FALSE;
5586 }
5587}
5588
5589 static int
5590check_connection(void)
5591{
5592 make_connection();
5593 if (X_DISPLAY == NULL)
5594 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005595 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596 return FAIL;
5597 }
5598 return OK;
5599}
5600#endif
5601
5602#ifdef FEAT_CLIENTSERVER
5603 static void
5604remote_common(typval_T *argvars, typval_T *rettv, int expr)
5605{
5606 char_u *server_name;
5607 char_u *keys;
5608 char_u *r = NULL;
5609 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005610 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005611# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005612 HWND w;
5613# else
5614 Window w;
5615# endif
5616
5617 if (check_restricted() || check_secure())
5618 return;
5619
5620# ifdef FEAT_X11
5621 if (check_connection() == FAIL)
5622 return;
5623# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005624 if (argvars[2].v_type != VAR_UNKNOWN
5625 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005626 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005627
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005628 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005629 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005630 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005631 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005632# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005633 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005634# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005635 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5636 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005637# endif
5638 {
5639 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005640 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005641 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005642 vim_free(r);
5643 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005644 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005645 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005646 return;
5647 }
5648
5649 rettv->vval.v_string = r;
5650
5651 if (argvars[2].v_type != VAR_UNKNOWN)
5652 {
5653 dictitem_T v;
5654 char_u str[30];
5655 char_u *idvar;
5656
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005657 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005658 if (idvar != NULL && *idvar != NUL)
5659 {
5660 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5661 v.di_tv.v_type = VAR_STRING;
5662 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005663 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005664 vim_free(v.di_tv.vval.v_string);
5665 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005666 }
5667}
5668#endif
5669
5670/*
5671 * "remote_expr()" function
5672 */
5673 static void
5674f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5675{
5676 rettv->v_type = VAR_STRING;
5677 rettv->vval.v_string = NULL;
5678#ifdef FEAT_CLIENTSERVER
5679 remote_common(argvars, rettv, TRUE);
5680#endif
5681}
5682
5683/*
5684 * "remote_foreground()" function
5685 */
5686 static void
5687f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5688{
5689#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005690# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005691 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005692 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005693 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005694
5695 if (server_name != NULL)
5696 serverForeground(server_name);
5697 }
5698# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005699 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005700 argvars[1].v_type = VAR_STRING;
5701 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5702 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005703 rettv->v_type = VAR_STRING;
5704 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005705 remote_common(argvars, rettv, TRUE);
5706 vim_free(argvars[1].vval.v_string);
5707# endif
5708#endif
5709}
5710
5711 static void
5712f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5713{
5714#ifdef FEAT_CLIENTSERVER
5715 dictitem_T v;
5716 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005717# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005718 long_u n = 0;
5719# endif
5720 char_u *serverid;
5721
5722 if (check_restricted() || check_secure())
5723 {
5724 rettv->vval.v_number = -1;
5725 return;
5726 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005727 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005728 if (serverid == NULL)
5729 {
5730 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005731 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005732 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005733# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5735 if (n == 0)
5736 rettv->vval.v_number = -1;
5737 else
5738 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005739 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005740 rettv->vval.v_number = (s != NULL);
5741 }
5742# else
5743 if (check_connection() == FAIL)
5744 return;
5745
5746 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5747 serverStrToWin(serverid), &s);
5748# endif
5749
5750 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5751 {
5752 char_u *retvar;
5753
5754 v.di_tv.v_type = VAR_STRING;
5755 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005756 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005757 if (retvar != NULL)
5758 set_var(retvar, &v.di_tv, FALSE);
5759 vim_free(v.di_tv.vval.v_string);
5760 }
5761#else
5762 rettv->vval.v_number = -1;
5763#endif
5764}
5765
5766 static void
5767f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5768{
5769 char_u *r = NULL;
5770
5771#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005772 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005773
5774 if (serverid != NULL && !check_restricted() && !check_secure())
5775 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005776 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005777# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005778 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005779 long_u n = 0;
5780# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005781
5782 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005783 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005784
Bram Moolenaar4f974752019-02-17 17:44:42 +01005785# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005786 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5787 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005788 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005789 if (r == NULL)
5790# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005791 if (check_connection() == FAIL
5792 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5793 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005795 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005796 }
5797#endif
5798 rettv->v_type = VAR_STRING;
5799 rettv->vval.v_string = r;
5800}
5801
5802/*
5803 * "remote_send()" function
5804 */
5805 static void
5806f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5807{
5808 rettv->v_type = VAR_STRING;
5809 rettv->vval.v_string = NULL;
5810#ifdef FEAT_CLIENTSERVER
5811 remote_common(argvars, rettv, FALSE);
5812#endif
5813}
5814
5815/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005816 * "remote_startserver()" function
5817 */
5818 static void
5819f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5820{
5821#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005822 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005823
5824 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005825 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005826 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005827 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005828 else
5829 {
5830# ifdef FEAT_X11
5831 if (check_connection() == OK)
5832 serverRegisterName(X_DISPLAY, server);
5833# else
5834 serverSetName(server);
5835# endif
5836 }
5837#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005838 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005839#endif
5840}
5841
5842/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005843 * "rename({from}, {to})" function
5844 */
5845 static void
5846f_rename(typval_T *argvars, typval_T *rettv)
5847{
5848 char_u buf[NUMBUFLEN];
5849
5850 if (check_restricted() || check_secure())
5851 rettv->vval.v_number = -1;
5852 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005853 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5854 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005855}
5856
5857/*
5858 * "repeat()" function
5859 */
5860 static void
5861f_repeat(typval_T *argvars, typval_T *rettv)
5862{
5863 char_u *p;
5864 int n;
5865 int slen;
5866 int len;
5867 char_u *r;
5868 int i;
5869
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005870 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005871 if (argvars[0].v_type == VAR_LIST)
5872 {
5873 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5874 while (n-- > 0)
5875 if (list_extend(rettv->vval.v_list,
5876 argvars[0].vval.v_list, NULL) == FAIL)
5877 break;
5878 }
5879 else
5880 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005881 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005882 rettv->v_type = VAR_STRING;
5883 rettv->vval.v_string = NULL;
5884
5885 slen = (int)STRLEN(p);
5886 len = slen * n;
5887 if (len <= 0)
5888 return;
5889
5890 r = alloc(len + 1);
5891 if (r != NULL)
5892 {
5893 for (i = 0; i < n; i++)
5894 mch_memmove(r + i * slen, p, (size_t)slen);
5895 r[len] = NUL;
5896 }
5897
5898 rettv->vval.v_string = r;
5899 }
5900}
5901
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005902#define SP_NOMOVE 0x01 // don't move cursor
5903#define SP_REPEAT 0x02 // repeat to find outer pair
5904#define SP_RETCOUNT 0x04 // return matchcount
5905#define SP_SETPCMARK 0x08 // set previous context mark
5906#define SP_START 0x10 // accept match at start position
5907#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5908#define SP_END 0x40 // leave cursor at end of match
5909#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005910
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005911/*
5912 * Get flags for a search function.
5913 * Possibly sets "p_ws".
5914 * Returns BACKWARD, FORWARD or zero (for an error).
5915 */
5916 static int
5917get_search_arg(typval_T *varp, int *flagsp)
5918{
5919 int dir = FORWARD;
5920 char_u *flags;
5921 char_u nbuf[NUMBUFLEN];
5922 int mask;
5923
5924 if (varp->v_type != VAR_UNKNOWN)
5925 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005926 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005927 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005928 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005929 while (*flags != NUL)
5930 {
5931 switch (*flags)
5932 {
5933 case 'b': dir = BACKWARD; break;
5934 case 'w': p_ws = TRUE; break;
5935 case 'W': p_ws = FALSE; break;
5936 default: mask = 0;
5937 if (flagsp != NULL)
5938 switch (*flags)
5939 {
5940 case 'c': mask = SP_START; break;
5941 case 'e': mask = SP_END; break;
5942 case 'm': mask = SP_RETCOUNT; break;
5943 case 'n': mask = SP_NOMOVE; break;
5944 case 'p': mask = SP_SUBPAT; break;
5945 case 'r': mask = SP_REPEAT; break;
5946 case 's': mask = SP_SETPCMARK; break;
5947 case 'z': mask = SP_COLUMN; break;
5948 }
5949 if (mask == 0)
5950 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005951 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005952 dir = 0;
5953 }
5954 else
5955 *flagsp |= mask;
5956 }
5957 if (dir == 0)
5958 break;
5959 ++flags;
5960 }
5961 }
5962 return dir;
5963}
5964
5965/*
5966 * Shared by search() and searchpos() functions.
5967 */
5968 static int
5969search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5970{
5971 int flags;
5972 char_u *pat;
5973 pos_T pos;
5974 pos_T save_cursor;
5975 int save_p_ws = p_ws;
5976 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005977 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005979#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005980 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005981 long time_limit = 0;
5982#endif
5983 int options = SEARCH_KEEP;
5984 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005985 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005986
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005987 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005988 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005989 if (dir == 0)
5990 goto theend;
5991 flags = *flagsp;
5992 if (flags & SP_START)
5993 options |= SEARCH_START;
5994 if (flags & SP_END)
5995 options |= SEARCH_END;
5996 if (flags & SP_COLUMN)
5997 options |= SEARCH_COL;
5998
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005999 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006000 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6001 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006002 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006003 if (lnum_stop < 0)
6004 goto theend;
6005#ifdef FEAT_RELTIME
6006 if (argvars[3].v_type != VAR_UNKNOWN)
6007 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006008 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006009 if (time_limit < 0)
6010 goto theend;
6011 }
6012#endif
6013 }
6014
6015#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006016 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006017 profile_setlimit(time_limit, &tm);
6018#endif
6019
6020 /*
6021 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6022 * Check to make sure only those flags are set.
6023 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6024 * flags cannot be set. Check for that condition also.
6025 */
6026 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6027 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6028 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006029 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030 goto theend;
6031 }
6032
6033 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006034 vim_memset(&sia, 0, sizeof(sia));
6035 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6036#ifdef FEAT_RELTIME
6037 sia.sa_tm = &tm;
6038#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006039 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006040 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006041 if (subpatnum != FAIL)
6042 {
6043 if (flags & SP_SUBPAT)
6044 retval = subpatnum;
6045 else
6046 retval = pos.lnum;
6047 if (flags & SP_SETPCMARK)
6048 setpcmark();
6049 curwin->w_cursor = pos;
6050 if (match_pos != NULL)
6051 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006052 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006053 match_pos->lnum = pos.lnum;
6054 match_pos->col = pos.col + 1;
6055 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006056 // "/$" will put the cursor after the end of the line, may need to
6057 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006058 check_cursor();
6059 }
6060
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006061 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006062 if (flags & SP_NOMOVE)
6063 curwin->w_cursor = save_cursor;
6064 else
6065 curwin->w_set_curswant = TRUE;
6066theend:
6067 p_ws = save_p_ws;
6068
6069 return retval;
6070}
6071
6072#ifdef FEAT_FLOAT
6073
6074/*
6075 * round() is not in C90, use ceil() or floor() instead.
6076 */
6077 float_T
6078vim_round(float_T f)
6079{
6080 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6081}
6082
6083/*
6084 * "round({float})" function
6085 */
6086 static void
6087f_round(typval_T *argvars, typval_T *rettv)
6088{
6089 float_T f = 0.0;
6090
6091 rettv->v_type = VAR_FLOAT;
6092 if (get_float_arg(argvars, &f) == OK)
6093 rettv->vval.v_float = vim_round(f);
6094 else
6095 rettv->vval.v_float = 0.0;
6096}
6097#endif
6098
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006099#ifdef FEAT_RUBY
6100/*
6101 * "rubyeval()" function
6102 */
6103 static void
6104f_rubyeval(typval_T *argvars, typval_T *rettv)
6105{
6106 char_u *str;
6107 char_u buf[NUMBUFLEN];
6108
6109 str = tv_get_string_buf(&argvars[0], buf);
6110 do_rubyeval(str, rettv);
6111}
6112#endif
6113
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006114/*
6115 * "screenattr()" function
6116 */
6117 static void
6118f_screenattr(typval_T *argvars, typval_T *rettv)
6119{
6120 int row;
6121 int col;
6122 int c;
6123
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006124 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6125 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006126 if (row < 0 || row >= screen_Rows
6127 || col < 0 || col >= screen_Columns)
6128 c = -1;
6129 else
6130 c = ScreenAttrs[LineOffset[row] + col];
6131 rettv->vval.v_number = c;
6132}
6133
6134/*
6135 * "screenchar()" function
6136 */
6137 static void
6138f_screenchar(typval_T *argvars, typval_T *rettv)
6139{
6140 int row;
6141 int col;
6142 int off;
6143 int c;
6144
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006145 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6146 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006147 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006148 c = -1;
6149 else
6150 {
6151 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006152 if (enc_utf8 && ScreenLinesUC[off] != 0)
6153 c = ScreenLinesUC[off];
6154 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006155 c = ScreenLines[off];
6156 }
6157 rettv->vval.v_number = c;
6158}
6159
6160/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006161 * "screenchars()" function
6162 */
6163 static void
6164f_screenchars(typval_T *argvars, typval_T *rettv)
6165{
6166 int row;
6167 int col;
6168 int off;
6169 int c;
6170 int i;
6171
6172 if (rettv_list_alloc(rettv) == FAIL)
6173 return;
6174 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6175 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6176 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6177 return;
6178
6179 off = LineOffset[row] + col;
6180 if (enc_utf8 && ScreenLinesUC[off] != 0)
6181 c = ScreenLinesUC[off];
6182 else
6183 c = ScreenLines[off];
6184 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6185
6186 if (enc_utf8)
6187
6188 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6189 list_append_number(rettv->vval.v_list,
6190 (varnumber_T)ScreenLinesC[i][off]);
6191}
6192
6193/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 * "screencol()" function
6195 *
6196 * First column is 1 to be consistent with virtcol().
6197 */
6198 static void
6199f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6200{
6201 rettv->vval.v_number = screen_screencol() + 1;
6202}
6203
6204/*
6205 * "screenrow()" function
6206 */
6207 static void
6208f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6209{
6210 rettv->vval.v_number = screen_screenrow() + 1;
6211}
6212
6213/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006214 * "screenstring()" function
6215 */
6216 static void
6217f_screenstring(typval_T *argvars, typval_T *rettv)
6218{
6219 int row;
6220 int col;
6221 int off;
6222 int c;
6223 int i;
6224 char_u buf[MB_MAXBYTES + 1];
6225 int buflen = 0;
6226
6227 rettv->vval.v_string = NULL;
6228 rettv->v_type = VAR_STRING;
6229
6230 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6231 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6232 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6233 return;
6234
6235 off = LineOffset[row] + col;
6236 if (enc_utf8 && ScreenLinesUC[off] != 0)
6237 c = ScreenLinesUC[off];
6238 else
6239 c = ScreenLines[off];
6240 buflen += mb_char2bytes(c, buf);
6241
6242 if (enc_utf8)
6243 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6244 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6245
6246 buf[buflen] = NUL;
6247 rettv->vval.v_string = vim_strsave(buf);
6248}
6249
6250/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006251 * "search()" function
6252 */
6253 static void
6254f_search(typval_T *argvars, typval_T *rettv)
6255{
6256 int flags = 0;
6257
6258 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6259}
6260
6261/*
6262 * "searchdecl()" function
6263 */
6264 static void
6265f_searchdecl(typval_T *argvars, typval_T *rettv)
6266{
6267 int locally = 1;
6268 int thisblock = 0;
6269 int error = FALSE;
6270 char_u *name;
6271
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006272 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006273
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006274 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006275 if (argvars[1].v_type != VAR_UNKNOWN)
6276 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006277 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006278 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006279 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006280 }
6281 if (!error && name != NULL)
6282 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6283 locally, thisblock, SEARCH_KEEP) == FAIL;
6284}
6285
6286/*
6287 * Used by searchpair() and searchpairpos()
6288 */
6289 static int
6290searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6291{
6292 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006293 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294 int save_p_ws = p_ws;
6295 int dir;
6296 int flags = 0;
6297 char_u nbuf1[NUMBUFLEN];
6298 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006299 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300 long lnum_stop = 0;
6301 long time_limit = 0;
6302
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006303 // Get the three pattern arguments: start, middle, end. Will result in an
6304 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006305 spat = tv_get_string_chk(&argvars[0]);
6306 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6307 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006308 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006309 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006310
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006311 // Handle the optional fourth argument: flags
6312 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 if (dir == 0)
6314 goto theend;
6315
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006316 // Don't accept SP_END or SP_SUBPAT.
6317 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318 if ((flags & (SP_END | SP_SUBPAT)) != 0
6319 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6320 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006321 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322 goto theend;
6323 }
6324
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006325 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006326 if (flags & SP_REPEAT)
6327 p_ws = FALSE;
6328
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006329 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006330 if (argvars[3].v_type == VAR_UNKNOWN
6331 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006332 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333 else
6334 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006335 skip = &argvars[4];
6336 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6337 && skip->v_type != VAR_STRING)
6338 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006339 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006340 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006341 goto theend;
6342 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343 if (argvars[5].v_type != VAR_UNKNOWN)
6344 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006345 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006346 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006347 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006348 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006349 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006350 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351#ifdef FEAT_RELTIME
6352 if (argvars[6].v_type != VAR_UNKNOWN)
6353 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006354 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006356 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006357 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006358 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006359 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006360 }
6361#endif
6362 }
6363 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006364
6365 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6366 match_pos, lnum_stop, time_limit);
6367
6368theend:
6369 p_ws = save_p_ws;
6370
6371 return retval;
6372}
6373
6374/*
6375 * "searchpair()" function
6376 */
6377 static void
6378f_searchpair(typval_T *argvars, typval_T *rettv)
6379{
6380 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6381}
6382
6383/*
6384 * "searchpairpos()" function
6385 */
6386 static void
6387f_searchpairpos(typval_T *argvars, typval_T *rettv)
6388{
6389 pos_T match_pos;
6390 int lnum = 0;
6391 int col = 0;
6392
6393 if (rettv_list_alloc(rettv) == FAIL)
6394 return;
6395
6396 if (searchpair_cmn(argvars, &match_pos) > 0)
6397 {
6398 lnum = match_pos.lnum;
6399 col = match_pos.col;
6400 }
6401
6402 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6403 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6404}
6405
6406/*
6407 * Search for a start/middle/end thing.
6408 * Used by searchpair(), see its documentation for the details.
6409 * Returns 0 or -1 for no match,
6410 */
6411 long
6412do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006413 char_u *spat, // start pattern
6414 char_u *mpat, // middle pattern
6415 char_u *epat, // end pattern
6416 int dir, // BACKWARD or FORWARD
6417 typval_T *skip, // skip expression
6418 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006419 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006420 linenr_T lnum_stop, // stop at this line if not zero
6421 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422{
6423 char_u *save_cpo;
6424 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6425 long retval = 0;
6426 pos_T pos;
6427 pos_T firstpos;
6428 pos_T foundpos;
6429 pos_T save_cursor;
6430 pos_T save_pos;
6431 int n;
6432 int r;
6433 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006434 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006435 int err;
6436 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006437#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006438 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006439#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006440
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006441 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 save_cpo = p_cpo;
6443 p_cpo = empty_option;
6444
6445#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006446 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006447 profile_setlimit(time_limit, &tm);
6448#endif
6449
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006450 // Make two search patterns: start/end (pat2, for in nested pairs) and
6451 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006452 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6453 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006454 if (pat2 == NULL || pat3 == NULL)
6455 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006456 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006457 if (*mpat == NUL)
6458 STRCPY(pat3, pat2);
6459 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006460 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006461 spat, epat, mpat);
6462 if (flags & SP_START)
6463 options |= SEARCH_START;
6464
Bram Moolenaar48570482017-10-30 21:48:41 +01006465 if (skip != NULL)
6466 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006467 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006468 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6469 use_skip = skip->vval.v_string != NULL
6470 && *skip->vval.v_string != NUL;
6471 }
6472
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473 save_cursor = curwin->w_cursor;
6474 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006475 CLEAR_POS(&firstpos);
6476 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006477 pat = pat3;
6478 for (;;)
6479 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006480 searchit_arg_T sia;
6481
6482 vim_memset(&sia, 0, sizeof(sia));
6483 sia.sa_stop_lnum = lnum_stop;
6484#ifdef FEAT_RELTIME
6485 sia.sa_tm = &tm;
6486#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006487 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006488 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006489 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006490 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491 break;
6492
6493 if (firstpos.lnum == 0)
6494 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006495 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006497 // Found the same position again. Can happen with a pattern that
6498 // has "\zs" at the end and searching backwards. Advance one
6499 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500 if (dir == BACKWARD)
6501 decl(&pos);
6502 else
6503 incl(&pos);
6504 }
6505 foundpos = pos;
6506
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006507 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508 options &= ~SEARCH_START;
6509
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006510 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006511 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006512 {
6513 save_pos = curwin->w_cursor;
6514 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006515 err = FALSE;
6516 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006517 curwin->w_cursor = save_pos;
6518 if (err)
6519 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006520 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006521 curwin->w_cursor = save_cursor;
6522 retval = -1;
6523 break;
6524 }
6525 if (r)
6526 continue;
6527 }
6528
6529 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6530 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006531 // Found end when searching backwards or start when searching
6532 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006533 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006534 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006535 }
6536 else
6537 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006538 // Found end when searching forward or start when searching
6539 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006540 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006541 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006542 }
6543
6544 if (nest == 0)
6545 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006546 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006547 if (flags & SP_RETCOUNT)
6548 ++retval;
6549 else
6550 retval = pos.lnum;
6551 if (flags & SP_SETPCMARK)
6552 setpcmark();
6553 curwin->w_cursor = pos;
6554 if (!(flags & SP_REPEAT))
6555 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006556 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006557 }
6558 }
6559
6560 if (match_pos != NULL)
6561 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006562 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006563 match_pos->lnum = curwin->w_cursor.lnum;
6564 match_pos->col = curwin->w_cursor.col + 1;
6565 }
6566
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006567 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006568 if ((flags & SP_NOMOVE) || retval == 0)
6569 curwin->w_cursor = save_cursor;
6570
6571theend:
6572 vim_free(pat2);
6573 vim_free(pat3);
6574 if (p_cpo == empty_option)
6575 p_cpo = save_cpo;
6576 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006577 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006578 free_string_option(save_cpo);
6579
6580 return retval;
6581}
6582
6583/*
6584 * "searchpos()" function
6585 */
6586 static void
6587f_searchpos(typval_T *argvars, typval_T *rettv)
6588{
6589 pos_T match_pos;
6590 int lnum = 0;
6591 int col = 0;
6592 int n;
6593 int flags = 0;
6594
6595 if (rettv_list_alloc(rettv) == FAIL)
6596 return;
6597
6598 n = search_cmn(argvars, &match_pos, &flags);
6599 if (n > 0)
6600 {
6601 lnum = match_pos.lnum;
6602 col = match_pos.col;
6603 }
6604
6605 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6606 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6607 if (flags & SP_SUBPAT)
6608 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6609}
6610
6611 static void
6612f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6613{
6614#ifdef FEAT_CLIENTSERVER
6615 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006616 char_u *server = tv_get_string_chk(&argvars[0]);
6617 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006618
6619 rettv->vval.v_number = -1;
6620 if (server == NULL || reply == NULL)
6621 return;
6622 if (check_restricted() || check_secure())
6623 return;
6624# ifdef FEAT_X11
6625 if (check_connection() == FAIL)
6626 return;
6627# endif
6628
6629 if (serverSendReply(server, reply) < 0)
6630 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006631 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006632 return;
6633 }
6634 rettv->vval.v_number = 0;
6635#else
6636 rettv->vval.v_number = -1;
6637#endif
6638}
6639
6640 static void
6641f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6642{
6643 char_u *r = NULL;
6644
6645#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006646# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006647 r = serverGetVimNames();
6648# else
6649 make_connection();
6650 if (X_DISPLAY != NULL)
6651 r = serverGetVimNames(X_DISPLAY);
6652# endif
6653#endif
6654 rettv->v_type = VAR_STRING;
6655 rettv->vval.v_string = r;
6656}
6657
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006658 static void
6659f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6660{
6661 dict_T *d;
6662 dictitem_T *di;
6663 char_u *csearch;
6664
6665 if (argvars[0].v_type != VAR_DICT)
6666 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006667 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006668 return;
6669 }
6670
6671 if ((d = argvars[0].vval.v_dict) != NULL)
6672 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006673 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006674 if (csearch != NULL)
6675 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006676 if (enc_utf8)
6677 {
6678 int pcc[MAX_MCO];
6679 int c = utfc_ptr2char(csearch, pcc);
6680
6681 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6682 }
6683 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006684 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006685 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006686 }
6687
6688 di = dict_find(d, (char_u *)"forward", -1);
6689 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006690 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006691 ? FORWARD : BACKWARD);
6692
6693 di = dict_find(d, (char_u *)"until", -1);
6694 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006695 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006696 }
6697}
6698
6699/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006700 * "setenv()" function
6701 */
6702 static void
6703f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6704{
6705 char_u namebuf[NUMBUFLEN];
6706 char_u valbuf[NUMBUFLEN];
6707 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6708
6709 if (argvars[1].v_type == VAR_SPECIAL
6710 && argvars[1].vval.v_number == VVAL_NULL)
6711 vim_unsetenv(name);
6712 else
6713 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6714}
6715
6716/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006717 * "setfperm({fname}, {mode})" function
6718 */
6719 static void
6720f_setfperm(typval_T *argvars, typval_T *rettv)
6721{
6722 char_u *fname;
6723 char_u modebuf[NUMBUFLEN];
6724 char_u *mode_str;
6725 int i;
6726 int mask;
6727 int mode = 0;
6728
6729 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006730 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006731 if (fname == NULL)
6732 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006733 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006734 if (mode_str == NULL)
6735 return;
6736 if (STRLEN(mode_str) != 9)
6737 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006738 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 return;
6740 }
6741
6742 mask = 1;
6743 for (i = 8; i >= 0; --i)
6744 {
6745 if (mode_str[i] != '-')
6746 mode |= mask;
6747 mask = mask << 1;
6748 }
6749 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6750}
6751
6752/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006753 * "setpos()" function
6754 */
6755 static void
6756f_setpos(typval_T *argvars, typval_T *rettv)
6757{
6758 pos_T pos;
6759 int fnum;
6760 char_u *name;
6761 colnr_T curswant = -1;
6762
6763 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006764 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006765 if (name != NULL)
6766 {
6767 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6768 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006769 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770 pos.col = 0;
6771 if (name[0] == '.' && name[1] == NUL)
6772 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006773 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006774 curwin->w_cursor = pos;
6775 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006777 curwin->w_curswant = curswant - 1;
6778 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006780 check_cursor();
6781 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782 }
6783 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6784 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006785 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006786 if (setmark_pos(name[1], &pos, fnum) == OK)
6787 rettv->vval.v_number = 0;
6788 }
6789 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006790 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006791 }
6792 }
6793}
6794
6795/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 * "setreg()" function
6797 */
6798 static void
6799f_setreg(typval_T *argvars, typval_T *rettv)
6800{
6801 int regname;
6802 char_u *strregname;
6803 char_u *stropt;
6804 char_u *strval;
6805 int append;
6806 char_u yank_type;
6807 long block_len;
6808
6809 block_len = -1;
6810 yank_type = MAUTO;
6811 append = FALSE;
6812
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006813 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006814 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006815
6816 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006817 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006818 regname = *strregname;
6819 if (regname == 0 || regname == '@')
6820 regname = '"';
6821
6822 if (argvars[2].v_type != VAR_UNKNOWN)
6823 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006824 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006825 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006826 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006827 for (; *stropt != NUL; ++stropt)
6828 switch (*stropt)
6829 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006830 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831 append = TRUE;
6832 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006833 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834 yank_type = MCHAR;
6835 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006836 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006837 yank_type = MLINE;
6838 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006839 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840 yank_type = MBLOCK;
6841 if (VIM_ISDIGIT(stropt[1]))
6842 {
6843 ++stropt;
6844 block_len = getdigits(&stropt) - 1;
6845 --stropt;
6846 }
6847 break;
6848 }
6849 }
6850
6851 if (argvars[1].v_type == VAR_LIST)
6852 {
6853 char_u **lstval;
6854 char_u **allocval;
6855 char_u buf[NUMBUFLEN];
6856 char_u **curval;
6857 char_u **curallocval;
6858 list_T *ll = argvars[1].vval.v_list;
6859 listitem_T *li;
6860 int len;
6861
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006862 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006863 len = ll == NULL ? 0 : ll->lv_len;
6864
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006865 // First half: use for pointers to result lines; second half: use for
6866 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006867 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868 if (lstval == NULL)
6869 return;
6870 curval = lstval;
6871 allocval = lstval + len + 2;
6872 curallocval = allocval;
6873
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006874 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006875 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006876 range_list_materialize(ll);
6877 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006879 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 if (strval == NULL)
6881 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006882 if (strval == buf)
6883 {
6884 // Need to make a copy, next tv_get_string_buf_chk() will
6885 // overwrite the string.
6886 strval = vim_strsave(buf);
6887 if (strval == NULL)
6888 goto free_lstval;
6889 *curallocval++ = strval;
6890 }
6891 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893 }
6894 *curval++ = NULL;
6895
6896 write_reg_contents_lst(regname, lstval, -1,
6897 append, yank_type, block_len);
6898free_lstval:
6899 while (curallocval > allocval)
6900 vim_free(*--curallocval);
6901 vim_free(lstval);
6902 }
6903 else
6904 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006905 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 if (strval == NULL)
6907 return;
6908 write_reg_contents_ex(regname, strval, -1,
6909 append, yank_type, block_len);
6910 }
6911 rettv->vval.v_number = 0;
6912}
6913
6914/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006915 * "settagstack()" function
6916 */
6917 static void
6918f_settagstack(typval_T *argvars, typval_T *rettv)
6919{
6920 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6921 win_T *wp;
6922 dict_T *d;
6923 int action = 'r';
6924
6925 rettv->vval.v_number = -1;
6926
6927 // first argument: window number or id
6928 wp = find_win_by_nr_or_id(&argvars[0]);
6929 if (wp == NULL)
6930 return;
6931
6932 // second argument: dict with items to set in the tag stack
6933 if (argvars[1].v_type != VAR_DICT)
6934 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006935 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006936 return;
6937 }
6938 d = argvars[1].vval.v_dict;
6939 if (d == NULL)
6940 return;
6941
6942 // third argument: action - 'a' for append and 'r' for replace.
6943 // default is to replace the stack.
6944 if (argvars[2].v_type == VAR_UNKNOWN)
6945 action = 'r';
6946 else if (argvars[2].v_type == VAR_STRING)
6947 {
6948 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006949 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006950 if (actstr == NULL)
6951 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006952 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6953 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006954 action = *actstr;
6955 else
6956 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006957 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006958 return;
6959 }
6960 }
6961 else
6962 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006963 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006964 return;
6965 }
6966
6967 if (set_tagstack(wp, d, action) == OK)
6968 rettv->vval.v_number = 0;
6969}
6970
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006971#ifdef FEAT_CRYPT
6972/*
6973 * "sha256({string})" function
6974 */
6975 static void
6976f_sha256(typval_T *argvars, typval_T *rettv)
6977{
6978 char_u *p;
6979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006980 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006981 rettv->vval.v_string = vim_strsave(
6982 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6983 rettv->v_type = VAR_STRING;
6984}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006985#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986
6987/*
6988 * "shellescape({string})" function
6989 */
6990 static void
6991f_shellescape(typval_T *argvars, typval_T *rettv)
6992{
Bram Moolenaar20615522017-06-05 18:46:26 +02006993 int do_special = non_zero_arg(&argvars[1]);
6994
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006995 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006996 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006997 rettv->v_type = VAR_STRING;
6998}
6999
7000/*
7001 * shiftwidth() function
7002 */
7003 static void
7004f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7005{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007006 rettv->vval.v_number = 0;
7007
7008 if (argvars[0].v_type != VAR_UNKNOWN)
7009 {
7010 long col;
7011
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007012 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007013 if (col < 0)
7014 return; // type error; errmsg already given
7015#ifdef FEAT_VARTABS
7016 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7017 return;
7018#endif
7019 }
7020
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007021 rettv->vval.v_number = get_sw_value(curbuf);
7022}
7023
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024#ifdef FEAT_FLOAT
7025/*
7026 * "sin()" function
7027 */
7028 static void
7029f_sin(typval_T *argvars, typval_T *rettv)
7030{
7031 float_T f = 0.0;
7032
7033 rettv->v_type = VAR_FLOAT;
7034 if (get_float_arg(argvars, &f) == OK)
7035 rettv->vval.v_float = sin(f);
7036 else
7037 rettv->vval.v_float = 0.0;
7038}
7039
7040/*
7041 * "sinh()" function
7042 */
7043 static void
7044f_sinh(typval_T *argvars, typval_T *rettv)
7045{
7046 float_T f = 0.0;
7047
7048 rettv->v_type = VAR_FLOAT;
7049 if (get_float_arg(argvars, &f) == OK)
7050 rettv->vval.v_float = sinh(f);
7051 else
7052 rettv->vval.v_float = 0.0;
7053}
7054#endif
7055
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007056/*
7057 * "soundfold({word})" function
7058 */
7059 static void
7060f_soundfold(typval_T *argvars, typval_T *rettv)
7061{
7062 char_u *s;
7063
7064 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007065 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007066#ifdef FEAT_SPELL
7067 rettv->vval.v_string = eval_soundfold(s);
7068#else
7069 rettv->vval.v_string = vim_strsave(s);
7070#endif
7071}
7072
7073/*
7074 * "spellbadword()" function
7075 */
7076 static void
7077f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7078{
7079 char_u *word = (char_u *)"";
7080 hlf_T attr = HLF_COUNT;
7081 int len = 0;
7082
7083 if (rettv_list_alloc(rettv) == FAIL)
7084 return;
7085
7086#ifdef FEAT_SPELL
7087 if (argvars[0].v_type == VAR_UNKNOWN)
7088 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007089 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007090 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7091 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007092 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007093 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007094 curwin->w_set_curswant = TRUE;
7095 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007096 }
7097 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7098 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007099 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007100 int capcol = -1;
7101
7102 if (str != NULL)
7103 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007104 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007105 while (*str != NUL)
7106 {
7107 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7108 if (attr != HLF_COUNT)
7109 {
7110 word = str;
7111 break;
7112 }
7113 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007114 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007115 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007116 }
7117 }
7118 }
7119#endif
7120
7121 list_append_string(rettv->vval.v_list, word, len);
7122 list_append_string(rettv->vval.v_list, (char_u *)(
7123 attr == HLF_SPB ? "bad" :
7124 attr == HLF_SPR ? "rare" :
7125 attr == HLF_SPL ? "local" :
7126 attr == HLF_SPC ? "caps" :
7127 ""), -1);
7128}
7129
7130/*
7131 * "spellsuggest()" function
7132 */
7133 static void
7134f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7135{
7136#ifdef FEAT_SPELL
7137 char_u *str;
7138 int typeerr = FALSE;
7139 int maxcount;
7140 garray_T ga;
7141 int i;
7142 listitem_T *li;
7143 int need_capital = FALSE;
7144#endif
7145
7146 if (rettv_list_alloc(rettv) == FAIL)
7147 return;
7148
7149#ifdef FEAT_SPELL
7150 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7151 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007152 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007153 if (argvars[1].v_type != VAR_UNKNOWN)
7154 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007155 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007156 if (maxcount <= 0)
7157 return;
7158 if (argvars[2].v_type != VAR_UNKNOWN)
7159 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007160 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007161 if (typeerr)
7162 return;
7163 }
7164 }
7165 else
7166 maxcount = 25;
7167
7168 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7169
7170 for (i = 0; i < ga.ga_len; ++i)
7171 {
7172 str = ((char_u **)ga.ga_data)[i];
7173
7174 li = listitem_alloc();
7175 if (li == NULL)
7176 vim_free(str);
7177 else
7178 {
7179 li->li_tv.v_type = VAR_STRING;
7180 li->li_tv.v_lock = 0;
7181 li->li_tv.vval.v_string = str;
7182 list_append(rettv->vval.v_list, li);
7183 }
7184 }
7185 ga_clear(&ga);
7186 }
7187#endif
7188}
7189
7190 static void
7191f_split(typval_T *argvars, typval_T *rettv)
7192{
7193 char_u *str;
7194 char_u *end;
7195 char_u *pat = NULL;
7196 regmatch_T regmatch;
7197 char_u patbuf[NUMBUFLEN];
7198 char_u *save_cpo;
7199 int match;
7200 colnr_T col = 0;
7201 int keepempty = FALSE;
7202 int typeerr = FALSE;
7203
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007204 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007205 save_cpo = p_cpo;
7206 p_cpo = (char_u *)"";
7207
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007208 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007209 if (argvars[1].v_type != VAR_UNKNOWN)
7210 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007211 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007212 if (pat == NULL)
7213 typeerr = TRUE;
7214 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007215 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007216 }
7217 if (pat == NULL || *pat == NUL)
7218 pat = (char_u *)"[\\x01- ]\\+";
7219
7220 if (rettv_list_alloc(rettv) == FAIL)
7221 return;
7222 if (typeerr)
7223 return;
7224
7225 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7226 if (regmatch.regprog != NULL)
7227 {
7228 regmatch.rm_ic = FALSE;
7229 while (*str != NUL || keepempty)
7230 {
7231 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007232 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 else
7234 match = vim_regexec_nl(&regmatch, str, col);
7235 if (match)
7236 end = regmatch.startp[0];
7237 else
7238 end = str + STRLEN(str);
7239 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7240 && *str != NUL && match && end < regmatch.endp[0]))
7241 {
7242 if (list_append_string(rettv->vval.v_list, str,
7243 (int)(end - str)) == FAIL)
7244 break;
7245 }
7246 if (!match)
7247 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007248 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007249 if (regmatch.endp[0] > str)
7250 col = 0;
7251 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007252 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007253 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 str = regmatch.endp[0];
7255 }
7256
7257 vim_regfree(regmatch.regprog);
7258 }
7259
7260 p_cpo = save_cpo;
7261}
7262
7263#ifdef FEAT_FLOAT
7264/*
7265 * "sqrt()" function
7266 */
7267 static void
7268f_sqrt(typval_T *argvars, typval_T *rettv)
7269{
7270 float_T f = 0.0;
7271
7272 rettv->v_type = VAR_FLOAT;
7273 if (get_float_arg(argvars, &f) == OK)
7274 rettv->vval.v_float = sqrt(f);
7275 else
7276 rettv->vval.v_float = 0.0;
7277}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007278#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007279
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007280#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007281/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007282 * "str2float()" function
7283 */
7284 static void
7285f_str2float(typval_T *argvars, typval_T *rettv)
7286{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007287 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007288 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007289
Bram Moolenaar08243d22017-01-10 16:12:29 +01007290 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007291 p = skipwhite(p + 1);
7292 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007293 if (isneg)
7294 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007295 rettv->v_type = VAR_FLOAT;
7296}
7297#endif
7298
7299/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007300 * "str2list()" function
7301 */
7302 static void
7303f_str2list(typval_T *argvars, typval_T *rettv)
7304{
7305 char_u *p;
7306 int utf8 = FALSE;
7307
7308 if (rettv_list_alloc(rettv) == FAIL)
7309 return;
7310
7311 if (argvars[1].v_type != VAR_UNKNOWN)
7312 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7313
7314 p = tv_get_string(&argvars[0]);
7315
7316 if (has_mbyte || utf8)
7317 {
7318 int (*ptr2len)(char_u *);
7319 int (*ptr2char)(char_u *);
7320
7321 if (utf8 || enc_utf8)
7322 {
7323 ptr2len = utf_ptr2len;
7324 ptr2char = utf_ptr2char;
7325 }
7326 else
7327 {
7328 ptr2len = mb_ptr2len;
7329 ptr2char = mb_ptr2char;
7330 }
7331
7332 for ( ; *p != NUL; p += (*ptr2len)(p))
7333 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7334 }
7335 else
7336 for ( ; *p != NUL; ++p)
7337 list_append_number(rettv->vval.v_list, *p);
7338}
7339
7340/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007341 * "str2nr()" function
7342 */
7343 static void
7344f_str2nr(typval_T *argvars, typval_T *rettv)
7345{
7346 int base = 10;
7347 char_u *p;
7348 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007349 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007350 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351
7352 if (argvars[1].v_type != VAR_UNKNOWN)
7353 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007354 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007355 if (base != 2 && base != 8 && base != 10 && base != 16)
7356 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007357 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007358 return;
7359 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007360 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7361 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362 }
7363
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007364 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007365 isneg = (*p == '-');
7366 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007367 p = skipwhite(p + 1);
7368 switch (base)
7369 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007370 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7371 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7372 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007373 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007374 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7375 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007376 if (isneg)
7377 rettv->vval.v_number = -n;
7378 else
7379 rettv->vval.v_number = n;
7380
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007381}
7382
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383/*
7384 * "strgetchar()" function
7385 */
7386 static void
7387f_strgetchar(typval_T *argvars, typval_T *rettv)
7388{
7389 char_u *str;
7390 int len;
7391 int error = FALSE;
7392 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007393 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007394
7395 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007396 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007397 if (str == NULL)
7398 return;
7399 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007400 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007401 if (error)
7402 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403
Bram Moolenaar13505972019-01-24 15:04:48 +01007404 while (charidx >= 0 && byteidx < len)
7405 {
7406 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007408 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7409 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007411 --charidx;
7412 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007413 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007414}
7415
7416/*
7417 * "stridx()" function
7418 */
7419 static void
7420f_stridx(typval_T *argvars, typval_T *rettv)
7421{
7422 char_u buf[NUMBUFLEN];
7423 char_u *needle;
7424 char_u *haystack;
7425 char_u *save_haystack;
7426 char_u *pos;
7427 int start_idx;
7428
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007429 needle = tv_get_string_chk(&argvars[1]);
7430 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431 rettv->vval.v_number = -1;
7432 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007433 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434
7435 if (argvars[2].v_type != VAR_UNKNOWN)
7436 {
7437 int error = FALSE;
7438
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007439 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 if (error || start_idx >= (int)STRLEN(haystack))
7441 return;
7442 if (start_idx >= 0)
7443 haystack += start_idx;
7444 }
7445
7446 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7447 if (pos != NULL)
7448 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7449}
7450
7451/*
7452 * "string()" function
7453 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007454 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455f_string(typval_T *argvars, typval_T *rettv)
7456{
7457 char_u *tofree;
7458 char_u numbuf[NUMBUFLEN];
7459
7460 rettv->v_type = VAR_STRING;
7461 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7462 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007463 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464 if (rettv->vval.v_string != NULL && tofree == NULL)
7465 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7466}
7467
7468/*
7469 * "strlen()" function
7470 */
7471 static void
7472f_strlen(typval_T *argvars, typval_T *rettv)
7473{
7474 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007475 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007476}
7477
7478/*
7479 * "strchars()" function
7480 */
7481 static void
7482f_strchars(typval_T *argvars, typval_T *rettv)
7483{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007484 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007485 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007486 varnumber_T len = 0;
7487 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488
7489 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007490 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007492 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007493 else
7494 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7496 while (*s != NUL)
7497 {
7498 func_mb_ptr2char_adv(&s);
7499 ++len;
7500 }
7501 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502 }
7503}
7504
7505/*
7506 * "strdisplaywidth()" function
7507 */
7508 static void
7509f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7510{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007511 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007512 int col = 0;
7513
7514 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007515 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516
7517 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7518}
7519
7520/*
7521 * "strwidth()" function
7522 */
7523 static void
7524f_strwidth(typval_T *argvars, typval_T *rettv)
7525{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007526 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527
Bram Moolenaar13505972019-01-24 15:04:48 +01007528 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529}
7530
7531/*
7532 * "strcharpart()" function
7533 */
7534 static void
7535f_strcharpart(typval_T *argvars, typval_T *rettv)
7536{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537 char_u *p;
7538 int nchar;
7539 int nbyte = 0;
7540 int charlen;
7541 int len = 0;
7542 int slen;
7543 int error = FALSE;
7544
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007545 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 slen = (int)STRLEN(p);
7547
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007548 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007549 if (!error)
7550 {
7551 if (nchar > 0)
7552 while (nchar > 0 && nbyte < slen)
7553 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007554 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007555 --nchar;
7556 }
7557 else
7558 nbyte = nchar;
7559 if (argvars[2].v_type != VAR_UNKNOWN)
7560 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007561 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007562 while (charlen > 0 && nbyte + len < slen)
7563 {
7564 int off = nbyte + len;
7565
7566 if (off < 0)
7567 len += 1;
7568 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007569 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570 --charlen;
7571 }
7572 }
7573 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007574 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575 }
7576
7577 /*
7578 * Only return the overlap between the specified part and the actual
7579 * string.
7580 */
7581 if (nbyte < 0)
7582 {
7583 len += nbyte;
7584 nbyte = 0;
7585 }
7586 else if (nbyte > slen)
7587 nbyte = slen;
7588 if (len < 0)
7589 len = 0;
7590 else if (nbyte + len > slen)
7591 len = slen - nbyte;
7592
7593 rettv->v_type = VAR_STRING;
7594 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007595}
7596
7597/*
7598 * "strpart()" function
7599 */
7600 static void
7601f_strpart(typval_T *argvars, typval_T *rettv)
7602{
7603 char_u *p;
7604 int n;
7605 int len;
7606 int slen;
7607 int error = FALSE;
7608
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007609 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 slen = (int)STRLEN(p);
7611
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007612 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613 if (error)
7614 len = 0;
7615 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007616 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007618 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619
7620 /*
7621 * Only return the overlap between the specified part and the actual
7622 * string.
7623 */
7624 if (n < 0)
7625 {
7626 len += n;
7627 n = 0;
7628 }
7629 else if (n > slen)
7630 n = slen;
7631 if (len < 0)
7632 len = 0;
7633 else if (n + len > slen)
7634 len = slen - n;
7635
7636 rettv->v_type = VAR_STRING;
7637 rettv->vval.v_string = vim_strnsave(p + n, len);
7638}
7639
7640/*
7641 * "strridx()" function
7642 */
7643 static void
7644f_strridx(typval_T *argvars, typval_T *rettv)
7645{
7646 char_u buf[NUMBUFLEN];
7647 char_u *needle;
7648 char_u *haystack;
7649 char_u *rest;
7650 char_u *lastmatch = NULL;
7651 int haystack_len, end_idx;
7652
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007653 needle = tv_get_string_chk(&argvars[1]);
7654 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655
7656 rettv->vval.v_number = -1;
7657 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007658 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659
7660 haystack_len = (int)STRLEN(haystack);
7661 if (argvars[2].v_type != VAR_UNKNOWN)
7662 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007663 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007664 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007665 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007666 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667 }
7668 else
7669 end_idx = haystack_len;
7670
7671 if (*needle == NUL)
7672 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007673 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007674 lastmatch = haystack + end_idx;
7675 }
7676 else
7677 {
7678 for (rest = haystack; *rest != '\0'; ++rest)
7679 {
7680 rest = (char_u *)strstr((char *)rest, (char *)needle);
7681 if (rest == NULL || rest > haystack + end_idx)
7682 break;
7683 lastmatch = rest;
7684 }
7685 }
7686
7687 if (lastmatch == NULL)
7688 rettv->vval.v_number = -1;
7689 else
7690 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7691}
7692
7693/*
7694 * "strtrans()" function
7695 */
7696 static void
7697f_strtrans(typval_T *argvars, typval_T *rettv)
7698{
7699 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007700 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007701}
7702
7703/*
7704 * "submatch()" function
7705 */
7706 static void
7707f_submatch(typval_T *argvars, typval_T *rettv)
7708{
7709 int error = FALSE;
7710 int no;
7711 int retList = 0;
7712
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007713 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714 if (error)
7715 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007716 if (no < 0 || no >= NSUBEXP)
7717 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007718 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007719 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007720 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007721 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007722 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007723 if (error)
7724 return;
7725
7726 if (retList == 0)
7727 {
7728 rettv->v_type = VAR_STRING;
7729 rettv->vval.v_string = reg_submatch(no);
7730 }
7731 else
7732 {
7733 rettv->v_type = VAR_LIST;
7734 rettv->vval.v_list = reg_submatch_list(no);
7735 }
7736}
7737
7738/*
7739 * "substitute()" function
7740 */
7741 static void
7742f_substitute(typval_T *argvars, typval_T *rettv)
7743{
7744 char_u patbuf[NUMBUFLEN];
7745 char_u subbuf[NUMBUFLEN];
7746 char_u flagsbuf[NUMBUFLEN];
7747
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007748 char_u *str = tv_get_string_chk(&argvars[0]);
7749 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007750 char_u *sub = NULL;
7751 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007752 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007753
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007754 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7755 expr = &argvars[2];
7756 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007757 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007758
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007760 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7761 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007762 rettv->vval.v_string = NULL;
7763 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007764 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765}
7766
7767/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007768 * "swapinfo(swap_filename)" function
7769 */
7770 static void
7771f_swapinfo(typval_T *argvars, typval_T *rettv)
7772{
7773 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007774 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007775}
7776
7777/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007778 * "swapname(expr)" function
7779 */
7780 static void
7781f_swapname(typval_T *argvars, typval_T *rettv)
7782{
7783 buf_T *buf;
7784
7785 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007786 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007787 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7788 || buf->b_ml.ml_mfp->mf_fname == NULL)
7789 rettv->vval.v_string = NULL;
7790 else
7791 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7792}
7793
7794/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795 * "synID(lnum, col, trans)" function
7796 */
7797 static void
7798f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7799{
7800 int id = 0;
7801#ifdef FEAT_SYN_HL
7802 linenr_T lnum;
7803 colnr_T col;
7804 int trans;
7805 int transerr = FALSE;
7806
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007807 lnum = tv_get_lnum(argvars); // -1 on type error
7808 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007809 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007810
7811 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7812 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7813 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7814#endif
7815
7816 rettv->vval.v_number = id;
7817}
7818
7819/*
7820 * "synIDattr(id, what [, mode])" function
7821 */
7822 static void
7823f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7824{
7825 char_u *p = NULL;
7826#ifdef FEAT_SYN_HL
7827 int id;
7828 char_u *what;
7829 char_u *mode;
7830 char_u modebuf[NUMBUFLEN];
7831 int modec;
7832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007833 id = (int)tv_get_number(&argvars[0]);
7834 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007835 if (argvars[2].v_type != VAR_UNKNOWN)
7836 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007837 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007838 modec = TOLOWER_ASC(mode[0]);
7839 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007840 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841 }
7842 else
7843 {
7844#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7845 if (USE_24BIT)
7846 modec = 'g';
7847 else
7848#endif
7849 if (t_colors > 1)
7850 modec = 'c';
7851 else
7852 modec = 't';
7853 }
7854
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007855 switch (TOLOWER_ASC(what[0]))
7856 {
7857 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007858 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007860 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 p = highlight_has_attr(id, HL_BOLD, modec);
7862 break;
7863
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007864 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007865 p = highlight_color(id, what, modec);
7866 break;
7867
7868 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007869 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007870 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007871 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007872 p = highlight_has_attr(id, HL_ITALIC, modec);
7873 break;
7874
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007875 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007876 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007877 break;
7878
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007879 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 p = highlight_has_attr(id, HL_INVERSE, modec);
7881 break;
7882
7883 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007884 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007886 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007887 else if (TOLOWER_ASC(what[1]) == 't' &&
7888 TOLOWER_ASC(what[2]) == 'r')
7889 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007890 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007891 p = highlight_has_attr(id, HL_STANDOUT, modec);
7892 break;
7893
7894 case 'u':
7895 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007896 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7898 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007899 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7901 break;
7902 }
7903
7904 if (p != NULL)
7905 p = vim_strsave(p);
7906#endif
7907 rettv->v_type = VAR_STRING;
7908 rettv->vval.v_string = p;
7909}
7910
7911/*
7912 * "synIDtrans(id)" function
7913 */
7914 static void
7915f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7916{
7917 int id;
7918
7919#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007920 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921
7922 if (id > 0)
7923 id = syn_get_final_id(id);
7924 else
7925#endif
7926 id = 0;
7927
7928 rettv->vval.v_number = id;
7929}
7930
7931/*
7932 * "synconcealed(lnum, col)" function
7933 */
7934 static void
7935f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7936{
7937#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7938 linenr_T lnum;
7939 colnr_T col;
7940 int syntax_flags = 0;
7941 int cchar;
7942 int matchid = 0;
7943 char_u str[NUMBUFLEN];
7944#endif
7945
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007946 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007947
7948#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007949 lnum = tv_get_lnum(argvars); // -1 on type error
7950 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951
7952 vim_memset(str, NUL, sizeof(str));
7953
7954 if (rettv_list_alloc(rettv) != FAIL)
7955 {
7956 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7957 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7958 && curwin->w_p_cole > 0)
7959 {
7960 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7961 syntax_flags = get_syntax_info(&matchid);
7962
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007963 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007964 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7965 {
7966 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007967 if (cchar == NUL && curwin->w_p_cole == 1)
7968 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007969 if (cchar != NUL)
7970 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007971 if (has_mbyte)
7972 (*mb_char2bytes)(cchar, str);
7973 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007974 str[0] = cchar;
7975 }
7976 }
7977 }
7978
7979 list_append_number(rettv->vval.v_list,
7980 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007981 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007982 list_append_string(rettv->vval.v_list, str, -1);
7983 list_append_number(rettv->vval.v_list, matchid);
7984 }
7985#endif
7986}
7987
7988/*
7989 * "synstack(lnum, col)" function
7990 */
7991 static void
7992f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7993{
7994#ifdef FEAT_SYN_HL
7995 linenr_T lnum;
7996 colnr_T col;
7997 int i;
7998 int id;
7999#endif
8000
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008001 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002
8003#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008004 lnum = tv_get_lnum(argvars); // -1 on type error
8005 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006
8007 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8008 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8009 && rettv_list_alloc(rettv) != FAIL)
8010 {
8011 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8012 for (i = 0; ; ++i)
8013 {
8014 id = syn_get_stack_item(i);
8015 if (id < 0)
8016 break;
8017 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8018 break;
8019 }
8020 }
8021#endif
8022}
8023
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008024/*
8025 * "tabpagebuflist()" function
8026 */
8027 static void
8028f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8029{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008030 tabpage_T *tp;
8031 win_T *wp = NULL;
8032
8033 if (argvars[0].v_type == VAR_UNKNOWN)
8034 wp = firstwin;
8035 else
8036 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008037 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008038 if (tp != NULL)
8039 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8040 }
8041 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8042 {
8043 for (; wp != NULL; wp = wp->w_next)
8044 if (list_append_number(rettv->vval.v_list,
8045 wp->w_buffer->b_fnum) == FAIL)
8046 break;
8047 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008048}
8049
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008051 * "tagfiles()" function
8052 */
8053 static void
8054f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8055{
8056 char_u *fname;
8057 tagname_T tn;
8058 int first;
8059
8060 if (rettv_list_alloc(rettv) == FAIL)
8061 return;
8062 fname = alloc(MAXPATHL);
8063 if (fname == NULL)
8064 return;
8065
8066 for (first = TRUE; ; first = FALSE)
8067 if (get_tagfname(&tn, first, fname) == FAIL
8068 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8069 break;
8070 tagname_free(&tn);
8071 vim_free(fname);
8072}
8073
8074/*
8075 * "taglist()" function
8076 */
8077 static void
8078f_taglist(typval_T *argvars, typval_T *rettv)
8079{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008080 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081 char_u *tag_pattern;
8082
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008083 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084
8085 rettv->vval.v_number = FALSE;
8086 if (*tag_pattern == NUL)
8087 return;
8088
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008089 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008090 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008091 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008092 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008093}
8094
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095#ifdef FEAT_FLOAT
8096/*
8097 * "tan()" function
8098 */
8099 static void
8100f_tan(typval_T *argvars, typval_T *rettv)
8101{
8102 float_T f = 0.0;
8103
8104 rettv->v_type = VAR_FLOAT;
8105 if (get_float_arg(argvars, &f) == OK)
8106 rettv->vval.v_float = tan(f);
8107 else
8108 rettv->vval.v_float = 0.0;
8109}
8110
8111/*
8112 * "tanh()" function
8113 */
8114 static void
8115f_tanh(typval_T *argvars, typval_T *rettv)
8116{
8117 float_T f = 0.0;
8118
8119 rettv->v_type = VAR_FLOAT;
8120 if (get_float_arg(argvars, &f) == OK)
8121 rettv->vval.v_float = tanh(f);
8122 else
8123 rettv->vval.v_float = 0.0;
8124}
8125#endif
8126
8127/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 * "tolower(string)" function
8129 */
8130 static void
8131f_tolower(typval_T *argvars, typval_T *rettv)
8132{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008134 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008135}
8136
8137/*
8138 * "toupper(string)" function
8139 */
8140 static void
8141f_toupper(typval_T *argvars, typval_T *rettv)
8142{
8143 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008144 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008145}
8146
8147/*
8148 * "tr(string, fromstr, tostr)" function
8149 */
8150 static void
8151f_tr(typval_T *argvars, typval_T *rettv)
8152{
8153 char_u *in_str;
8154 char_u *fromstr;
8155 char_u *tostr;
8156 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008157 int inlen;
8158 int fromlen;
8159 int tolen;
8160 int idx;
8161 char_u *cpstr;
8162 int cplen;
8163 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164 char_u buf[NUMBUFLEN];
8165 char_u buf2[NUMBUFLEN];
8166 garray_T ga;
8167
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008168 in_str = tv_get_string(&argvars[0]);
8169 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8170 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008171
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008172 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008173 rettv->v_type = VAR_STRING;
8174 rettv->vval.v_string = NULL;
8175 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008176 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008177 ga_init2(&ga, (int)sizeof(char), 80);
8178
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008180 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008181 if (STRLEN(fromstr) != STRLEN(tostr))
8182 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008183error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008184 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008185 ga_clear(&ga);
8186 return;
8187 }
8188
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008189 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 while (*in_str != NUL)
8191 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192 if (has_mbyte)
8193 {
8194 inlen = (*mb_ptr2len)(in_str);
8195 cpstr = in_str;
8196 cplen = inlen;
8197 idx = 0;
8198 for (p = fromstr; *p != NUL; p += fromlen)
8199 {
8200 fromlen = (*mb_ptr2len)(p);
8201 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8202 {
8203 for (p = tostr; *p != NUL; p += tolen)
8204 {
8205 tolen = (*mb_ptr2len)(p);
8206 if (idx-- == 0)
8207 {
8208 cplen = tolen;
8209 cpstr = p;
8210 break;
8211 }
8212 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008213 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008214 goto error;
8215 break;
8216 }
8217 ++idx;
8218 }
8219
8220 if (first && cpstr == in_str)
8221 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008222 // Check that fromstr and tostr have the same number of
8223 // (multi-byte) characters. Done only once when a character
8224 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225 first = FALSE;
8226 for (p = tostr; *p != NUL; p += tolen)
8227 {
8228 tolen = (*mb_ptr2len)(p);
8229 --idx;
8230 }
8231 if (idx != 0)
8232 goto error;
8233 }
8234
8235 (void)ga_grow(&ga, cplen);
8236 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8237 ga.ga_len += cplen;
8238
8239 in_str += inlen;
8240 }
8241 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008242 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008243 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008244 p = vim_strchr(fromstr, *in_str);
8245 if (p != NULL)
8246 ga_append(&ga, tostr[p - fromstr]);
8247 else
8248 ga_append(&ga, *in_str);
8249 ++in_str;
8250 }
8251 }
8252
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008253 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008254 (void)ga_grow(&ga, 1);
8255 ga_append(&ga, NUL);
8256
8257 rettv->vval.v_string = ga.ga_data;
8258}
8259
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008260/*
8261 * "trim({expr})" function
8262 */
8263 static void
8264f_trim(typval_T *argvars, typval_T *rettv)
8265{
8266 char_u buf1[NUMBUFLEN];
8267 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008268 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008269 char_u *mask = NULL;
8270 char_u *tail;
8271 char_u *prev;
8272 char_u *p;
8273 int c1;
8274
8275 rettv->v_type = VAR_STRING;
8276 if (head == NULL)
8277 {
8278 rettv->vval.v_string = NULL;
8279 return;
8280 }
8281
8282 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008283 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008284
8285 while (*head != NUL)
8286 {
8287 c1 = PTR2CHAR(head);
8288 if (mask == NULL)
8289 {
8290 if (c1 > ' ' && c1 != 0xa0)
8291 break;
8292 }
8293 else
8294 {
8295 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8296 if (c1 == PTR2CHAR(p))
8297 break;
8298 if (*p == NUL)
8299 break;
8300 }
8301 MB_PTR_ADV(head);
8302 }
8303
8304 for (tail = head + STRLEN(head); tail > head; tail = prev)
8305 {
8306 prev = tail;
8307 MB_PTR_BACK(head, prev);
8308 c1 = PTR2CHAR(prev);
8309 if (mask == NULL)
8310 {
8311 if (c1 > ' ' && c1 != 0xa0)
8312 break;
8313 }
8314 else
8315 {
8316 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8317 if (c1 == PTR2CHAR(p))
8318 break;
8319 if (*p == NUL)
8320 break;
8321 }
8322 }
8323 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8324}
8325
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008326#ifdef FEAT_FLOAT
8327/*
8328 * "trunc({float})" function
8329 */
8330 static void
8331f_trunc(typval_T *argvars, typval_T *rettv)
8332{
8333 float_T f = 0.0;
8334
8335 rettv->v_type = VAR_FLOAT;
8336 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008337 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008338 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8339 else
8340 rettv->vval.v_float = 0.0;
8341}
8342#endif
8343
8344/*
8345 * "type(expr)" function
8346 */
8347 static void
8348f_type(typval_T *argvars, typval_T *rettv)
8349{
8350 int n = -1;
8351
8352 switch (argvars[0].v_type)
8353 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008354 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8355 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008356 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008357 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8358 case VAR_LIST: n = VAR_TYPE_LIST; break;
8359 case VAR_DICT: n = VAR_TYPE_DICT; break;
8360 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8361 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8362 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008363 case VAR_JOB: n = VAR_TYPE_JOB; break;
8364 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008365 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008366 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008367 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008368 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 n = -1;
8370 break;
8371 }
8372 rettv->vval.v_number = n;
8373}
8374
8375/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376 * "virtcol(string)" function
8377 */
8378 static void
8379f_virtcol(typval_T *argvars, typval_T *rettv)
8380{
8381 colnr_T vcol = 0;
8382 pos_T *fp;
8383 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008384 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008385
8386 fp = var2fpos(&argvars[0], FALSE, &fnum);
8387 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8388 && fnum == curbuf->b_fnum)
8389 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008390 // Limit the column to a valid value, getvvcol() doesn't check.
8391 if (fp->col < 0)
8392 fp->col = 0;
8393 else
8394 {
8395 len = (int)STRLEN(ml_get(fp->lnum));
8396 if (fp->col > len)
8397 fp->col = len;
8398 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008399 getvvcol(curwin, fp, NULL, NULL, &vcol);
8400 ++vcol;
8401 }
8402
8403 rettv->vval.v_number = vcol;
8404}
8405
8406/*
8407 * "visualmode()" function
8408 */
8409 static void
8410f_visualmode(typval_T *argvars, typval_T *rettv)
8411{
8412 char_u str[2];
8413
8414 rettv->v_type = VAR_STRING;
8415 str[0] = curbuf->b_visual_mode_eval;
8416 str[1] = NUL;
8417 rettv->vval.v_string = vim_strsave(str);
8418
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008419 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008420 if (non_zero_arg(&argvars[0]))
8421 curbuf->b_visual_mode_eval = NUL;
8422}
8423
8424/*
8425 * "wildmenumode()" function
8426 */
8427 static void
8428f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8429{
8430#ifdef FEAT_WILDMENU
8431 if (wild_menu_showing)
8432 rettv->vval.v_number = 1;
8433#endif
8434}
8435
8436/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008437 * "windowsversion()" function
8438 */
8439 static void
8440f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8441{
8442 rettv->v_type = VAR_STRING;
8443 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8444}
8445
8446/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008447 * "wordcount()" function
8448 */
8449 static void
8450f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8451{
8452 if (rettv_dict_alloc(rettv) == FAIL)
8453 return;
8454 cursor_pos_info(rettv->vval.v_dict);
8455}
8456
8457/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458 * "xor(expr, expr)" function
8459 */
8460 static void
8461f_xor(typval_T *argvars, typval_T *rettv)
8462{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008463 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8464 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008465}
8466
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008467#endif // FEAT_EVAL